Search in sources :

Example 1 with TriangleTextureElement

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);
}
Also used : TriangleTextureElement(com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement) TemporalMesh(com.jme3.scene.plugins.blender.meshes.TemporalMesh) TreeSet(java.util.TreeSet) Vector3f(com.jme3.math.Vector3f) BoundingBox(com.jme3.bounding.BoundingBox)

Example 2 with TriangleTextureElement

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;
}
Also used : Texture2D(com.jme3.texture.Texture2D) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Image(com.jme3.texture.Image) BufferedImage(java.awt.image.BufferedImage) Vector2f(com.jme3.math.Vector2f) HashSet(java.util.HashSet)

Example 3 with TriangleTextureElement

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;
}
Also used : Format(com.jme3.texture.Image.Format) Image(com.jme3.texture.Image) BufferedImage(java.awt.image.BufferedImage)

Example 4 with TriangleTextureElement

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;
}
Also used : TemporalMesh(com.jme3.scene.plugins.blender.meshes.TemporalMesh) Texture2D(com.jme3.texture.Texture2D) TriangleTextureElement(com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement) UVCoordinatesType(com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator.UVCoordinatesType) TemporalMesh(com.jme3.scene.plugins.blender.meshes.TemporalMesh) Mesh(com.jme3.scene.Mesh) ArrayList(java.util.ArrayList) List(java.util.List) Texture(com.jme3.texture.Texture)

Example 5 with TriangleTextureElement

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]);
    }
}
Also used : Vector2f(com.jme3.math.Vector2f) AffineTransform(java.awt.geom.AffineTransform) Image(com.jme3.texture.Image) BufferedImage(java.awt.image.BufferedImage) BufferedImage(java.awt.image.BufferedImage) Graphics2D(java.awt.Graphics2D)

Aggregations

Image (com.jme3.texture.Image)3 BufferedImage (java.awt.image.BufferedImage)3 Vector2f (com.jme3.math.Vector2f)2 TemporalMesh (com.jme3.scene.plugins.blender.meshes.TemporalMesh)2 TriangleTextureElement (com.jme3.scene.plugins.blender.textures.TriangulatedTexture.TriangleTextureElement)2 Texture2D (com.jme3.texture.Texture2D)2 ArrayList (java.util.ArrayList)2 BoundingBox (com.jme3.bounding.BoundingBox)1 Vector3f (com.jme3.math.Vector3f)1 Mesh (com.jme3.scene.Mesh)1 UVCoordinatesType (com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator.UVCoordinatesType)1 Format (com.jme3.texture.Image.Format)1 Texture (com.jme3.texture.Texture)1 Graphics2D (java.awt.Graphics2D)1 AffineTransform (java.awt.geom.AffineTransform)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 List (java.util.List)1 TreeSet (java.util.TreeSet)1