use of com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement in project jmonkeyengine by jMonkeyEngine.
the class GeneratedTexture method triangulate.
/**
* This method triangulates the texture. In the result we get a set of small
* flat textures for each face of the given mesh. This can be later merged
* into one flat texture.
*
* @param mesh
* the mesh we create the texture for
* @param geometriesOMA
* the old memory address of the geometries group that the given
* mesh belongs to (required for bounding box calculations)
* @param coordinatesType
* the types of UV coordinates
* @param blenderContext
* the blender context
* @return triangulated texture
*/
public TriangulatedTexture triangulate(Mesh mesh, Long geometriesOMA, UVCoordinatesType coordinatesType, BlenderContext blenderContext) {
TemporalMesh geometries = (TemporalMesh) blenderContext.getLoadedFeature(geometriesOMA, LoadedDataType.TEMPORAL_MESH);
int[] coordinatesSwappingIndexes = new int[] { ((Number) mTex.getFieldValue("projx")).intValue(), ((Number) mTex.getFieldValue("projy")).intValue(), ((Number) mTex.getFieldValue("projz")).intValue() };
List<Vector3f> uvs = UVCoordinatesGenerator.generateUVCoordinatesFor3DTexture(mesh, coordinatesType, coordinatesSwappingIndexes, geometries);
Vector3f[] uvsArray = uvs.toArray(new Vector3f[uvs.size()]);
BoundingBox boundingBox = UVCoordinatesGenerator.getBoundingBox(geometries);
Set<TriangleTextureElement> triangleTextureElements = new TreeSet<TriangleTextureElement>(new Comparator<TriangleTextureElement>() {
public int compare(TriangleTextureElement o1, TriangleTextureElement o2) {
return o1.faceIndex - o2.faceIndex;
}
});
int[] indices = new int[3];
for (int i = 0; i < mesh.getTriangleCount(); ++i) {
mesh.getTriangle(i, indices);
triangleTextureElements.add(new TriangleTextureElement(i, boundingBox, this, uvsArray, indices, blenderContext));
}
return new TriangulatedTexture(triangleTextureElements, blenderContext);
}
use of com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement in project jmonkeyengine by jMonkeyEngine.
the class TriangulatedTexture method getResultTexture.
/**
* This method returns the flat texture. It is calculated if required or if
* it was not created before. Images that are identical are discarded to
* reduce the texture size.
*
* @param rebuild
* a variable that forces texture recomputation (even if it was
* computed vefore)
* @return flat result texture (all images merged into one)
*/
public Texture2D getResultTexture(boolean rebuild) {
if (resultTexture == null || rebuild) {
// sorting the parts by their height (from highest to the lowest)
List<TriangleTextureElement> list = new ArrayList<TriangleTextureElement>(faceTextures);
Collections.sort(list, new Comparator<TriangleTextureElement>() {
public int compare(TriangleTextureElement o1, TriangleTextureElement o2) {
return o2.image.getHeight() - o1.image.getHeight();
}
});
// arraging the images on the resulting image (calculating the result image width and height)
Set<Integer> duplicatedFaceIndexes = new HashSet<Integer>();
int resultImageHeight = list.get(0).image.getHeight();
int resultImageWidth = 0;
int currentXPos = 0, currentYPos = 0;
Map<TriangleTextureElement, Integer[]> imageLayoutData = new HashMap<TriangleTextureElement, Integer[]>(list.size());
while (list.size() > 0) {
TriangleTextureElement currentElement = list.remove(0);
if (currentXPos + currentElement.image.getWidth() > maxTextureSize) {
currentXPos = 0;
currentYPos = resultImageHeight;
resultImageHeight += currentElement.image.getHeight();
}
Integer[] currentPositions = new Integer[] { currentXPos, currentYPos };
imageLayoutData.put(currentElement, currentPositions);
if (keepIdenticalTextures) {
// removing identical images
for (int i = 0; i < list.size(); ++i) {
if (currentElement.image.equals(list.get(i).image)) {
duplicatedFaceIndexes.add(list.get(i).faceIndex);
imageLayoutData.put(list.remove(i--), currentPositions);
}
}
}
currentXPos += currentElement.image.getWidth();
resultImageWidth = Math.max(resultImageWidth, currentXPos);
// currentYPos += currentElement.image.getHeight();
// TODO: implement that to compact the result image
// try to add smaller images below the current one
// int remainingHeight = resultImageHeight -
// currentElement.image.getHeight();
// while(remainingHeight > 0) {
// for(int i=list.size() - 1;i>=0;--i) {
//
// }
// }
}
// computing the result UV coordinates
resultUVS = new ArrayList<Vector2f>(imageLayoutData.size() * 3);
for (int i = 0; i < imageLayoutData.size() * 3; ++i) {
resultUVS.add(null);
}
Vector2f[] uvs = new Vector2f[3];
for (Entry<TriangleTextureElement, Integer[]> entry : imageLayoutData.entrySet()) {
Integer[] position = entry.getValue();
entry.getKey().computeFinalUVCoordinates(resultImageWidth, resultImageHeight, position[0], position[1], uvs);
resultUVS.set(entry.getKey().faceIndex * 3, uvs[0]);
resultUVS.set(entry.getKey().faceIndex * 3 + 1, uvs[1]);
resultUVS.set(entry.getKey().faceIndex * 3 + 2, uvs[2]);
}
Image resultImage = new Image(format, resultImageWidth, resultImageHeight, BufferUtils.createByteBuffer(resultImageWidth * resultImageHeight * (format.getBitsPerPixel() >> 3)), ColorSpace.Linear);
resultTexture = new Texture2D(resultImage);
for (Entry<TriangleTextureElement, Integer[]> entry : imageLayoutData.entrySet()) {
if (!duplicatedFaceIndexes.contains(entry.getKey().faceIndex)) {
this.draw(resultImage, entry.getKey().image, entry.getValue()[0], entry.getValue()[1]);
}
}
// setting additional data
resultTexture.setWrap(WrapAxis.S, this.getWrap(WrapAxis.S));
resultTexture.setWrap(WrapAxis.T, this.getWrap(WrapAxis.T));
resultTexture.setMagFilter(this.getMagFilter());
resultTexture.setMinFilter(this.getMinFilter());
}
return resultTexture;
}
use of com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement in project jmonkeyengine by jMonkeyEngine.
the class TriangulatedTexture method blend.
/**
* This method blends the each image using the given blender and taking base
* texture into consideration.
*
* @param textureBlender
* the texture blender that holds the blending definition
* @param baseTexture
* the texture that is 'below' the current texture (can be null)
* @param blenderContext
* the blender context
*/
public void blend(TextureBlender textureBlender, TriangulatedTexture baseTexture, BlenderContext blenderContext) {
Format newFormat = null;
for (TriangleTextureElement triangleTextureElement : faceTextures) {
Image baseImage = baseTexture == null ? null : baseTexture.getFaceTextureElement(triangleTextureElement.faceIndex).image;
triangleTextureElement.image = textureBlender.blend(triangleTextureElement.image, baseImage, blenderContext);
if (newFormat == null) {
newFormat = triangleTextureElement.image.getFormat();
} else if (newFormat != triangleTextureElement.image.getFormat()) {
throw new IllegalArgumentException("Face texture element images MUST have the same image format!");
}
}
format = newFormat;
}
use of com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement in project jmonkeyengine by jMonkeyEngine.
the class CombinedTexture method flatten.
/**
* This method flattens the texture and creates a single result of Texture2D
* type.
*
* @param geometry
* the geometry the texture is created for
* @param geometriesOMA
* the old memory address of the geometries list that the given
* geometry belongs to (needed for bounding box creation)
* @param userDefinedUVCoordinates
* the UV's defined by user (null or zero length table if none
* were defined)
* @param blenderContext
* the blender context
* @return the name of the user UV coordinates used (null if the UV's were
* generated)
*/
public String flatten(Geometry geometry, Long geometriesOMA, Map<String, List<Vector2f>> userDefinedUVCoordinates, BlenderContext blenderContext) {
Mesh mesh = geometry.getMesh();
Texture previousTexture = null;
UVCoordinatesType masterUVCoordinatesType = null;
String masterUserUVSetName = null;
for (TextureData textureData : textureDatas) {
// decompress compressed textures (all will be merged into one texture anyway)
if (textureDatas.size() > 1 && textureData.texture.getImage().getFormat().isCompressed()) {
textureData.texture.setImage(ImageUtils.decompress(textureData.texture.getImage()));
textureData.textureBlender = TextureBlenderFactory.alterTextureType(textureData.texture.getImage().getFormat(), textureData.textureBlender);
}
if (previousTexture == null) {
// the first texture will lead the others to its shape
if (textureData.texture instanceof GeneratedTexture) {
resultTexture = ((GeneratedTexture) textureData.texture).triangulate(mesh, geometriesOMA, textureData.uvCoordinatesType, blenderContext);
} else if (textureData.texture instanceof Texture2D) {
resultTexture = textureData.texture;
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
if (textureData.uvCoordinatesName == null) {
// get the first UV available
resultUVS = userDefinedUVCoordinates.values().iterator().next();
} else {
resultUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
}
if (resultUVS == null && LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("The texture " + textureData.texture.getName() + " has assigned non existing UV coordinates group: " + textureData.uvCoordinatesName + ".");
}
masterUserUVSetName = textureData.uvCoordinatesName;
} else {
TemporalMesh temporalMesh = (TemporalMesh) blenderContext.getLoadedFeature(geometriesOMA, LoadedDataType.TEMPORAL_MESH);
resultUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, temporalMesh);
}
}
this.blend(resultTexture, textureData.textureBlender, blenderContext);
previousTexture = resultTexture;
masterUVCoordinatesType = textureData.uvCoordinatesType;
} else {
if (textureData.texture instanceof GeneratedTexture) {
if (!(resultTexture instanceof TriangulatedTexture)) {
resultTexture = new TriangulatedTexture((Texture2D) resultTexture, resultUVS, blenderContext);
resultUVS = null;
previousTexture = resultTexture;
}
TriangulatedTexture triangulatedTexture = ((GeneratedTexture) textureData.texture).triangulate(mesh, geometriesOMA, textureData.uvCoordinatesType, blenderContext);
triangulatedTexture.castToUVS((TriangulatedTexture) resultTexture, blenderContext);
triangulatedTexture.blend(textureData.textureBlender, (TriangulatedTexture) resultTexture, blenderContext);
resultTexture = previousTexture = triangulatedTexture;
} else if (textureData.texture 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());
ImageUtils.merge(resultTexture.getImage(), textureData.texture.getImage());
previousTexture = resultTexture;
} else {
if (!(resultTexture instanceof TriangulatedTexture)) {
resultTexture = new TriangulatedTexture((Texture2D) resultTexture, resultUVS, blenderContext);
resultUVS = null;
}
// first triangulate the current texture
List<Vector2f> textureUVS = null;
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
if (textureData.uvCoordinatesName == null) {
// get the first UV available
textureUVS = userDefinedUVCoordinates.values().iterator().next();
} else {
textureUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
}
} else {
TemporalMesh geometries = (TemporalMesh) blenderContext.getLoadedFeature(geometriesOMA, LoadedDataType.TEMPORAL_MESH);
textureUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
}
TriangulatedTexture triangulatedTexture = new TriangulatedTexture((Texture2D) textureData.texture, textureUVS, blenderContext);
// then move the texture to different UV's
triangulatedTexture.castToUVS((TriangulatedTexture) resultTexture, blenderContext);
// merge triangulated textures
for (int i = 0; i < ((TriangulatedTexture) resultTexture).getFaceTextureCount(); ++i) {
ImageUtils.merge(((TriangulatedTexture) resultTexture).getFaceTextureElement(i).image, triangulatedTexture.getFaceTextureElement(i).image);
}
}
}
}
}
if (resultTexture instanceof TriangulatedTexture) {
if (mappingType == MaterialContext.MTEX_NOR) {
for (int i = 0; i < ((TriangulatedTexture) resultTexture).getFaceTextureCount(); ++i) {
TriangleTextureElement triangleTextureElement = ((TriangulatedTexture) resultTexture).getFaceTextureElement(i);
// TODO: get proper strength factor
triangleTextureElement.image = ImageUtils.convertToNormalMapTexture(triangleTextureElement.image, 1);
}
}
resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
masterUserUVSetName = null;
}
// setting additional data
resultTexture.setWrap(WrapMode.Repeat);
// the filters are required if generated textures are used because
// otherwise ugly lines appear between the mesh faces
resultTexture.setMagFilter(MagFilter.Nearest);
resultTexture.setMinFilter(MinFilter.NearestNoMipMaps);
return masterUserUVSetName;
}
use of com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement in project jmonkeyengine by jMonkeyEngine.
the class TriangulatedTexture method castToUVS.
/**
* This method alters the images to fit them into UV coordinates of the
* given target texture.
*
* @param targetTexture
* the texture to whose UV coordinates we fit current images
* @param blenderContext
* the blender context
*/
public void castToUVS(TriangulatedTexture targetTexture, BlenderContext blenderContext) {
int[] sourceSize = new int[2], targetSize = new int[2];
ImageLoader imageLoader = new ImageLoader();
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
for (TriangleTextureElement entry : faceTextures) {
TriangleTextureElement targetFaceTextureElement = targetTexture.getFaceTextureElement(entry.faceIndex);
Vector2f[] dest = targetFaceTextureElement.uv;
// get the sizes of the source and target images
sourceSize[0] = entry.image.getWidth();
sourceSize[1] = entry.image.getHeight();
targetSize[0] = targetFaceTextureElement.image.getWidth();
targetSize[1] = targetFaceTextureElement.image.getHeight();
// create triangle transformation
AffineTransform affineTransform = textureHelper.createAffineTransform(entry.uv, dest, sourceSize, targetSize);
// compute the result texture
BufferedImage sourceImage = ImageToAwt.convert(entry.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);
entry.image = output;
entry.uv[0].set(dest[0]);
entry.uv[1].set(dest[1]);
entry.uv[2].set(dest[2]);
}
}
Aggregations