Feature: loading separate UV sets defined by user and loading LightMap.
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10737 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
d2d86d649b
commit
bf4447bc46
@ -2,9 +2,11 @@ package com.jme3.scene.plugins.blender.materials;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
@ -44,6 +46,7 @@ public final class MaterialContext {
|
|||||||
public static final int MTEX_SPEC = 0x04;
|
public static final int MTEX_SPEC = 0x04;
|
||||||
public static final int MTEX_EMIT = 0x40;
|
public static final int MTEX_EMIT = 0x40;
|
||||||
public static final int MTEX_ALPHA = 0x80;
|
public static final int MTEX_ALPHA = 0x80;
|
||||||
|
public static final int MTEX_AMB = 0x800;
|
||||||
|
|
||||||
/* package */final String name;
|
/* package */final String name;
|
||||||
/* package */final Map<Number, CombinedTexture> loadedTextures;
|
/* package */final Map<Number, CombinedTexture> loadedTextures;
|
||||||
@ -109,6 +112,10 @@ public final class MaterialContext {
|
|||||||
textureData.mtex = p.fetchData(blenderContext.getInputStream()).get(0);
|
textureData.mtex = p.fetchData(blenderContext.getInputStream()).get(0);
|
||||||
textureData.uvCoordinatesType = ((Number) textureData.mtex.getFieldValue("texco")).intValue();
|
textureData.uvCoordinatesType = ((Number) textureData.mtex.getFieldValue("texco")).intValue();
|
||||||
textureData.projectionType = ((Number) textureData.mtex.getFieldValue("mapping")).intValue();
|
textureData.projectionType = ((Number) textureData.mtex.getFieldValue("mapping")).intValue();
|
||||||
|
textureData.uvCoordinatesName = textureData.mtex.getFieldValue("uvName").toString();
|
||||||
|
if(textureData.uvCoordinatesName != null && textureData.uvCoordinatesName.trim().length() == 0) {
|
||||||
|
textureData.uvCoordinatesName = null;
|
||||||
|
}
|
||||||
|
|
||||||
Pointer pTex = (Pointer) textureData.mtex.getFieldValue("tex");
|
Pointer pTex = (Pointer) textureData.mtex.getFieldValue("tex");
|
||||||
if (pTex.isNotNull()) {
|
if (pTex.isNotNull()) {
|
||||||
@ -136,7 +143,8 @@ public final class MaterialContext {
|
|||||||
float[] color = new float[] { ((Number) textureData.mtex.getFieldValue("r")).floatValue(), ((Number) textureData.mtex.getFieldValue("g")).floatValue(), ((Number) textureData.mtex.getFieldValue("b")).floatValue() };
|
float[] color = new float[] { ((Number) textureData.mtex.getFieldValue("r")).floatValue(), ((Number) textureData.mtex.getFieldValue("g")).floatValue(), ((Number) textureData.mtex.getFieldValue("b")).floatValue() };
|
||||||
float colfac = ((Number) textureData.mtex.getFieldValue("colfac")).floatValue();
|
float colfac = ((Number) textureData.mtex.getFieldValue("colfac")).floatValue();
|
||||||
TextureBlender textureBlender = TextureBlenderFactory.createTextureBlender(texture.getImage().getFormat(), texflag, negateTexture, blendType, diffuseColorArray, color, colfac);
|
TextureBlender textureBlender = TextureBlenderFactory.createTextureBlender(texture.getImage().getFormat(), texflag, negateTexture, blendType, diffuseColorArray, color, colfac);
|
||||||
combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType, textureData.textureStructure, blenderContext);
|
combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType,
|
||||||
|
textureData.textureStructure, textureData.uvCoordinatesName, blenderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (combinedTexture.getTexturesCount() > 0) {
|
if (combinedTexture.getTexturesCount() > 0) {
|
||||||
@ -176,7 +184,7 @@ public final class MaterialContext {
|
|||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
*/
|
*/
|
||||||
public void applyMaterial(Geometry geometry, Long geometriesOMA, List<Vector2f> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
public void applyMaterial(Geometry geometry, Long geometriesOMA, LinkedHashMap<String, List<Vector2f>> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
||||||
Material material = null;
|
Material material = null;
|
||||||
if (shadeless) {
|
if (shadeless) {
|
||||||
material = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
|
material = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
|
||||||
@ -206,30 +214,24 @@ public final class MaterialContext {
|
|||||||
|
|
||||||
// applying textures
|
// applying textures
|
||||||
if (loadedTextures != null && loadedTextures.size() > 0) {
|
if (loadedTextures != null && loadedTextures.size() > 0) {
|
||||||
Entry<Number, CombinedTexture> basicUVSOwner = null;
|
int textureIndex = 0;
|
||||||
|
if(loadedTextures.size() > 8) {
|
||||||
|
LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different textures. JME supports only {0} UV mappings.", TextureHelper.TEXCOORD_TYPES.length);
|
||||||
|
}
|
||||||
for (Entry<Number, CombinedTexture> entry : loadedTextures.entrySet()) {
|
for (Entry<Number, CombinedTexture> entry : loadedTextures.entrySet()) {
|
||||||
|
if(textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
|
||||||
CombinedTexture combinedTexture = entry.getValue();
|
CombinedTexture combinedTexture = entry.getValue();
|
||||||
combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
|
combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
|
||||||
|
|
||||||
if (basicUVSOwner == null) {
|
|
||||||
basicUVSOwner = entry;
|
|
||||||
} else {
|
|
||||||
combinedTexture.castToUVS(basicUVSOwner.getValue(), blenderContext);
|
|
||||||
this.setTexture(material, entry.getKey().intValue(), combinedTexture.getResultTexture());
|
this.setTexture(material, entry.getKey().intValue(), combinedTexture.getResultTexture());
|
||||||
}
|
List<Vector2f> uvs = entry.getValue().getResultUVS();
|
||||||
}
|
VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]);
|
||||||
|
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
|
||||||
if (basicUVSOwner != null) {
|
|
||||||
this.setTexture(material, basicUVSOwner.getKey().intValue(), basicUVSOwner.getValue().getResultTexture());
|
|
||||||
List<Vector2f> basicUVS = basicUVSOwner.getValue().getResultUVS();
|
|
||||||
VertexBuffer uvCoordsBuffer = new VertexBuffer(VertexBuffer.Type.TexCoord);
|
|
||||||
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(basicUVS.toArray(new Vector2f[basicUVS.size()])));
|
|
||||||
geometry.getMesh().setBuffer(uvCoordsBuffer);
|
geometry.getMesh().setBuffer(uvCoordsBuffer);
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
|
||||||
VertexBuffer uvCoordsBuffer = new VertexBuffer(VertexBuffer.Type.TexCoord);
|
|
||||||
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(userDefinedUVCoordinates.toArray(new Vector2f[userDefinedUVCoordinates.size()])));
|
|
||||||
geometry.getMesh().setBuffer(uvCoordsBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// applying additional data
|
// applying additional data
|
||||||
@ -237,11 +239,7 @@ public final class MaterialContext {
|
|||||||
if (vertexColor) {
|
if (vertexColor) {
|
||||||
material.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", true);
|
material.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", true);
|
||||||
}
|
}
|
||||||
if (this.faceCullMode != null) {
|
material.getAdditionalRenderState().setFaceCullMode(faceCullMode != null ? faceCullMode : blenderContext.getBlenderKey().getFaceCullMode());
|
||||||
material.getAdditionalRenderState().setFaceCullMode(faceCullMode);
|
|
||||||
} else {
|
|
||||||
material.getAdditionalRenderState().setFaceCullMode(blenderContext.getBlenderKey().getFaceCullMode());
|
|
||||||
}
|
|
||||||
if (transparent) {
|
if (transparent) {
|
||||||
material.setTransparent(true);
|
material.setTransparent(true);
|
||||||
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
||||||
@ -282,6 +280,9 @@ public final class MaterialContext {
|
|||||||
LOGGER.warning("JME does not support alpha map on unshaded material. Material name is " + name);
|
LOGGER.warning("JME does not support alpha map on unshaded material. Material name is " + name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MTEX_AMB:
|
||||||
|
material.setTexture(MaterialHelper.TEXTURE_TYPE_LIGHTMAP, texture);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOGGER.severe("Unknown mapping type: " + mapTo);
|
LOGGER.severe("Unknown mapping type: " + mapTo);
|
||||||
}
|
}
|
||||||
@ -311,7 +312,7 @@ public final class MaterialContext {
|
|||||||
* @return a map with sorted and filtered textures
|
* @return a map with sorted and filtered textures
|
||||||
*/
|
*/
|
||||||
private Map<Number, List<TextureData>> sortAndFilterTextures(List<TextureData> textures) {
|
private Map<Number, List<TextureData>> sortAndFilterTextures(List<TextureData> textures) {
|
||||||
int[] mappings = new int[] { MTEX_COL, MTEX_NOR, MTEX_EMIT, MTEX_SPEC, MTEX_ALPHA };
|
int[] mappings = new int[] { MTEX_COL, MTEX_NOR, MTEX_EMIT, MTEX_SPEC, MTEX_ALPHA, MTEX_AMB };
|
||||||
Map<Number, List<TextureData>> result = new HashMap<Number, List<TextureData>>();
|
Map<Number, List<TextureData>> result = new HashMap<Number, List<TextureData>>();
|
||||||
for (TextureData data : textures) {
|
for (TextureData data : textures) {
|
||||||
Number mapto = (Number) data.mtex.getFieldValue("mapto");
|
Number mapto = (Number) data.mtex.getFieldValue("mapto");
|
||||||
@ -413,5 +414,7 @@ public final class MaterialContext {
|
|||||||
Structure textureStructure;
|
Structure textureStructure;
|
||||||
int uvCoordinatesType;
|
int uvCoordinatesType;
|
||||||
int projectionType;
|
int projectionType;
|
||||||
|
/** The name of the user's UV coordinates that are used for this texture. */
|
||||||
|
String uvCoordinatesName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ public class MaterialHelper extends AbstractBlenderHelper {
|
|||||||
public static final String TEXTURE_TYPE_SPECULAR = "SpecularMap";
|
public static final String TEXTURE_TYPE_SPECULAR = "SpecularMap";
|
||||||
public static final String TEXTURE_TYPE_GLOW = "GlowMap";
|
public static final String TEXTURE_TYPE_GLOW = "GlowMap";
|
||||||
public static final String TEXTURE_TYPE_ALPHA = "AlphaMap";
|
public static final String TEXTURE_TYPE_ALPHA = "AlphaMap";
|
||||||
|
public static final String TEXTURE_TYPE_LIGHTMAP = "LightMap";
|
||||||
|
|
||||||
public static final Integer ALPHA_MASK_NONE = Integer.valueOf(0);
|
public static final Integer ALPHA_MASK_NONE = Integer.valueOf(0);
|
||||||
public static final Integer ALPHA_MASK_CIRCLE = Integer.valueOf(1);
|
public static final Integer ALPHA_MASK_CIRCLE = Integer.valueOf(1);
|
||||||
|
@ -3,13 +3,16 @@ package com.jme3.scene.plugins.blender.meshes;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.math.Vector2f;
|
import com.jme3.math.Vector2f;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.plugins.blender.textures.UserUVCollection;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,7 +20,7 @@ import com.jme3.util.BufferUtils;
|
|||||||
*
|
*
|
||||||
* @author Marcin Roguski (Kaelthas)
|
* @author Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
/*package*/class MeshBuilder {
|
/* package */class MeshBuilder {
|
||||||
private static final Logger LOGGER = Logger.getLogger(MeshBuilder.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(MeshBuilder.class.getName());
|
||||||
|
|
||||||
/** An array of reference vertices. */
|
/** An array of reference vertices. */
|
||||||
@ -26,15 +29,11 @@ import com.jme3.util.BufferUtils;
|
|||||||
private List<byte[]> verticesColors;
|
private List<byte[]> verticesColors;
|
||||||
/** A variable that indicates if the model uses generated textures. */
|
/** A variable that indicates if the model uses generated textures. */
|
||||||
private boolean usesGeneratedTextures;
|
private boolean usesGeneratedTextures;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
|
* This map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
|
||||||
* positions (it simply tells which vertex is referenced where in the result list).
|
* positions (it simply tells which vertex is referenced where in the result list).
|
||||||
*/
|
*/
|
||||||
private Map<Integer, Map<Integer, List<Integer>>> globalVertexReferenceMap;
|
private Map<Integer, Map<Integer, List<Integer>>> globalVertexReferenceMap;
|
||||||
|
|
||||||
/** A map between vertex index and its UV coordinates. */
|
|
||||||
private Map<Integer, Vector2f> uvsMap = new HashMap<Integer, Vector2f>();
|
|
||||||
/** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
|
/** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
|
||||||
private Map<Integer, List<Vector3f>> normalMap = new HashMap<Integer, List<Vector3f>>();
|
private Map<Integer, List<Vector3f>> normalMap = new HashMap<Integer, List<Vector3f>>();
|
||||||
/** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
|
/** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
|
||||||
@ -43,8 +42,8 @@ import com.jme3.util.BufferUtils;
|
|||||||
private Map<Integer, List<byte[]>> vertexColorsMap = new HashMap<Integer, List<byte[]>>();
|
private Map<Integer, List<byte[]>> vertexColorsMap = new HashMap<Integer, List<byte[]>>();
|
||||||
/** The following map sorts indexes by material number (because in jme Mesh can have only one material). */
|
/** The following map sorts indexes by material number (because in jme Mesh can have only one material). */
|
||||||
private Map<Integer, List<Integer>> indexMap = new HashMap<Integer, List<Integer>>();
|
private Map<Integer, List<Integer>> indexMap = new HashMap<Integer, List<Integer>>();
|
||||||
/** A map between material number and UV coordinates of mesh that has this material applied. */
|
/** A collection of user defined UV coordinates (one mesh can have more than one such mappings). */
|
||||||
private Map<Integer, List<Vector2f>> uvCoordinates = new HashMap<Integer, List<Vector2f>>(); // <material_number; list of uv coordinates for mesh's vertices>
|
private UserUVCollection userUVCollection = new UserUVCollection();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. Stores the given array (not copying it).
|
* Constructor. Stores the given array (not copying it).
|
||||||
@ -100,16 +99,20 @@ import com.jme3.util.BufferUtils;
|
|||||||
* indicates if this face should have smooth shading or flat shading
|
* indicates if this face should have smooth shading or flat shading
|
||||||
* @param materialNumber
|
* @param materialNumber
|
||||||
* the material number for this face
|
* the material number for this face
|
||||||
* @param uvs
|
* @param uvsForFace
|
||||||
* a 3-element array of vertices UV coordinates
|
* a 3-element array of vertices UV coordinates mapped to the UV's set name
|
||||||
* @param quad
|
* @param quad
|
||||||
* indicates if the appended face is a part of a quad face (used for creating vertex colors buffer)
|
* indicates if the appended face is a part of a quad face (used for creating vertex colors buffer)
|
||||||
* @param faceIndex
|
* @param faceIndex
|
||||||
* the face index (used for creating vertex colors buffer)
|
* the face index (used for creating vertex colors buffer)
|
||||||
*/
|
*/
|
||||||
public void appendFace(int v1, int v2, int v3, boolean smooth, int materialNumber, Vector2f[] uvs, boolean quad, int faceIndex) {
|
public void appendFace(int v1, int v2, int v3, boolean smooth, int materialNumber, Map<String, Vector2f[]> uvsForFace, boolean quad, int faceIndex) {
|
||||||
if (uvs != null && uvs.length != 3) {
|
if (uvsForFace != null && uvsForFace.size() > 0) {
|
||||||
throw new IllegalArgumentException("UV coordinates must be a 3-element array!");
|
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||||
|
if (entry.getValue().length != 3) {
|
||||||
|
throw new IllegalArgumentException("UV coordinates must be a 3-element array!" + (entry.getKey() != null ? " (UV set name: " + entry.getKey() + ')' : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getting the required lists
|
// getting the required lists
|
||||||
@ -139,14 +142,6 @@ import com.jme3.util.BufferUtils;
|
|||||||
vertexReferenceMap = new HashMap<Integer, List<Integer>>();
|
vertexReferenceMap = new HashMap<Integer, List<Integer>>();
|
||||||
globalVertexReferenceMap.put(materialNumber, vertexReferenceMap);
|
globalVertexReferenceMap.put(materialNumber, vertexReferenceMap);
|
||||||
}
|
}
|
||||||
List<Vector2f> uvCoordinatesList = null;
|
|
||||||
if (uvs != null) {
|
|
||||||
uvCoordinatesList = uvCoordinates.get(Integer.valueOf(materialNumber));
|
|
||||||
if (uvCoordinatesList == null) {
|
|
||||||
uvCoordinatesList = new ArrayList<Vector2f>();
|
|
||||||
uvCoordinates.put(Integer.valueOf(materialNumber), uvCoordinatesList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
faceIndex *= 4;
|
faceIndex *= 4;
|
||||||
if (quad) {
|
if (quad) {
|
||||||
@ -159,38 +154,55 @@ import com.jme3.util.BufferUtils;
|
|||||||
if (smooth && !usesGeneratedTextures) {
|
if (smooth && !usesGeneratedTextures) {
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
if (!vertexReferenceMap.containsKey(index[i])) {
|
if (!vertexReferenceMap.containsKey(index[i])) {
|
||||||
|
//if this index is not yet used then create another face
|
||||||
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
||||||
|
if (uvsForFace != null) {
|
||||||
|
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||||
|
userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vertexList.add(verticesAndNormals[index[i]][0]);
|
vertexList.add(verticesAndNormals[index[i]][0]);
|
||||||
if (verticesColors != null) {
|
if (verticesColors != null) {
|
||||||
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
|
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
|
||||||
}
|
}
|
||||||
normalList.add(verticesAndNormals[index[i]][1]);
|
normalList.add(verticesAndNormals[index[i]][1]);
|
||||||
if (uvCoordinatesList != null) {
|
|
||||||
uvsMap.put(vertexList.size(), uvs[i]);
|
|
||||||
uvCoordinatesList.add(uvs[i]);
|
|
||||||
}
|
|
||||||
index[i] = vertexList.size() - 1;
|
index[i] = vertexList.size() - 1;
|
||||||
} else if (uvCoordinatesList != null) {
|
} else if (uvsForFace != null) {
|
||||||
|
//if the index is used then check if the vertexe's UV coordinates match, if yes then the vertex doesn't have separate UV's
|
||||||
|
//in different faces so we can use it here as well, if UV's are different in separate faces the we need to add this vert
|
||||||
|
//because in jme one vertex can have only on UV coordinate
|
||||||
boolean vertexAlreadyUsed = false;
|
boolean vertexAlreadyUsed = false;
|
||||||
for (Integer vertexIndex : vertexReferenceMap.get(index[i])) {
|
for (Integer vertexIndex : vertexReferenceMap.get(index[i])) {
|
||||||
if (uvs[i].equals(uvsMap.get(vertexIndex))) {
|
int vertexUseCounter = 0;
|
||||||
|
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||||
|
if (entry.getValue()[i].equals(userUVCollection.getUVForVertex(entry.getKey(), vertexIndex))) {
|
||||||
|
++vertexUseCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vertexUseCounter == uvsForFace.size()) {
|
||||||
vertexAlreadyUsed = true;
|
vertexAlreadyUsed = true;
|
||||||
index[i] = vertexIndex;
|
index[i] = vertexIndex;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vertexAlreadyUsed) {
|
if (!vertexAlreadyUsed) {
|
||||||
|
// treat this face as a new one because its vertices have separate UV's
|
||||||
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
||||||
uvsMap.put(vertexList.size(), uvs[i]);
|
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||||
|
userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
|
||||||
|
}
|
||||||
vertexList.add(verticesAndNormals[index[i]][0]);
|
vertexList.add(verticesAndNormals[index[i]][0]);
|
||||||
if (verticesColors != null) {
|
if (verticesColors != null) {
|
||||||
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
|
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
|
||||||
}
|
}
|
||||||
normalList.add(verticesAndNormals[index[i]][1]);
|
normalList.add(verticesAndNormals[index[i]][1]);
|
||||||
uvCoordinatesList.add(uvs[i]);
|
|
||||||
index[i] = vertexList.size() - 1;
|
index[i] = vertexList.size() - 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
//use this index again
|
||||||
index[i] = vertexList.indexOf(verticesAndNormals[index[i]][0]);
|
index[i] = vertexList.indexOf(verticesAndNormals[index[i]][0]);
|
||||||
}
|
}
|
||||||
indexList.add(index[i]);
|
indexList.add(index[i]);
|
||||||
@ -200,9 +212,10 @@ import com.jme3.util.BufferUtils;
|
|||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
indexList.add(vertexList.size());
|
indexList.add(vertexList.size());
|
||||||
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
||||||
if (uvCoordinatesList != null) {
|
if (uvsForFace != null) {
|
||||||
uvCoordinatesList.add(uvs[i]);
|
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||||
uvsMap.put(vertexList.size(), uvs[i]);
|
userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vertexList.add(verticesAndNormals[index[i]][0]);
|
vertexList.add(verticesAndNormals[index[i]][0]);
|
||||||
if (verticesColors != null) {
|
if (verticesColors != null) {
|
||||||
@ -288,15 +301,15 @@ import com.jme3.util.BufferUtils;
|
|||||||
* the material number that is appied to the mesh
|
* the material number that is appied to the mesh
|
||||||
* @return UV coordinates of vertices that belong to the required mesh part
|
* @return UV coordinates of vertices that belong to the required mesh part
|
||||||
*/
|
*/
|
||||||
public List<Vector2f> getUVCoordinates(int materialNumber) {
|
public LinkedHashMap<String, List<Vector2f>> getUVCoordinates(int materialNumber) {
|
||||||
return uvCoordinates.get(materialNumber);
|
return userUVCollection.getUVCoordinates(materialNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return indicates if the mesh has UV coordinates
|
* @return indicates if the mesh has UV coordinates
|
||||||
*/
|
*/
|
||||||
public boolean hasUVCoordinates() {
|
public boolean hasUVCoordinates() {
|
||||||
return uvCoordinates.size() > 0;
|
return userUVCollection.hasUVCoordinates();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +32,10 @@
|
|||||||
package com.jme3.scene.plugins.blender.meshes;
|
package com.jme3.scene.plugins.blender.meshes;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
|||||||
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
||||||
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||||
import com.jme3.scene.plugins.blender.objects.Properties;
|
import com.jme3.scene.plugins.blender.objects.Properties;
|
||||||
|
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,6 +69,11 @@ import com.jme3.util.BufferUtils;
|
|||||||
public class MeshHelper extends AbstractBlenderHelper {
|
public class MeshHelper extends AbstractBlenderHelper {
|
||||||
private static final Logger LOGGER = Logger.getLogger(MeshHelper.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(MeshHelper.class.getName());
|
||||||
|
|
||||||
|
/** A type of UV data layer in traditional faced mesh (triangles or quads). */
|
||||||
|
private static final int UV_DATA_LAYER_TYPE_FMESH = 5;
|
||||||
|
/** A type of UV data layer in bmesh type. */
|
||||||
|
private static final int UV_DATA_LAYER_TYPE_BMESH = 16;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
|
* This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
|
||||||
* versions.
|
* versions.
|
||||||
@ -213,7 +222,7 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
for (Geometry geometry : geometries) {
|
for (Geometry geometry : geometries) {
|
||||||
int materialNumber = meshContext.getMaterialIndex(geometry);
|
int materialNumber = meshContext.getMaterialIndex(geometry);
|
||||||
if (materials[materialNumber] != null) {
|
if (materials[materialNumber] != null) {
|
||||||
List<Vector2f> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
|
LinkedHashMap<String, List<Vector2f>> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
|
||||||
MaterialContext materialContext = materials[materialNumber];
|
MaterialContext materialContext = materials[materialNumber];
|
||||||
materialContext.applyMaterial(geometry, structure.getOldMemoryAddress(), uvCoordinates, blenderContext);
|
materialContext.applyMaterial(geometry, structure.getOldMemoryAddress(), uvCoordinates, blenderContext);
|
||||||
} else {
|
} else {
|
||||||
@ -223,17 +232,26 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// add UV coordinates if they are defined even if the material is not applied to the model
|
// add UV coordinates if they are defined even if the material is not applied to the model
|
||||||
VertexBuffer uvCoordsBuffer = null;
|
List<VertexBuffer> uvCoordsBuffer = null;
|
||||||
if (meshBuilder.hasUVCoordinates()) {
|
if (meshBuilder.hasUVCoordinates()) {
|
||||||
List<Vector2f> uvs = meshBuilder.getUVCoordinates(0);
|
Map<String, List<Vector2f>> uvs = meshBuilder.getUVCoordinates(0);
|
||||||
uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
|
if (uvs != null && uvs.size() > 0) {
|
||||||
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
|
uvCoordsBuffer = new ArrayList<VertexBuffer>(uvs.size());
|
||||||
|
int uvIndex = 0;
|
||||||
|
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||||
|
VertexBuffer buffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[uvIndex++]);
|
||||||
|
buffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(entry.getValue().toArray(new Vector2f[uvs.size()])));
|
||||||
|
uvCoordsBuffer.add(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Geometry geometry : geometries) {
|
for (Geometry geometry : geometries) {
|
||||||
geometry.setMaterial(blenderContext.getDefaultMaterial());
|
geometry.setMaterial(blenderContext.getDefaultMaterial());
|
||||||
if (uvCoordsBuffer != null) {
|
if (uvCoordsBuffer != null) {
|
||||||
geometry.getMesh().setBuffer(uvCoordsBuffer);
|
for (VertexBuffer buffer : uvCoordsBuffer) {
|
||||||
|
geometry.getMesh().setBuffer(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,6 +272,67 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
return pMLoop != null && pMPoly != null && pMLoop.isNotNull() && pMPoly.isNotNull();
|
return pMLoop != null && pMPoly != null && pMLoop.isNotNull() && pMPoly.isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method loads the UV coordinates. The result is a map where the key is the user's UV set name and the values are UV coordinates.
|
||||||
|
* But depending on the mesh type (triangle/quads or bmesh) the lists in the map have different meaning.
|
||||||
|
* For bmesh they are enlisted just like they are stored in the blend file (in loops).
|
||||||
|
* For traditional faces every 4 UV's should be assigned for a single face.
|
||||||
|
* @param meshStructure
|
||||||
|
* the mesh structure
|
||||||
|
* @param useBMesh
|
||||||
|
* tells if we should load the coordinates from loops of from faces
|
||||||
|
* @param blenderContext
|
||||||
|
* the blender context
|
||||||
|
* @return a map that sorts UV coordinates between different UV sets
|
||||||
|
* @throws BlenderFileException
|
||||||
|
* an exception is thrown when problems with blend file occur
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Map<String, List<Vector2f>> loadUVCoordinates(Structure meshStructure, boolean useBMesh, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
|
Map<String, List<Vector2f>> result = new HashMap<String, List<Vector2f>>();
|
||||||
|
if (useBMesh) {
|
||||||
|
// in this case the UV's are assigned to vertices (an array is the same length as the vertex array)
|
||||||
|
Structure loopData = (Structure) meshStructure.getFieldValue("ldata");
|
||||||
|
Pointer pLoopDataLayers = (Pointer) loopData.getFieldValue("layers");
|
||||||
|
List<Structure> loopDataLayers = pLoopDataLayers.fetchData(blenderContext.getInputStream());
|
||||||
|
for (Structure structure : loopDataLayers) {
|
||||||
|
Pointer p = (Pointer) structure.getFieldValue("data");
|
||||||
|
if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == UV_DATA_LAYER_TYPE_BMESH) {
|
||||||
|
String uvSetName = structure.getFieldValue("name").toString();
|
||||||
|
List<Structure> uvsStructures = p.fetchData(blenderContext.getInputStream());
|
||||||
|
List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
|
||||||
|
for (Structure uvStructure : uvsStructures) {
|
||||||
|
DynamicArray<Number> loopUVS = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
|
||||||
|
uvs.add(new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue()));
|
||||||
|
}
|
||||||
|
result.put(uvSetName, uvs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// in this case UV's are assigned to faces (the array has the same legnth as the faces count)
|
||||||
|
Structure facesData = (Structure) meshStructure.getFieldValue("fdata");
|
||||||
|
Pointer pFacesDataLayers = (Pointer) facesData.getFieldValue("layers");
|
||||||
|
List<Structure> facesDataLayers = pFacesDataLayers.fetchData(blenderContext.getInputStream());
|
||||||
|
for (Structure structure : facesDataLayers) {
|
||||||
|
Pointer p = (Pointer) structure.getFieldValue("data");
|
||||||
|
if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == UV_DATA_LAYER_TYPE_FMESH) {
|
||||||
|
String uvSetName = structure.getFieldValue("name").toString();
|
||||||
|
List<Structure> uvsStructures = p.fetchData(blenderContext.getInputStream());
|
||||||
|
List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
|
||||||
|
for (Structure uvStructure : uvsStructures) {
|
||||||
|
DynamicArray<Number> mFaceUVs = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
|
||||||
|
uvs.add(new Vector2f(mFaceUVs.get(0).floatValue(), mFaceUVs.get(1).floatValue()));
|
||||||
|
uvs.add(new Vector2f(mFaceUVs.get(2).floatValue(), mFaceUVs.get(3).floatValue()));
|
||||||
|
uvs.add(new Vector2f(mFaceUVs.get(4).floatValue(), mFaceUVs.get(5).floatValue()));
|
||||||
|
uvs.add(new Vector2f(mFaceUVs.get(6).floatValue(), mFaceUVs.get(7).floatValue()));
|
||||||
|
}
|
||||||
|
result.put(uvSetName, uvs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method reads the mesh from the new BMesh system.
|
* This method reads the mesh from the new BMesh system.
|
||||||
*
|
*
|
||||||
@ -267,33 +346,26 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
* an exception is thrown when there are problems with the
|
* an exception is thrown when there are problems with the
|
||||||
* blender file
|
* blender file
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void readBMesh(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
|
private void readBMesh(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
Pointer pMLoop = (Pointer) meshStructure.getFieldValue("mloop");
|
Pointer pMLoop = (Pointer) meshStructure.getFieldValue("mloop");
|
||||||
Pointer pMPoly = (Pointer) meshStructure.getFieldValue("mpoly");
|
Pointer pMPoly = (Pointer) meshStructure.getFieldValue("mpoly");
|
||||||
Pointer pMEdge = (Pointer) meshStructure.getFieldValue("medge");
|
Pointer pMEdge = (Pointer) meshStructure.getFieldValue("medge");
|
||||||
Pointer pMLoopUV = (Pointer) meshStructure.getFieldValue("mloopuv");
|
Map<String, Vector2f[]> uvCoordinatesForFace = new HashMap<String, Vector2f[]>();
|
||||||
Vector2f[] uvCoordinatesForFace = new Vector2f[3];
|
|
||||||
|
|
||||||
if (pMPoly.isNotNull() && pMLoop.isNotNull() && pMEdge.isNotNull()) {
|
if (pMPoly.isNotNull() && pMLoop.isNotNull() && pMEdge.isNotNull()) {
|
||||||
|
Map<String, List<Vector2f>> uvs = this.loadUVCoordinates(meshStructure, true, blenderContext);
|
||||||
int faceIndex = 0;
|
int faceIndex = 0;
|
||||||
List<Structure> polys = pMPoly.fetchData(blenderContext.getInputStream());
|
List<Structure> polys = pMPoly.fetchData(blenderContext.getInputStream());
|
||||||
List<Structure> loops = pMLoop.fetchData(blenderContext.getInputStream());
|
List<Structure> loops = pMLoop.fetchData(blenderContext.getInputStream());
|
||||||
List<Structure> loopuvs = pMLoopUV.isNotNull() ? pMLoopUV.fetchData(blenderContext.getInputStream()) : null;
|
|
||||||
for (Structure poly : polys) {
|
for (Structure poly : polys) {
|
||||||
int materialNumber = ((Number) poly.getFieldValue("mat_nr")).intValue();
|
int materialNumber = ((Number) poly.getFieldValue("mat_nr")).intValue();
|
||||||
int loopStart = ((Number) poly.getFieldValue("loopstart")).intValue();
|
int loopStart = ((Number) poly.getFieldValue("loopstart")).intValue();
|
||||||
int totLoop = ((Number) poly.getFieldValue("totloop")).intValue();
|
int totLoop = ((Number) poly.getFieldValue("totloop")).intValue();
|
||||||
boolean smooth = (((Number) poly.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
|
boolean smooth = (((Number) poly.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
|
||||||
int[] vertexIndexes = new int[totLoop];
|
int[] vertexIndexes = new int[totLoop];
|
||||||
Vector2f[] uvs = loopuvs != null ? new Vector2f[totLoop] : null;
|
|
||||||
|
|
||||||
for (int i = loopStart; i < loopStart + totLoop; ++i) {
|
for (int i = loopStart; i < loopStart + totLoop; ++i) {
|
||||||
vertexIndexes[i - loopStart] = ((Number) loops.get(i).getFieldValue("v")).intValue();
|
vertexIndexes[i - loopStart] = ((Number) loops.get(i).getFieldValue("v")).intValue();
|
||||||
if (uvs != null) {
|
|
||||||
DynamicArray<Number> loopUVS = (DynamicArray<Number>) loopuvs.get(i).getFieldValue("uv");
|
|
||||||
uvs[i - loopStart] = new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -302,15 +374,19 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
int v2 = vertexIndexes[i + 1];
|
int v2 = vertexIndexes[i + 1];
|
||||||
int v3 = vertexIndexes[i + 2];
|
int v3 = vertexIndexes[i + 2];
|
||||||
|
|
||||||
if (uvs != null) {// uvs always must be added wheater we
|
if (uvs != null) {
|
||||||
// have texture or not
|
// uvs always must be added wheater we have texture or not
|
||||||
uvCoordinatesForFace[0] = uvs[0];
|
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||||
uvCoordinatesForFace[1] = uvs[i + 1];
|
Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
|
||||||
uvCoordinatesForFace[2] = uvs[i + 2];
|
uvCoordsForASingleFace[0] = entry.getValue().get(loopStart);
|
||||||
|
uvCoordsForASingleFace[1] = entry.getValue().get(loopStart + i + 1);
|
||||||
|
uvCoordsForASingleFace[2] = entry.getValue().get(loopStart + i + 2);
|
||||||
|
uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, faceIndex);
|
meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, faceIndex);
|
||||||
|
uvCoordinatesForFace.clear();
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
++faceIndex;
|
++faceIndex;
|
||||||
@ -332,38 +408,26 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
* an exception is thrown when there are problems with the
|
* an exception is thrown when there are problems with the
|
||||||
* blender file
|
* blender file
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void readTraditionalFaces(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
|
private void readTraditionalFaces(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||||
Pointer pMFace = (Pointer) meshStructure.getFieldValue("mface");
|
Pointer pMFace = (Pointer) meshStructure.getFieldValue("mface");
|
||||||
List<Structure> mFaces = pMFace.isNotNull() ? pMFace.fetchData(blenderContext.getInputStream()) : null;
|
List<Structure> mFaces = pMFace.isNotNull() ? pMFace.fetchData(blenderContext.getInputStream()) : null;
|
||||||
if (mFaces != null && mFaces.size() > 0) {
|
if (mFaces != null && mFaces.size() > 0) {
|
||||||
Pointer pMTFace = (Pointer) meshStructure.getFieldValue("mtface");
|
// indicates if the material with the specified number should have a texture attached
|
||||||
List<Structure> mtFaces = null;
|
Map<String, List<Vector2f>> uvs = this.loadUVCoordinates(meshStructure, false, blenderContext);
|
||||||
|
Map<String, Vector2f[]> uvCoordinatesForFace = new HashMap<String, Vector2f[]>();
|
||||||
if (pMTFace.isNotNull()) {
|
|
||||||
mtFaces = pMTFace.fetchData(blenderContext.getInputStream());
|
|
||||||
int facesAmount = ((Number) meshStructure.getFieldValue("totface")).intValue();
|
|
||||||
if (mtFaces.size() != facesAmount) {
|
|
||||||
throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// indicates if the material with the specified number should have a
|
|
||||||
// texture attached
|
|
||||||
Vector2f[] uvCoordinatesForFace = new Vector2f[3];
|
|
||||||
for (int i = 0; i < mFaces.size(); ++i) {
|
for (int i = 0; i < mFaces.size(); ++i) {
|
||||||
Structure mFace = mFaces.get(i);
|
Structure mFace = mFaces.get(i);
|
||||||
int materialNumber = ((Number) mFace.getFieldValue("mat_nr")).intValue();
|
int materialNumber = ((Number) mFace.getFieldValue("mat_nr")).intValue();
|
||||||
boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
|
boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
|
||||||
DynamicArray<Number> uvs = null;
|
if (uvs != null) {
|
||||||
|
|
||||||
if (mtFaces != null) {
|
|
||||||
Structure mtFace = mtFaces.get(i);
|
|
||||||
// uvs always must be added wheater we have texture or not
|
// uvs always must be added wheater we have texture or not
|
||||||
uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");
|
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||||
uvCoordinatesForFace[0] = new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue());
|
Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
|
||||||
uvCoordinatesForFace[1] = new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue());
|
uvCoordsForASingleFace[0] = entry.getValue().get(i * 4);
|
||||||
uvCoordinatesForFace[2] = new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue());
|
uvCoordsForASingleFace[1] = entry.getValue().get(i * 4 + 1);
|
||||||
|
uvCoordsForASingleFace[2] = entry.getValue().get(i * 4 + 2);
|
||||||
|
uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
|
int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
|
||||||
@ -372,13 +436,20 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
|
int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
|
||||||
|
|
||||||
meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, i);
|
meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, i);
|
||||||
|
uvCoordinatesForFace.clear();
|
||||||
if (v4 > 0) {
|
if (v4 > 0) {
|
||||||
if (uvs != null) {
|
if (uvs != null) {
|
||||||
uvCoordinatesForFace[0] = new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue());
|
// uvs always must be added wheater we have texture or not
|
||||||
uvCoordinatesForFace[1] = new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue());
|
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||||
uvCoordinatesForFace[2] = new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue());
|
Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
|
||||||
|
uvCoordsForASingleFace[0] = entry.getValue().get(i * 4);
|
||||||
|
uvCoordsForASingleFace[1] = entry.getValue().get(i * 4 + 2);
|
||||||
|
uvCoordsForASingleFace[2] = entry.getValue().get(i * 4 + 3);
|
||||||
|
uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i);
|
meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i);
|
||||||
|
uvCoordinatesForFace.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,10 +2,9 @@ package com.jme3.scene.plugins.blender.textures;
|
|||||||
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.geom.AffineTransform;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -46,8 +45,6 @@ public class CombinedTexture {
|
|||||||
private final int mappingType;
|
private final int mappingType;
|
||||||
/** The data for each of the textures. */
|
/** The data for each of the textures. */
|
||||||
private List<TextureData> textureDatas = new ArrayList<TextureData>();
|
private List<TextureData> textureDatas = new ArrayList<TextureData>();
|
||||||
/** The variable indicates if the texture was already triangulated or not. */
|
|
||||||
private boolean wasTriangulated;
|
|
||||||
/** The result texture. */
|
/** The result texture. */
|
||||||
private Texture resultTexture;
|
private Texture resultTexture;
|
||||||
/** The UV values for the result texture. */
|
/** The UV values for the result texture. */
|
||||||
@ -77,10 +74,12 @@ public class CombinedTexture {
|
|||||||
* the type of UV coordinates projection (for flat textures)
|
* the type of UV coordinates projection (for flat textures)
|
||||||
* @param textureStructure
|
* @param textureStructure
|
||||||
* the texture sructure
|
* the texture sructure
|
||||||
|
* @param uvCoordinatesName
|
||||||
|
* the name of the used user's UV coordinates for this texture
|
||||||
* @param blenderContext
|
* @param blenderContext
|
||||||
* the blender context
|
* the blender context
|
||||||
*/
|
*/
|
||||||
public void add(Texture texture, TextureBlender textureBlender, int uvCoordinatesType, int projectionType, Structure textureStructure, BlenderContext blenderContext) {
|
public void add(Texture texture, TextureBlender textureBlender, int uvCoordinatesType, int projectionType, Structure textureStructure, String uvCoordinatesName, BlenderContext blenderContext) {
|
||||||
if (!(texture instanceof GeneratedTexture) && !(texture instanceof Texture2D)) {
|
if (!(texture instanceof GeneratedTexture) && !(texture instanceof Texture2D)) {
|
||||||
throw new IllegalArgumentException("Unsupported texture type: " + (texture == null ? "null" : texture.getClass()));
|
throw new IllegalArgumentException("Unsupported texture type: " + (texture == null ? "null" : texture.getClass()));
|
||||||
}
|
}
|
||||||
@ -92,6 +91,7 @@ public class CombinedTexture {
|
|||||||
textureData.uvCoordinatesType = UVCoordinatesType.valueOf(uvCoordinatesType);
|
textureData.uvCoordinatesType = UVCoordinatesType.valueOf(uvCoordinatesType);
|
||||||
textureData.projectionType = UVProjectionType.valueOf(projectionType);
|
textureData.projectionType = UVProjectionType.valueOf(projectionType);
|
||||||
textureData.textureStructure = textureStructure;
|
textureData.textureStructure = textureStructure;
|
||||||
|
textureData.uvCoordinatesName = uvCoordinatesName;
|
||||||
|
|
||||||
if (textureDatas.size() > 0 && this.isWithoutAlpha(textureData, blenderContext)) {
|
if (textureDatas.size() > 0 && this.isWithoutAlpha(textureData, blenderContext)) {
|
||||||
textureDatas.clear();// clear previous textures, they will be covered anyway
|
textureDatas.clear();// clear previous textures, they will be covered anyway
|
||||||
@ -119,11 +119,12 @@ public class CombinedTexture {
|
|||||||
* the blender context
|
* the blender context
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void flatten(Geometry geometry, Long geometriesOMA, List<Vector2f> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
public void flatten(Geometry geometry, Long geometriesOMA, LinkedHashMap<String, List<Vector2f>> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
||||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
||||||
Mesh mesh = geometry.getMesh();
|
Mesh mesh = geometry.getMesh();
|
||||||
Texture previousTexture = null;
|
Texture previousTexture = null;
|
||||||
UVCoordinatesType masterUVCoordinatesType = null;
|
UVCoordinatesType masterUVCoordinatesType = null;
|
||||||
|
String masterUserUVSetName = null;
|
||||||
for (TextureData textureData : textureDatas) {
|
for (TextureData textureData : textureDatas) {
|
||||||
// decompress compressed textures (all will be merged into one texture anyway)
|
// decompress compressed textures (all will be merged into one texture anyway)
|
||||||
if (textureDatas.size() > 1 && textureData.texture.getImage().getFormat().isCompressed()) {
|
if (textureDatas.size() > 1 && textureData.texture.getImage().getFormat().isCompressed()) {
|
||||||
@ -138,7 +139,12 @@ public class CombinedTexture {
|
|||||||
resultTexture = textureData.texture;
|
resultTexture = textureData.texture;
|
||||||
|
|
||||||
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
||||||
resultUVS = userDefinedUVCoordinates;
|
if(textureData.uvCoordinatesName == null) {
|
||||||
|
resultUVS = userDefinedUVCoordinates.values().iterator().next();//get the first UV available
|
||||||
|
} else {
|
||||||
|
resultUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
|
||||||
|
}
|
||||||
|
masterUserUVSetName = textureData.uvCoordinatesName;
|
||||||
} else {
|
} else {
|
||||||
List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
resultUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
|
resultUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
|
||||||
@ -161,7 +167,9 @@ public class CombinedTexture {
|
|||||||
triangulatedTexture.blend(textureData.textureBlender, (TriangulatedTexture) resultTexture, blenderContext);
|
triangulatedTexture.blend(textureData.textureBlender, (TriangulatedTexture) resultTexture, blenderContext);
|
||||||
resultTexture = previousTexture = triangulatedTexture;
|
resultTexture = previousTexture = triangulatedTexture;
|
||||||
} else if (textureData.texture instanceof Texture2D) {
|
} else if (textureData.texture instanceof Texture2D) {
|
||||||
if (masterUVCoordinatesType == textureData.uvCoordinatesType && resultTexture instanceof Texture2D) {
|
if (this.isUVTypesMatch(masterUVCoordinatesType, masterUserUVSetName,
|
||||||
|
textureData.uvCoordinatesType, textureData.uvCoordinatesName) &&
|
||||||
|
resultTexture instanceof Texture2D) {
|
||||||
this.scale((Texture2D) textureData.texture, resultTexture.getImage().getWidth(), resultTexture.getImage().getHeight());
|
this.scale((Texture2D) textureData.texture, resultTexture.getImage().getWidth(), resultTexture.getImage().getHeight());
|
||||||
this.merge((Texture2D) resultTexture, (Texture2D) textureData.texture);
|
this.merge((Texture2D) resultTexture, (Texture2D) textureData.texture);
|
||||||
previousTexture = resultTexture;
|
previousTexture = resultTexture;
|
||||||
@ -173,7 +181,11 @@ public class CombinedTexture {
|
|||||||
// first triangulate the current texture
|
// first triangulate the current texture
|
||||||
List<Vector2f> textureUVS = null;
|
List<Vector2f> textureUVS = null;
|
||||||
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
||||||
textureUVS = userDefinedUVCoordinates;
|
if(textureData.uvCoordinatesName == null) {
|
||||||
|
textureUVS = userDefinedUVCoordinates.values().iterator().next();//get the first UV available
|
||||||
|
} else {
|
||||||
|
textureUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||||
textureUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
|
textureUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
|
||||||
@ -196,7 +208,6 @@ public class CombinedTexture {
|
|||||||
}
|
}
|
||||||
resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
|
resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
|
||||||
resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
|
resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
|
||||||
wasTriangulated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting additional data
|
// setting additional data
|
||||||
@ -207,6 +218,31 @@ public class CombinedTexture {
|
|||||||
resultTexture.setMinFilter(MinFilter.NearestNoMipMaps);
|
resultTexture.setMinFilter(MinFilter.NearestNoMipMaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method checks if the texture UV coordinates match.
|
||||||
|
* It the types are equal and different then UVCoordinatesType.TEXCO_UV then we consider them a match.
|
||||||
|
* If they are both UVCoordinatesType.TEXCO_UV then they match only when their UV sets names are equal.
|
||||||
|
* In other cases they are considered NOT a match.
|
||||||
|
* @param type1 the UV coord type
|
||||||
|
* @param uvSetName1 the user's UV coords set name (considered only for UVCoordinatesType.TEXCO_UV)
|
||||||
|
* @param type2 the UV coord type
|
||||||
|
* @param uvSetName2 the user's UV coords set name (considered only for UVCoordinatesType.TEXCO_UV)
|
||||||
|
* @return <b>true</b> if the types match and <b>false</b> otherwise
|
||||||
|
*/
|
||||||
|
private boolean isUVTypesMatch(UVCoordinatesType type1, String uvSetName1,
|
||||||
|
UVCoordinatesType type2, String uvSetName2) {
|
||||||
|
if(type1 == type2) {
|
||||||
|
if(type1 == UVCoordinatesType.TEXCO_UV) {
|
||||||
|
if(uvSetName1 != null && uvSetName2 != null && uvSetName1.equals(uvSetName2)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method blends the texture.
|
* This method blends the texture.
|
||||||
*
|
*
|
||||||
@ -228,129 +264,6 @@ public class CombinedTexture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method casts the current image to the basic UV's owner UV's
|
|
||||||
* coordinates.
|
|
||||||
*
|
|
||||||
* @param basicUVSOwner
|
|
||||||
* the owner of the UV's we cast to
|
|
||||||
* @param blenderContext
|
|
||||||
* the blender context
|
|
||||||
*/
|
|
||||||
public void castToUVS(CombinedTexture basicUVSOwner, BlenderContext blenderContext) {
|
|
||||||
if (resultUVS.size() != basicUVSOwner.resultUVS.size()) {
|
|
||||||
throw new IllegalStateException("The amount of UV coordinates must be equal in order to cast one UV's onto another!");
|
|
||||||
}
|
|
||||||
if (!resultUVS.equals(basicUVSOwner.resultUVS)) {
|
|
||||||
if (!basicUVSOwner.wasTriangulated) {
|
|
||||||
throw new IllegalStateException("The given texture must be triangulated!");
|
|
||||||
}
|
|
||||||
if (!this.wasTriangulated) {
|
|
||||||
resultTexture = new TriangulatedTexture((Texture2D) resultTexture, resultUVS, blenderContext);
|
|
||||||
resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
|
|
||||||
resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
|
|
||||||
}
|
|
||||||
// casting algorithm
|
|
||||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
|
||||||
ImageLoader imageLoader = new ImageLoader();
|
|
||||||
List<TriangleTextureElement> faceTextures = new ArrayList<TriangleTextureElement>();
|
|
||||||
List<Vector2f> basicUVS = basicUVSOwner.getResultUVS();
|
|
||||||
int[] imageRectangle = new int[4];// minX, minY, maxX, maxY
|
|
||||||
int[] sourceSize = new int[2], targetSize = new int[2];// width,
|
|
||||||
// height
|
|
||||||
Vector2f[] destinationUVS = new Vector2f[3];
|
|
||||||
Vector2f[] sourceUVS = new Vector2f[3];
|
|
||||||
List<Vector2f> partImageUVS = Arrays.asList(new Vector2f(), new Vector2f(), new Vector2f());
|
|
||||||
int faceIndex = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < basicUVS.size(); i += 3) {
|
|
||||||
// destination size nad UVS
|
|
||||||
destinationUVS[0] = basicUVS.get(i);
|
|
||||||
destinationUVS[1] = basicUVS.get(i + 1);
|
|
||||||
destinationUVS[2] = basicUVS.get(i + 2);
|
|
||||||
this.computeImageRectangle(destinationUVS, imageRectangle, basicUVSOwner.resultTexture.getImage().getWidth(), basicUVSOwner.resultTexture.getImage().getHeight(), blenderContext);
|
|
||||||
targetSize[0] = imageRectangle[2] - imageRectangle[0];
|
|
||||||
targetSize[1] = imageRectangle[3] - imageRectangle[1];
|
|
||||||
for (int j = 0; j < 3; ++j) {
|
|
||||||
partImageUVS.get(j).set((basicUVSOwner.resultTexture.getImage().getWidth() * destinationUVS[j].x - imageRectangle[0]) / targetSize[0], (basicUVSOwner.resultTexture.getImage().getHeight() * destinationUVS[j].y - imageRectangle[1]) / targetSize[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// source size and UVS (translate UVS to (0,0) and stretch it to
|
|
||||||
// the borders of the image)
|
|
||||||
sourceUVS[0] = resultUVS.get(i);
|
|
||||||
sourceUVS[1] = resultUVS.get(i + 1);
|
|
||||||
sourceUVS[2] = resultUVS.get(i + 2);
|
|
||||||
this.computeImageRectangle(sourceUVS, imageRectangle, resultTexture.getImage().getWidth(), resultTexture.getImage().getHeight(), blenderContext);
|
|
||||||
sourceSize[0] = imageRectangle[2] - imageRectangle[0];
|
|
||||||
sourceSize[1] = imageRectangle[3] - imageRectangle[1];
|
|
||||||
float xTranslateFactor = imageRectangle[0] / (float) resultTexture.getImage().getWidth();
|
|
||||||
float xStreachFactor = resultTexture.getImage().getWidth() / (float) sourceSize[0];
|
|
||||||
float yTranslateFactor = imageRectangle[1] / (float) resultTexture.getImage().getHeight();
|
|
||||||
float yStreachFactor = resultTexture.getImage().getHeight() / (float) sourceSize[1];
|
|
||||||
for (int j = 0; j < 3; ++j) {
|
|
||||||
sourceUVS[j].x = (sourceUVS[j].x - xTranslateFactor) * xStreachFactor;
|
|
||||||
sourceUVS[j].y = (sourceUVS[j].y - yTranslateFactor) * yStreachFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
AffineTransform affineTransform = textureHelper.createAffineTransform(sourceUVS, partImageUVS.toArray(new Vector2f[3]), sourceSize, targetSize);
|
|
||||||
|
|
||||||
Image image = textureHelper.getSubimage(resultTexture.getImage(), imageRectangle[0], imageRectangle[1], imageRectangle[2], imageRectangle[3]);
|
|
||||||
|
|
||||||
// compute the result texture
|
|
||||||
BufferedImage sourceImage = ImageToAwt.convert(image, false, true, 0);
|
|
||||||
|
|
||||||
BufferedImage targetImage = new BufferedImage(targetSize[0], targetSize[1], sourceImage.getType());
|
|
||||||
Graphics2D g = targetImage.createGraphics();
|
|
||||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
||||||
g.drawImage(sourceImage, affineTransform, null);
|
|
||||||
g.dispose();
|
|
||||||
|
|
||||||
Image output = imageLoader.load(targetImage, false);
|
|
||||||
faceTextures.add(new TriangleTextureElement(faceIndex++, output, partImageUVS, false, blenderContext));
|
|
||||||
}
|
|
||||||
TriangulatedTexture triangulatedTexture = new TriangulatedTexture(faceTextures, blenderContext);
|
|
||||||
triangulatedTexture.setKeepIdenticalTextures(false);
|
|
||||||
resultTexture = triangulatedTexture.getResultTexture();
|
|
||||||
resultUVS = basicUVS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method computes the rectangle of an image constrained by the
|
|
||||||
* triangle UV coordinates.
|
|
||||||
*
|
|
||||||
* @param triangleVertices
|
|
||||||
* the triangle UV coordinates
|
|
||||||
* @param result
|
|
||||||
* the array where the result is stored
|
|
||||||
* @param totalImageWidth
|
|
||||||
* the total image width
|
|
||||||
* @param totalImageHeight
|
|
||||||
* the total image height
|
|
||||||
* @param blenderContext
|
|
||||||
* the blender context
|
|
||||||
*/
|
|
||||||
private void computeImageRectangle(Vector2f[] triangleVertices, int[] result, int totalImageWidth, int totalImageHeight, BlenderContext blenderContext) {
|
|
||||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
|
||||||
|
|
||||||
float minX = Math.min(triangleVertices[0].x, triangleVertices[1].x);
|
|
||||||
minX = Math.min(minX, triangleVertices[2].x);
|
|
||||||
|
|
||||||
float maxX = Math.max(triangleVertices[0].x, triangleVertices[1].x);
|
|
||||||
maxX = Math.max(maxX, triangleVertices[2].x);
|
|
||||||
|
|
||||||
float minY = Math.min(triangleVertices[0].y, triangleVertices[1].y);
|
|
||||||
minY = Math.min(minY, triangleVertices[2].y);
|
|
||||||
|
|
||||||
float maxY = Math.max(triangleVertices[0].y, triangleVertices[1].y);
|
|
||||||
maxY = Math.max(maxY, triangleVertices[2].y);
|
|
||||||
|
|
||||||
result[0] = textureHelper.getPixelPosition(minX, totalImageWidth);
|
|
||||||
result[1] = textureHelper.getPixelPosition(minY, totalImageHeight);
|
|
||||||
result[2] = textureHelper.getPixelPosition(maxX, totalImageWidth);
|
|
||||||
result[3] = textureHelper.getPixelPosition(maxY, totalImageHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the result texture
|
* @return the result texture
|
||||||
*/
|
*/
|
||||||
@ -546,5 +459,7 @@ public class CombinedTexture {
|
|||||||
public UVProjectionType projectionType;
|
public UVProjectionType projectionType;
|
||||||
/** The texture sructure. */
|
/** The texture sructure. */
|
||||||
public Structure textureStructure;
|
public Structure textureStructure;
|
||||||
|
/** The name of the user's UV coordinates that are used for this texture. */
|
||||||
|
public String uvCoordinatesName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ import com.jme3.asset.GeneratedTextureKey;
|
|||||||
import com.jme3.asset.TextureKey;
|
import com.jme3.asset.TextureKey;
|
||||||
import com.jme3.math.Vector2f;
|
import com.jme3.math.Vector2f;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.VertexBuffer.Type;
|
||||||
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||||
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
||||||
@ -94,10 +95,10 @@ public class TextureHelper extends AbstractBlenderHelper {
|
|||||||
public static final int TEX_MUSGRAVE = 11;
|
public static final int TEX_MUSGRAVE = 11;
|
||||||
public static final int TEX_VORONOI = 12;
|
public static final int TEX_VORONOI = 12;
|
||||||
public static final int TEX_DISTNOISE = 13;
|
public static final int TEX_DISTNOISE = 13;
|
||||||
public static final int TEX_POINTDENSITY = 14; // v.
|
public static final int TEX_POINTDENSITY = 14; // v. 25+
|
||||||
// 25+
|
public static final int TEX_VOXELDATA = 15; // v. 25+
|
||||||
public static final int TEX_VOXELDATA = 15; // v.
|
|
||||||
// 25+
|
public static final Type[] TEXCOORD_TYPES = new Type[] { Type.TexCoord, Type.TexCoord2, Type.TexCoord3, Type.TexCoord4, Type.TexCoord5, Type.TexCoord6, Type.TexCoord7, Type.TexCoord8 };
|
||||||
|
|
||||||
private TextureGeneratorFactory textureGeneratorFactory = new TextureGeneratorFactory();
|
private TextureGeneratorFactory textureGeneratorFactory = new TextureGeneratorFactory();
|
||||||
|
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
package com.jme3.scene.plugins.blender.textures;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.jme3.math.Vector2f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of UV coordinates. The coords are stored in groups defined by the material index and their UV set name.
|
||||||
|
*
|
||||||
|
* @author Kaelthas (Marcin Roguski)
|
||||||
|
*/
|
||||||
|
public class UserUVCollection {
|
||||||
|
/** A map between material number and UV coordinates of mesh that has this material applied. */
|
||||||
|
private Map<Integer, LinkedHashMap<String, List<Vector2f>>> uvCoordinates = new HashMap<Integer, LinkedHashMap<String, List<Vector2f>>>();
|
||||||
|
/** A map between vertex index and its UV coordinates. */
|
||||||
|
private Map<String, Map<Integer, Vector2f>> uvsMap = new HashMap<String, Map<Integer, Vector2f>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a single UV coordinates for a specified vertex index.
|
||||||
|
* @param materialIndex
|
||||||
|
* the material index
|
||||||
|
* @param uvSetName
|
||||||
|
* the UV set name
|
||||||
|
* @param uv
|
||||||
|
* the added UV coordinates
|
||||||
|
* @param jmeVertexIndex
|
||||||
|
* the index of the vertex in result jme mesh
|
||||||
|
*/
|
||||||
|
public void addUV(int materialIndex, String uvSetName, Vector2f uv, int jmeVertexIndex) {
|
||||||
|
// first get all UV sets for the specified material ...
|
||||||
|
LinkedHashMap<String, List<Vector2f>> uvsForMaterial = uvCoordinates.get(materialIndex);
|
||||||
|
if (uvsForMaterial == null) {
|
||||||
|
uvsForMaterial = new LinkedHashMap<String, List<Vector2f>>();
|
||||||
|
uvCoordinates.put(materialIndex, uvsForMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... then fetch the UVS for the specified UV set name ...
|
||||||
|
List<Vector2f> uvsForName = uvsForMaterial.get(uvSetName);
|
||||||
|
if (uvsForName == null) {
|
||||||
|
uvsForName = new ArrayList<Vector2f>();
|
||||||
|
uvsForMaterial.put(uvSetName, uvsForName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... add the UV coordinates to the proper list ...
|
||||||
|
uvsForName.add(uv);
|
||||||
|
|
||||||
|
// ... and add the mapping of the UV coordinates to a vertex index for the specified UV set
|
||||||
|
Map<Integer, Vector2f> uvToVertexIndexMapping = uvsMap.get(uvSetName);
|
||||||
|
if (uvToVertexIndexMapping == null) {
|
||||||
|
uvToVertexIndexMapping = new HashMap<Integer, Vector2f>();
|
||||||
|
uvsMap.put(uvSetName, uvToVertexIndexMapping);
|
||||||
|
}
|
||||||
|
uvToVertexIndexMapping.put(jmeVertexIndex, uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uvSetName
|
||||||
|
* the name of the UV set
|
||||||
|
* @param vertexIndex
|
||||||
|
* the vertex index corresponds to the index in jme mesh and not the original one in blender
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Vector2f getUVForVertex(String uvSetName, int vertexIndex) {
|
||||||
|
return uvsMap.get(uvSetName).get(vertexIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param materialNumber
|
||||||
|
* the material number that is appied to the mesh
|
||||||
|
* @return UV coordinates of vertices that belong to the required mesh part
|
||||||
|
*/
|
||||||
|
public LinkedHashMap<String, List<Vector2f>> getUVCoordinates(int materialNumber) {
|
||||||
|
return uvCoordinates.get(materialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return indicates if the mesh has UV coordinates
|
||||||
|
*/
|
||||||
|
public boolean hasUVCoordinates() {
|
||||||
|
return uvCoordinates.size() > 0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user