Android: added support for cube maps, Sky works now, use AndroidSkyFactory

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7531 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
kim..ng 14 years ago
parent 4fa5522c8e
commit e5478faae0
  1. 151
      engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
  2. 30
      engine/src/android/com/jme3/renderer/android/TextureUtil.java
  3. 148
      engine/src/android/com/jme3/util/android/AndroidSkyFactory.java

@ -1708,50 +1708,59 @@ public class OGLESShaderRenderer implements Renderer {
} }
} }
private void setupTextureParams(Texture tex){ /**
* <code>setupTextureParams</code> sets the OpenGL context texture parameters
* @param tex the Texture to set the texture parameters from
*/
private void setupTextureParams(Texture tex)
{
int target = convertTextureType(tex.getType()); int target = convertTextureType(tex.getType());
// filter things // filter things
int minFilter = convertMinFilter(tex.getMinFilter()); int minFilter = convertMinFilter(tex.getMinFilter());
int magFilter = convertMagFilter(tex.getMagFilter()); int magFilter = convertMagFilter(tex.getMagFilter());
if (verboseLogging) if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MIN_FILTER, " + minFilter + ")"); logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MIN_FILTER, " + minFilter + ")");
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, minFilter); GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, minFilter);
if (verboseLogging) if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MAG_FILTER, " + magFilter + ")"); logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_MAG_FILTER, " + magFilter + ")");
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, magFilter); GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, magFilter);
/*
if (tex.getAnisotropicFilter() > 1){ if (tex.getAnisotropicFilter() > 1){
/*
if (GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){ if (GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic){
glTexParameterf(target, glTexParameterf(target,
EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT, EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT,
tex.getAnisotropicFilter()); tex.getAnisotropicFilter());
} }
*/
} }
*/
// repeat modes // repeat modes
switch (tex.getType()){ switch (tex.getType()){
case ThreeDimensional: case ThreeDimensional:
case CubeMap: // cubemaps use 3D coords case CubeMap: // cubemaps use 3D coords
// GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R))); // GL_TEXTURE_WRAP_R is not available in api 8
//GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_R, convertWrapMode(tex.getWrap(WrapAxis.R)));
case TwoDimensional: case TwoDimensional:
case TwoDimensionalArray: case TwoDimensionalArray:
if (verboseLogging) if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_T, " + convertWrapMode(tex.getWrap(WrapAxis.T))); logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_T, " + convertWrapMode(tex.getWrap(WrapAxis.T)));
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T))); GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, convertWrapMode(tex.getWrap(WrapAxis.T)));
// fall down here is intentional.. // fall down here is intentional..
// case OneDimensional: // case OneDimensional:
if (verboseLogging) if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_S, " + convertWrapMode(tex.getWrap(WrapAxis.S))); logger.info("GLES20.glTexParameteri(" + target + ", GLES20.GL_TEXTURE_WRAP_S, " + convertWrapMode(tex.getWrap(WrapAxis.S)));
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S))); GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, convertWrapMode(tex.getWrap(WrapAxis.S)));
break; break;
@ -1773,13 +1782,20 @@ public class OGLESShaderRenderer implements Renderer {
*/ */
} }
public void updateTexImageData(Image img, Texture.Type type, boolean mips){ /**
* <code>updateTexImageData</code> activates and binds the texture
* @param img
* @param type
* @param mips
*/
public void updateTexImageData(Image img, Texture.Type type, boolean mips)
{
int texId = img.getId(); int texId = img.getId();
if (texId == -1){ if (texId == -1)
{
// create texture // create texture
if (verboseLogging)
if (verboseLogging) logger.info("GLES20.glGenTexture(1, buffer)");
logger.info("GLES20.glGenTexture(1, buffer)");
GLES20.glGenTextures(1, intBuf1); GLES20.glGenTextures(1, intBuf1);
texId = intBuf1.get(0); texId = intBuf1.get(0);
@ -1791,72 +1807,56 @@ public class OGLESShaderRenderer implements Renderer {
// bind texture // bind texture
int target = convertTextureType(type); int target = convertTextureType(type);
if (context.boundTextures[0] != img){ if (context.boundTextures[0] != img)
if (context.boundTextureUnit != 0){ {
if (context.boundTextureUnit != 0)
if (verboseLogging) {
logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0)"); if (verboseLogging)
logger.info("GLES20.glActiveTexture(GLES20.GL_TEXTURE0)");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
context.boundTextureUnit = 0; context.boundTextureUnit = 0;
} }
if (verboseLogging) if (verboseLogging)
logger.info("GLES20.glBindTexture(" + target + ", " + texId + ")"); logger.info("GLES20.glBindTexture(" + target + ", " + texId + ")");
GLES20.glBindTexture(target, texId); GLES20.glBindTexture(target, texId);
context.boundTextures[0] = img; context.boundTextures[0] = img;
} }
if (!img.hasMipmaps() && mips){
// No pregenerated mips available,
// generate from base level if required
// if (!GLContext.getCapabilities().GL_EXT_framebuffer_multisample){
if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)");
GLES20.glTexParameteri(target, GLES11.GL_GENERATE_MIPMAP, GLES20.GL_TRUE); if (target == GLES20.GL_TEXTURE_CUBE_MAP)
// } {
}else{ // Upload a cube map / sky box
// glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0 ); @SuppressWarnings("unchecked")
if (img.getMipMapSizes() != null){ List<Bitmap> bmps = (List<Bitmap>)img.getEfficentData();
// GLES20.glTexParameteri(target, GLES11.GL_TEXTURE_MAX_LEVEL, img.getMipMapSizes().length ); if (bmps.size() != 6)
{
throw new UnsupportedOperationException("Invalid texture: " + img +
"Cubemap textures must contain 6 data units." );
}
for (int i = 0; i < 6; i++)
{
TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i), false, powerOf2);
} }
} }
else
{
TextureUtil.uploadTexture(img, target, 0, 0, tdc, false, powerOf2);
if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)");
if (target == GLES20.GL_TEXTURE_CUBE_MAP){ if (!img.hasMipmaps() && mips)
List<ByteBuffer> data = img.getData(); {
if (data.size() != 6){ // No pregenerated mips available,
logger.log(Level.WARNING, "Invalid texture: {0}\n" // generate from base level if required
+ "Cubemap textures must contain 6 data units.", img); if (verboseLogging)
return; logger.info("GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D)");
} GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
for (int i = 0; i < 6; i++){
TextureUtil.uploadTexture(img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc, true, powerOf2);
}
}/*else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT){
List<ByteBuffer> data = img.getData();
// -1 index specifies prepare data for 2D Array
TextureUtil.uploadTexture(img, target, -1, 0, tdc);
for (int i = 0; i < data.size(); i++){
// upload each slice of 2D array in turn
// this time with the appropriate index
TextureUtil.uploadTexture(img, target, i, 0, tdc);
} }
}*/else{ }
TextureUtil.uploadTexture(img, target, 0, 0, tdc, true, powerOf2);
if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)");
GLES20.glTexParameteri(target, GLES11.GL_GENERATE_MIPMAP, GLES20.GL_TRUE);
}
// if (GLContext.getCapabilities().GL_EXT_framebuffer_multisample){
// glGenerateMipmapEXT(target);
// }
img.clearUpdateNeeded(); img.clearUpdateNeeded();
} }
@ -1866,14 +1866,19 @@ public class OGLESShaderRenderer implements Renderer {
Image image = tex.getImage(); Image image = tex.getImage();
if (image.isUpdateNeeded()) if (image.isUpdateNeeded())
{ {
/*
Bitmap bmp = (Bitmap)image.getEfficentData(); Bitmap bmp = (Bitmap)image.getEfficentData();
// Check if the bitmap got recycled, can happen after wakeup/restart if (bmp != null)
if ( bmp.isRecycled() )
{ {
// We need to reload the bitmap // Check if the bitmap got recycled, can happen after wakeup/restart
Texture textureReloaded = JmeSystem.newAssetManager().loadTexture((TextureKey)tex.getKey()); if ( bmp.isRecycled() )
image.setEfficentData( textureReloaded.getImage().getEfficentData()); {
// We need to reload the bitmap
Texture textureReloaded = JmeSystem.newAssetManager().loadTexture((TextureKey)tex.getKey());
image.setEfficentData( textureReloaded.getImage().getEfficentData());
}
} }
*/
updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels()); updateTexImageData(image, tex.getType(), tex.getMinFilter().usesMipMapLevels());
} }

@ -62,11 +62,21 @@ public class TextureUtil {
} }
} }
private static void uploadTextureBitmap(Bitmap bitmap, boolean generateMips, boolean powerOf2){ /**
if (!powerOf2){ * <code>uploadTextureBitmap</code> uploads a native android bitmap
* @param target
* @param bitmap
* @param generateMips
* @param powerOf2
*/
public static void uploadTextureBitmap(final int target, Bitmap bitmap, boolean generateMips, boolean powerOf2)
{
if (!powerOf2)
{
int width = bitmap.getWidth(); int width = bitmap.getWidth();
int height = bitmap.getHeight(); int height = bitmap.getHeight();
if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height)){ if (!FastMath.isPowerOfTwo(width) || !FastMath.isPowerOfTwo(height))
{
// scale to power of two // scale to power of two
width = FastMath.nearestPowerOfTwo(width); width = FastMath.nearestPowerOfTwo(width);
height = FastMath.nearestPowerOfTwo(height); height = FastMath.nearestPowerOfTwo(height);
@ -76,11 +86,14 @@ public class TextureUtil {
} }
} }
if (generateMips){ if (generateMips)
{
buildMipmap(bitmap); buildMipmap(bitmap);
}else{ }
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); else
bitmap.recycle(); {
GLUtils.texImage2D(target, 0, bitmap, 0);
//bitmap.recycle();
} }
} }
@ -95,8 +108,7 @@ public class TextureUtil {
if (img.getEfficentData() instanceof Bitmap){ if (img.getEfficentData() instanceof Bitmap){
Bitmap bitmap = (Bitmap) img.getEfficentData(); Bitmap bitmap = (Bitmap) img.getEfficentData();
uploadTextureBitmap(bitmap, generateMips, powerOf2); uploadTextureBitmap(target, bitmap, generateMips, powerOf2);
// img.setEfficentData(null);
return; return;
} }

@ -0,0 +1,148 @@
package com.jme3.util.android;
import java.util.ArrayList;
import android.graphics.Bitmap;
import com.jme3.asset.AssetManager;
import com.jme3.asset.TextureKey;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.TextureCubeMap;
/**
* <code>AndroidSkyFactory</code> creates a sky box spatial
* @author larynx, derived from SkyFactory and adapted for android
*
*/
public class AndroidSkyFactory
{
private static final Sphere sphereMesh = new Sphere(10, 10, 101f, false, true);
public static Spatial createSky(AssetManager assetManager, Texture texture, Vector3f normalScale, boolean sphereMap)
{
Geometry sky = new Geometry("Sky", sphereMesh);
sky.setQueueBucket(Bucket.Sky);
sky.setCullHint(Spatial.CullHint.Never);
Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md");
skyMat.setVector3("NormalScale", normalScale);
if (sphereMap)
{
skyMat.setBoolean("SphereMap", sphereMap);
}
else if (!(texture instanceof TextureCubeMap))
{
// make sure its a cubemap
Image img = texture.getImage();
texture = new TextureCubeMap();
texture.setImage(img);
}
skyMat.setTexture("Texture", texture);
sky.setMaterial(skyMat);
return sky;
}
private static void checkImage(Image image)
{
if (image.getWidth() != image.getHeight())
throw new IllegalArgumentException("Image width and height must be the same");
if (image.getMultiSamples() != 1)
throw new IllegalArgumentException("Multisample textures not allowed");
}
private static void checkImagesForCubeMap(Image ... images)
{
if (images.length == 1) return;
Format fmt = images[0].getFormat();
int width = images[0].getWidth();
int height = images[0].getHeight();
checkImage(images[0]);
for (int i = 1; i < images.length; i++)
{
Image image = images[i];
checkImage(images[i]);
if (image.getFormat() != fmt) throw new IllegalArgumentException("Images must have same format");
if (image.getWidth() != width) throw new IllegalArgumentException("Images must have same width");
if (image.getHeight() != height) throw new IllegalArgumentException("Images must have same height");
}
}
public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south,
Texture up, Texture down, Vector3f normalScale)
{
Geometry sky = new Geometry("Sky", sphereMesh);
sky.setQueueBucket(Bucket.Sky);
sky.setCullHint(Spatial.CullHint.Never);
Image westImg = west.getImage();
Image eastImg = east.getImage();
Image northImg = north.getImage();
Image southImg = south.getImage();
Image upImg = up.getImage();
Image downImg = down.getImage();
checkImagesForCubeMap(westImg, eastImg, northImg, southImg, upImg, downImg);
Image cubeImage = new Image(westImg.getFormat(), westImg.getWidth(), westImg.getHeight(), null);
ArrayList<Bitmap> arrayList = new ArrayList<Bitmap>(6);
arrayList.add((Bitmap)westImg.getEfficentData());
arrayList.add((Bitmap)eastImg.getEfficentData());
arrayList.add((Bitmap)downImg.getEfficentData());
arrayList.add((Bitmap)upImg.getEfficentData());
arrayList.add((Bitmap)southImg.getEfficentData());
arrayList.add((Bitmap)northImg.getEfficentData());
cubeImage.setEfficentData(arrayList);
TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);
cubeMap.setAnisotropicFilter(0);
cubeMap.setMagFilter(Texture.MagFilter.Bilinear);
cubeMap.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
cubeMap.setWrap(Texture.WrapMode.EdgeClamp);
Material skyMat = new Material(assetManager, "Common/MatDefs/Misc/Sky.j3md");
skyMat.setTexture("Texture", cubeMap);
skyMat.setVector3("NormalScale", normalScale);
sky.setMaterial(skyMat);
return sky;
}
public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south,
Texture up, Texture down)
{
return createSky(assetManager, west, east, north, south, up, down, Vector3f.UNIT_XYZ);
}
public static Spatial createSky(AssetManager assetManager, Texture texture, boolean sphereMap)
{
return createSky(assetManager, texture, Vector3f.UNIT_XYZ, sphereMap);
}
public static Spatial createSky(AssetManager assetManager, String textureName, boolean sphereMap)
{
TextureKey key = new TextureKey(textureName, true);
key.setGenerateMips(true);
key.setAsCube(!sphereMap);
Texture tex = assetManager.loadTexture(key);
return createSky(assetManager, tex, sphereMap);
}
}
Loading…
Cancel
Save