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);
}
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());
}
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;
}
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;
}
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;
}
Aggregations