Search in sources :

Example 21 with Texture

use of com.jme3.texture.Texture in project jmonkeyengine by jMonkeyEngine.

the class GeneratedTexture method generateSkyTexture.

/**
     * Creates a texture for the sky. The result texture has 6 layers.
     * @param size
     *            the size of the texture (width and height are equal)
     * @param horizontalColor
     *            the horizon color
     * @param zenithColor
     *            the zenith color
     * @param blenderContext
     *            the blender context
     * @return the sky texture
     */
public TextureCubeMap generateSkyTexture(int size, ColorRGBA horizontalColor, ColorRGBA zenithColor, BlenderContext blenderContext) {
    Image image = ImageUtils.createEmptyImage(Format.RGB8, size, size, 6);
    PixelInputOutput pixelIO = PixelIOFactory.getPixelIO(image.getFormat());
    TexturePixel pixel = new TexturePixel();
    float delta = 1 / (float) (size - 1);
    float sideV, sideS = 1, forwardU = 1, forwardV, upS;
    TempVars tempVars = TempVars.get();
    CastFunction castFunction = CAST_FUNCTIONS[blenderContext.getBlenderKey().getSkyGeneratedTextureShape().ordinal()];
    float castRadius = blenderContext.getBlenderKey().getSkyGeneratedTextureRadius();
    for (int x = 0; x < size; ++x) {
        sideV = 1;
        forwardV = 1;
        upS = 0;
        for (int y = 0; y < size; ++y) {
            castFunction.cast(tempVars.vect1.set(1, sideV, sideS), castRadius);
            textureGenerator.getPixel(pixel, tempVars.vect1.x, tempVars.vect1.y, tempVars.vect1.z);
            // right
            pixelIO.write(image, NEGATIVE_X, ImageUtils.color(pixel, horizontalColor, zenithColor), x, y);
            castFunction.cast(tempVars.vect1.set(0, sideV, 1 - sideS), castRadius);
            textureGenerator.getPixel(pixel, tempVars.vect1.x, tempVars.vect1.y, tempVars.vect1.z);
            // left
            pixelIO.write(image, POSITIVE_X, ImageUtils.color(pixel, horizontalColor, zenithColor), x, y);
            castFunction.cast(tempVars.vect1.set(forwardU, forwardV, 0), castRadius);
            textureGenerator.getPixel(pixel, tempVars.vect1.x, tempVars.vect1.y, tempVars.vect1.z);
            // front
            pixelIO.write(image, POSITIVE_Z, ImageUtils.color(pixel, horizontalColor, zenithColor), x, y);
            castFunction.cast(tempVars.vect1.set(1 - forwardU, forwardV, 1), castRadius);
            textureGenerator.getPixel(pixel, tempVars.vect1.x, tempVars.vect1.y, tempVars.vect1.z);
            // back
            pixelIO.write(image, NEGATIVE_Z, ImageUtils.color(pixel, horizontalColor, zenithColor), x, y);
            castFunction.cast(tempVars.vect1.set(forwardU, 0, upS), castRadius);
            textureGenerator.getPixel(pixel, tempVars.vect1.x, tempVars.vect1.y, tempVars.vect1.z);
            // top
            pixelIO.write(image, NEGATIVE_Y, ImageUtils.color(pixel, horizontalColor, zenithColor), x, y);
            castFunction.cast(tempVars.vect1.set(forwardU, 1, 1 - upS), castRadius);
            textureGenerator.getPixel(pixel, tempVars.vect1.x, tempVars.vect1.y, tempVars.vect1.z);
            // bottom
            pixelIO.write(image, POSITIVE_Y, ImageUtils.color(pixel, horizontalColor, zenithColor), x, y);
            sideV = FastMath.clamp(sideV - delta, 0, 1);
            forwardV = FastMath.clamp(forwardV - delta, 0, 1);
            upS = FastMath.clamp(upS + delta, 0, 1);
        }
        sideS = FastMath.clamp(sideS - delta, 0, 1);
        forwardU = FastMath.clamp(forwardU - delta, 0, 1);
    }
    tempVars.release();
    return new TextureCubeMap(image);
}
Also used : PixelInputOutput(com.jme3.scene.plugins.blender.textures.io.PixelInputOutput) TextureCubeMap(com.jme3.texture.TextureCubeMap) TempVars(com.jme3.util.TempVars) Image(com.jme3.texture.Image)

Example 22 with Texture

use of com.jme3.texture.Texture in project jmonkeyengine by jMonkeyEngine.

the class ImageUtils method convertToNormalMapTexture.

/**
     * This method converts the given texture into normal-map texture.
     * 
     * @param source
     *            the source texture
     * @param strengthFactor
     *            the normal strength factor
     * @return normal-map texture
     */
public static Image convertToNormalMapTexture(Image source, float strengthFactor) {
    BufferedImage sourceImage = ImageToAwt.convert(source, false, false, 0);
    BufferedImage heightMap = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
    BufferedImage bumpMap = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
    ColorConvertOp gscale = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
    gscale.filter(sourceImage, heightMap);
    Vector3f S = new Vector3f();
    Vector3f T = new Vector3f();
    Vector3f N = new Vector3f();
    for (int x = 0; x < bumpMap.getWidth(); ++x) {
        for (int y = 0; y < bumpMap.getHeight(); ++y) {
            // generating bump pixel
            S.x = 1;
            S.y = 0;
            S.z = strengthFactor * ImageUtils.getHeight(heightMap, x + 1, y) - strengthFactor * ImageUtils.getHeight(heightMap, x - 1, y);
            T.x = 0;
            T.y = 1;
            T.z = strengthFactor * ImageUtils.getHeight(heightMap, x, y + 1) - strengthFactor * ImageUtils.getHeight(heightMap, x, y - 1);
            float den = (float) Math.sqrt(S.z * S.z + T.z * T.z + 1);
            N.x = -S.z;
            N.y = -T.z;
            N.z = 1;
            N.divideLocal(den);
            // setting thge pixel in the result image
            bumpMap.setRGB(x, y, ImageUtils.vectorToColor(N.x, N.y, N.z));
        }
    }
    return ImageUtils.toJmeImage(bumpMap, source.getFormat());
}
Also used : ColorConvertOp(java.awt.image.ColorConvertOp) Vector3f(com.jme3.math.Vector3f) BufferedImage(java.awt.image.BufferedImage)

Example 23 with Texture

use of com.jme3.texture.Texture in project jmonkeyengine by jMonkeyEngine.

the class TextureHelper method getTexture.

/**
     * This class returns a texture read from the file or from packed blender
     * data. The returned texture has the name set to the value of its blender
     * type.
     * 
     * @param textureStructure
     *            texture structure filled with data
     * @param blenderContext
     *            the blender context
     * @return the texture that can be used by JME engine
     * @throws BlenderFileException
     *             this exception is thrown when the blend file structure is
     *             somehow invalid or corrupted
     */
public Texture getTexture(Structure textureStructure, Structure mTex, BlenderContext blenderContext) throws BlenderFileException {
    Texture result = (Texture) blenderContext.getLoadedFeature(textureStructure.getOldMemoryAddress(), LoadedDataType.FEATURE);
    if (result != null) {
        return result;
    }
    if ("ID".equals(textureStructure.getType())) {
        LOGGER.fine("Loading texture from external blend file.");
        return (Texture) this.loadLibrary(textureStructure);
    }
    int type = ((Number) textureStructure.getFieldValue("type")).intValue();
    int imaflag = ((Number) textureStructure.getFieldValue("imaflag")).intValue();
    switch(type) {
        case // (it is first because probably this will be most commonly used)
        TEX_IMAGE:
            Pointer pImage = (Pointer) textureStructure.getFieldValue("ima");
            if (pImage.isNotNull()) {
                Structure image = pImage.fetchData().get(0);
                Texture loadedTexture = this.loadImageAsTexture(image, imaflag, blenderContext);
                if (loadedTexture != null) {
                    result = loadedTexture;
                    this.applyColorbandAndColorFactors(textureStructure, result.getImage(), blenderContext);
                }
            }
            break;
        case TEX_CLOUDS:
        case TEX_WOOD:
        case TEX_MARBLE:
        case TEX_MAGIC:
        case TEX_BLEND:
        case TEX_STUCCI:
        case TEX_NOISE:
        case TEX_MUSGRAVE:
        case TEX_VORONOI:
        case TEX_DISTNOISE:
            result = new GeneratedTexture(textureStructure, mTex, textureGeneratorFactory.createTextureGenerator(type), blenderContext);
            break;
        case // No texture, do nothing
        TEX_NONE:
            break;
        case TEX_POINTDENSITY:
        case TEX_VOXELDATA:
        case TEX_PLUGIN:
        case TEX_ENVMAP:
        case TEX_OCEAN:
            LOGGER.log(Level.WARNING, "Unsupported texture type: {0} for texture: {1}", new Object[] { type, textureStructure.getName() });
            break;
        default:
            throw new BlenderFileException("Unknown texture type: " + type + " for texture: " + textureStructure.getName());
    }
    if (result != null) {
        result.setName(textureStructure.getName());
        result.setWrap(WrapMode.Repeat);
        // decide if the mipmaps will be generated
        switch(blenderContext.getBlenderKey().getMipmapGenerationMethod()) {
            case ALWAYS_GENERATE:
                result.setMinFilter(MinFilter.Trilinear);
                break;
            case NEVER_GENERATE:
                break;
            case GENERATE_WHEN_NEEDED:
                if ((imaflag & 0x04) != 0) {
                    result.setMinFilter(MinFilter.Trilinear);
                }
                break;
            default:
                throw new IllegalStateException("Unknown mipmap generation method: " + blenderContext.getBlenderKey().getMipmapGenerationMethod());
        }
        if (type != TEX_IMAGE) {
            // only generated textures should have this key
            result.setKey(new GeneratedTextureKey(textureStructure.getName()));
        }
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.log(Level.FINE, "Adding texture {0} to the loaded features with OMA = {1}", new Object[] { result.getName(), textureStructure.getOldMemoryAddress() });
        }
        blenderContext.addLoadedFeatures(textureStructure.getOldMemoryAddress(), LoadedDataType.STRUCTURE, textureStructure);
        blenderContext.addLoadedFeatures(textureStructure.getOldMemoryAddress(), LoadedDataType.FEATURE, result);
    }
    return result;
}
Also used : BlenderFileException(com.jme3.scene.plugins.blender.file.BlenderFileException) Pointer(com.jme3.scene.plugins.blender.file.Pointer) GeneratedTextureKey(com.jme3.asset.GeneratedTextureKey) Structure(com.jme3.scene.plugins.blender.file.Structure) Texture(com.jme3.texture.Texture)

Example 24 with Texture

use of com.jme3.texture.Texture in project jmonkeyengine by jMonkeyEngine.

the class TextureHelper method loadImageFromFile.

/**
     * This method loads the textre from outside the blend file using the
     * AssetManager that the blend file was loaded with. It returns a texture
     * with a full assetKey that references the original texture so it later
     * doesn't need to ba packed when the model data is serialized. It searches
     * the AssetManager for the full path if the model file is a relative path
     * and will attempt to truncate the path if it is an absolute file path
     * until the path can be found in the AssetManager. If the texture can not
     * be found, it will issue a load attempt for the initial path anyway so the
     * failed load can be reported by the AssetManagers callback methods for
     * failed assets.
     * 
     * @param name
     *            the path to the image
     * @param imaflag
     *            the image flag
     * @param blenderContext
     *            the blender context
     * @return the loaded image or null if the image cannot be found
     */
protected Texture loadImageFromFile(String name, int imaflag, BlenderContext blenderContext) {
    if (!name.contains(".")) {
        // no extension means not a valid image
        return null;
    }
    // decide if the mipmaps will be generated
    boolean generateMipmaps = false;
    switch(blenderContext.getBlenderKey().getMipmapGenerationMethod()) {
        case ALWAYS_GENERATE:
            generateMipmaps = true;
            break;
        case NEVER_GENERATE:
            break;
        case GENERATE_WHEN_NEEDED:
            generateMipmaps = (imaflag & 0x04) != 0;
            break;
        default:
            throw new IllegalStateException("Unknown mipmap generation method: " + blenderContext.getBlenderKey().getMipmapGenerationMethod());
    }
    AssetManager assetManager = blenderContext.getAssetManager();
    name = name.replace('\\', '/');
    Texture result = null;
    if (name.startsWith("//")) {
        // This is a relative path, so try to find it relative to the .blend file
        String relativePath = name.substring(2);
        // Augument the path with blender key path
        BlenderKey blenderKey = blenderContext.getBlenderKey();
        int idx = blenderKey.getName().lastIndexOf('/');
        String blenderAssetFolder = blenderKey.getName().substring(0, idx != -1 ? idx : 0);
        String absoluteName = blenderAssetFolder + '/' + relativePath;
        // Directly try to load texture so AssetManager can report missing textures
        try {
            TextureKey key = new TextureKey(absoluteName);
            key.setFlipY(true);
            key.setGenerateMips(generateMipmaps);
            result = assetManager.loadTexture(key);
            result.setKey(key);
        } catch (AssetNotFoundException | AssetLoadException e) {
            LOGGER.fine(e.getLocalizedMessage());
        }
    } else {
        // This is a full path, try to truncate it until the file can be found
        // this works as the assetManager root is most probably a part of the
        // image path. E.g. AssetManager has a locator at c:/Files/ and the
        // texture path is c:/Files/Textures/Models/Image.jpg.
        // For this we create a list with every possible full path name from
        // the asset name to the root. Image.jpg, Models/Image.jpg,
        // Textures/Models/Image.jpg (bingo) etc.
        List<String> assetNames = new ArrayList<String>();
        String[] paths = name.split("\\/");
        // the asset name
        StringBuilder sb = new StringBuilder(paths[paths.length - 1]);
        assetNames.add(paths[paths.length - 1]);
        for (int i = paths.length - 2; i >= 0; --i) {
            sb.insert(0, '/');
            sb.insert(0, paths[i]);
            assetNames.add(0, sb.toString());
        }
        // Now try to locate the asset
        for (String assetName : assetNames) {
            try {
                TextureKey key = new TextureKey(assetName);
                key.setFlipY(true);
                key.setGenerateMips(generateMipmaps);
                AssetInfo info = assetManager.locateAsset(key);
                if (info != null) {
                    Texture texture = assetManager.loadTexture(key);
                    result = texture;
                    // Set key explicitly here if other ways fail
                    texture.setKey(key);
                    // If texture is found return it;
                    return result;
                }
            } catch (AssetNotFoundException | AssetLoadException e) {
                LOGGER.fine(e.getLocalizedMessage());
            }
        }
        // the missing asset to subsystems.
        try {
            TextureKey key = new TextureKey(name);
            assetManager.loadTexture(key);
        } catch (AssetNotFoundException | AssetLoadException e) {
            LOGGER.fine(e.getLocalizedMessage());
        }
    }
    return result;
}
Also used : AssetManager(com.jme3.asset.AssetManager) ArrayList(java.util.ArrayList) AssetNotFoundException(com.jme3.asset.AssetNotFoundException) AssetInfo(com.jme3.asset.AssetInfo) Texture(com.jme3.texture.Texture) AssetLoadException(com.jme3.asset.AssetLoadException) GeneratedTextureKey(com.jme3.asset.GeneratedTextureKey) TextureKey(com.jme3.asset.TextureKey) BlenderKey(com.jme3.asset.BlenderKey)

Example 25 with Texture

use of com.jme3.texture.Texture 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)

Aggregations

Material (com.jme3.material.Material)97 Texture (com.jme3.texture.Texture)94 Vector3f (com.jme3.math.Vector3f)66 Geometry (com.jme3.scene.Geometry)40 Image (com.jme3.texture.Image)39 TextureKey (com.jme3.asset.TextureKey)31 ArrayList (java.util.ArrayList)27 Texture2D (com.jme3.texture.Texture2D)25 ColorRGBA (com.jme3.math.ColorRGBA)23 Box (com.jme3.scene.shape.Box)19 Spatial (com.jme3.scene.Spatial)18 TerrainQuad (com.jme3.terrain.geomipmap.TerrainQuad)18 ParticleEmitter (com.jme3.effect.ParticleEmitter)17 DirectionalLight (com.jme3.light.DirectionalLight)17 Vector2f (com.jme3.math.Vector2f)17 TerrainLodControl (com.jme3.terrain.geomipmap.TerrainLodControl)16 ByteBuffer (java.nio.ByteBuffer)16 AbstractHeightMap (com.jme3.terrain.heightmap.AbstractHeightMap)15 ImageBasedHeightMap (com.jme3.terrain.heightmap.ImageBasedHeightMap)15 Camera (com.jme3.renderer.Camera)14