add native android lib for loading png and gif files. Does not premultiply. Uses stb_image (http://www.nothings.org/stb_image.c)

experimental
iwgeric 11 years ago
parent b94a20db14
commit ee8e42f921
  1. 142
      .gitignore
  2. 2
      jme3-android-native/build.gradle
  3. 13
      jme3-android-native/src/native/jme_stbi/Android.mk
  4. 3
      jme3-android-native/src/native/jme_stbi/Application.mk
  5. 125
      jme3-android-native/src/native/jme_stbi/com_jme3_texture_plugins_AndroidNativeImageLoader.c
  6. 66
      jme3-android-native/stb_image.gradle
  7. 4673
      jme3-android-native/stb_image/stb_image.c
  8. 163
      jme3-android/src/main/java/com/jme3/texture/plugins/AndroidNativeImageLoader.java

142
.gitignore vendored

@ -1,70 +1,72 @@
/.gradle/
/.nb-gradle/private/
/jme3-core/build/
/jme3-plugins/build/
/jme3-desktop/build/
/jme3-android-native/build/
/jme3-android/build/
/jme3-blender/build/
/jme3-effects/build/
/jme3-bullet/build/
/jme3-terrain/build/
/jme3-bullet-native/build/
/jme3-jogg/build/
/jme3-jbullet/build/
/jme3-lwjgl/build/
/jme3-networking/build/
/jme3-niftygui/build/
/jme3-testdata/build/
/jme3-examples/build/
/jme3-jogl/build/
/dist/
/jme3-bullet-native/bullet.zip
/jme3-bullet-native/bullet-2.82-r2704/
/sdk/build/
/sdk/jme3-core-baselibs/release/
/sdk/jme3-core-libraries/release/
/sdk/jme3-project-baselibs/release/
/sdk/jme3-project-libraries/release/
/sdk/jme3-codepalette/build/
/sdk/jme3-core-libraries/build/
/sdk/jme3-code-check/build/
/sdk/jme3-core-baselibs/build/
/sdk/jme3-core-baselibs/nbproject/private/
/sdk/jme3-documentation/build/
/sdk/jme3-core-updatecenters/build/
/sdk/jme3-project-testdata/build/
/sdk/jme3-project-libraries/build/
/sdk/jme3-project-baselibs/build/
/sdk/jme3-templates/build/
/sdk/jme3-texture-editor/build/
/sdk/jme3-tests-template/build/
/sdk/jme3-upgrader/build/
/sdk/jme3-core/build/
/sdk/jme3-obfuscate/build/
/sdk/jme3-gui/build/
/sdk/jme3-cinematics/build/
/sdk/jme3-terrain-editor/build/
/sdk/jme3-lwjgl-applet/build/
/sdk/jme3-blender/build/
/sdk/jme3-navmesh-gen/build/
/sdk/jme3-angelfont/build/
/sdk/jme3-materialeditor/build/
/sdk/jme3-android/build/
/sdk/jme3-desktop-executables/build/
/sdk/jme3-ogrexml/build/
/sdk/jme3-ogretools/build/
/sdk/jme3-scenecomposer/build/
/sdk/jme3-assetpack-support/build/
/sdk/jme3-model-importer/build/
/sdk/jme3-wavefront/build/
/sdk/jme3-vehicle-creator/build/
/sdk/jme3-welcome-screen/build/
/sdk/jme3-glsl-support/build/
/netbeans/
/sdk/jme3-tests-template/src/com/jme3/gde/templates/tests/JmeTestsProject.zip
/sdk/jme3-tests-template/src/com/jme3/gde/templates/tests/JME3TestsAndroidProject.zip
/sdk/jme3-project-testdata/release/
/sdk/JME3TestsTemplateAndroid/src/jme3test/
/sdk/JME3TestsTemplate/src/jme3test/
/jme3-ios/build/
/.gradle/
/.nb-gradle/private/
/jme3-core/build/
/jme3-plugins/build/
/jme3-desktop/build/
/jme3-android-native/build/
/jme3-android/build/
/jme3-blender/build/
/jme3-effects/build/
/jme3-bullet/build/
/jme3-terrain/build/
/jme3-bullet-native/build/
/jme3-jogg/build/
/jme3-jbullet/build/
/jme3-lwjgl/build/
/jme3-networking/build/
/jme3-niftygui/build/
/jme3-testdata/build/
/jme3-examples/build/
/jme3-jogl/build/
/dist/
/jme3-bullet-native/bullet.zip
/jme3-bullet-native/bullet-2.82-r2704/
/sdk/build/
/sdk/jme3-core-baselibs/release/
/sdk/jme3-core-libraries/release/
/sdk/jme3-project-baselibs/release/
/sdk/jme3-project-libraries/release/
/sdk/jme3-codepalette/build/
/sdk/jme3-core-libraries/build/
/sdk/jme3-code-check/build/
/sdk/jme3-core-baselibs/build/
/sdk/jme3-core-baselibs/nbproject/private/
/sdk/jme3-documentation/build/
/sdk/jme3-core-updatecenters/build/
/sdk/jme3-project-testdata/build/
/sdk/jme3-project-libraries/build/
/sdk/jme3-project-baselibs/build/
/sdk/jme3-templates/build/
/sdk/jme3-texture-editor/build/
/sdk/jme3-tests-template/build/
/sdk/jme3-upgrader/build/
/sdk/jme3-core/build/
/sdk/jme3-obfuscate/build/
/sdk/jme3-gui/build/
/sdk/jme3-cinematics/build/
/sdk/jme3-terrain-editor/build/
/sdk/jme3-lwjgl-applet/build/
/sdk/jme3-blender/build/
/sdk/jme3-navmesh-gen/build/
/sdk/jme3-angelfont/build/
/sdk/jme3-materialeditor/build/
/sdk/jme3-android/build/
/sdk/jme3-desktop-executables/build/
/sdk/jme3-ogrexml/build/
/sdk/jme3-ogretools/build/
/sdk/jme3-scenecomposer/build/
/sdk/jme3-assetpack-support/build/
/sdk/jme3-model-importer/build/
/sdk/jme3-wavefront/build/
/sdk/jme3-vehicle-creator/build/
/sdk/jme3-welcome-screen/build/
/sdk/jme3-glsl-support/build/
/netbeans/
/sdk/jme3-tests-template/src/com/jme3/gde/templates/tests/JmeTestsProject.zip
/sdk/jme3-tests-template/src/com/jme3/gde/templates/tests/JME3TestsAndroidProject.zip
/sdk/jme3-project-testdata/release/
/sdk/JME3TestsTemplateAndroid/src/jme3test/
/sdk/JME3TestsTemplate/src/jme3test/
/jme3-ios/build/
/jme3-android-native/openal-soft/
/jme3-android-native/OpenALSoft.zip

@ -49,5 +49,5 @@ ext {
// add each native lib build file
apply from: file('openalsoft.gradle')
//apply from: file('stb_image.gradle')
apply from: file('stb_image.gradle')

@ -0,0 +1,13 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := stbijme
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_CFLAGS += -O2
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := $(subst $(LOCAL_PATH)/,, $(wildcard $(LOCAL_PATH)/*.c))
#adds zlib
LOCAL_LDLIBS += -lz -llog
include $(BUILD_SHARED_LIBRARY)

@ -0,0 +1,3 @@
APP_OPTIM := release
APP_ABI := all
#APP_ABI := armeabi-v7a

@ -0,0 +1,125 @@
#include "com_jme3_texture_plugins_AndroidNativeImageLoader.h"
// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
#include <android/log.h>
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#define STBI_HEADER_FILE_ONLY
#include "stb_image.c"
typedef unsigned int uint32;
JNIEXPORT jobject JNICALL Java_com_jme3_texture_plugins_AndroidNativeImageLoader_getFailureReason
(JNIEnv * env, jclass clazz)
{
return stbi_failure_reason();
}
JNIEXPORT jint JNICALL Java_com_jme3_texture_plugins_AndroidNativeImageLoader_getImageInfo
(JNIEnv * env, jclass clazz, jobject inBuffer, jint bufSize, jobject outBuffer, jint outSize)
{
stbi_uc* pInBuffer = (stbi_uc*) (*env)->GetDirectBufferAddress(env, inBuffer);
stbi_uc* pOutBuffer = (stbi_uc*) (*env)->GetDirectBufferAddress(env, outBuffer);
uint32 width, height, comp;
uint32 result = stbi_info_from_memory(pInBuffer, bufSize, &width, &height, &comp);
if (result == 1) {
uint32 numBytes = (width) * (height) * (comp);
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "getImageInfo width: %d", width);
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "getImageInfo height: %d", height);
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "getImageInfo comp: %d", comp);
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "getImageInfo data size: %d", numBytes);
// each element is a 4 byte int
if (outSize != 12) {
return 2;
}
memcpy(pOutBuffer+0, &width, 4);
memcpy(pOutBuffer+4, &height, 4);
memcpy(pOutBuffer+8, &comp, 4);
return (jint) 0;
}
return 1;
}
JNIEXPORT jint JNICALL Java_com_jme3_texture_plugins_AndroidNativeImageLoader_decodeBuffer
(JNIEnv * env, jclass clazz, jobject inBuffer, jint inSize, jboolean flipY, jobject outBuffer, jint outSize)
{
stbi_uc* pInBuffer = (stbi_uc*) (*env)->GetDirectBufferAddress(env, inBuffer);
stbi_uc* pOutBuffer = (stbi_uc*) (*env)->GetDirectBufferAddress(env, outBuffer);
uint32 width, height, comp;
uint32 req_comp = 0;
stbi_uc* pData = stbi_load_from_memory(pInBuffer, inSize, &width, &height, &comp, req_comp);
if(pData == NULL) {
return 1;
}
uint32 numBytes = width * height * comp;
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "decodeBuffer width: %d", width);
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "decodeBuffer height: %d", height);
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "decodeBuffer comp: %d", comp);
__android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "decodeBuffer data size: %d", numBytes);
if (numBytes != outSize) {
return 2;
}
int i;
// for (i=0; i<outSize; i+=4) {
// __android_log_print(ANDROID_LOG_INFO, "NativeImageLoader",
// "pData byte[%d] r: %02x, g: %02x, b: %02x, a: %02x",
// i, *(pData+i), *(pData+i+1), *(pData+i+2), *(pData+i+3));
// }
if (!flipY) {
memcpy(pOutBuffer, pData, outSize);
stbi_image_free(pData);
return 0;
} else {
uint32 yNew = 0;
uint32 yOrig = 0;
// stb_image always outputs in bpp = 8
uint32 bytesPerLine = (width * comp);
stbi_uc* newData = (stbi_uc *) malloc(bytesPerLine * height);
if (newData == NULL) {
stbi_image_free(pData);
return 3;
}
for (yOrig = 0; yOrig < height; yOrig++){
yNew = height - yOrig - 1;
// __android_log_print(ANDROID_LOG_INFO, "NativeImageLoader", "yOrig: %d, yNew: %d, bytes: %d", yOrig, yNew, bytesPerLine);
memcpy(newData + (yNew * bytesPerLine), pData + (yOrig * bytesPerLine), bytesPerLine);
}
// for (i=0; i<outSize; i+=4) {
// __android_log_print(ANDROID_LOG_INFO, "NativeImageLoader",
// "newData byte[%d] r: %02x, g: %02x, b: %02x, a: %02x",
// i, *(newData+i), *(newData+i+1), *(newData+i+2), *(newData+i+3));
// }
memcpy(pOutBuffer, newData, outSize);
// for (i=0; i<outSize; i+=4) {
// __android_log_print(ANDROID_LOG_INFO, "NativeImageLoader",
// "pOutBuffer byte[%d] r: %02x, g: %02x, b: %02x, a: %02x",
// i, *(pOutBuffer+i), *(pOutBuffer+i+1), *(pOutBuffer+i+2), *(pOutBuffer+i+3));
// }
stbi_image_free(pData);
free(newData);
return 0;
}
return 0;
// stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
}

@ -0,0 +1,66 @@
// stb_image is not downloaded. The single source file is included in the repo
String stbiFolder = 'stb_image'
//Working directory for the ndk build.
//Must be the parent directory of the jni directory
//Libs directory (output of ndk) will be created in this directory as well
String stbiBuildDir = "${buildDir}" + File.separator + 'stb_image'
// jME Android Native source files path
String stbiJmeAndroidPath = 'src/native/jme_stbi'
// Copy stb_image files to jni directory
task copyStbiFiles(type: Copy) {
def sourceDir = file(stbiFolder)
def outputDir = file(stbiBuildDir + File.separator + 'jni')
// println "copyStbiFiles sourceDir: " + sourceDir
// println "copyStbiFiles outputDir: " + outputDir
from sourceDir
into outputDir
}
// Copy jME Android native files to jni directory
task copyStbiJmeFiles(type: Copy, dependsOn:copyStbiFiles) {
def sourceDir = file(stbiJmeAndroidPath)
def outputDir = file(stbiBuildDir + File.separator + 'jni')
// println "copyStbiJmeFiles sourceDir: " + sourceDir
// println "copyStbiJmeFiles outputDir: " + outputDir
from sourceDir
into outputDir
}
jar.into("lib") { from stbiBuildDir + File.separator + 'libs' }
task generateStbiHeaders(dependsOn:copyStbiJmeFiles) {
String destDir = stbiBuildDir + File.separator + 'jni'
String classes = ""
.concat("com.jme3.texture.plugins.AndroidNativeImageLoader, ")
// println "stb_image classes = " + classes
// println "stb_image destDir = " + destDir
// println "stb_image classpath = " + project.projectClassPath
ant.javah(
classpath: project.projectClassPath,
destdir: destDir,
class: classes
)
}
task buildStbiNativeLib(type: Exec, dependsOn: generateStbiHeaders) {
// println "stb_image build dir: " + buildLibDir
// println "ndkCommandPath: " + project.ndkCommandPath
args 'TARGET_PLATFORM=android-9'
workingDir stbiBuildDir
executable project.ndkCommandPath
}
compileJava.dependsOn {
// ndkPath is defined in the root project gradle.properties file
if (ndkCommandPath != null && new File(ndkCommandPath).exists()) {
buildStbiNativeLib
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,163 @@
package com.jme3.texture.plugins;
import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetLoadException;
import com.jme3.asset.AssetLoader;
import com.jme3.asset.TextureKey;
import com.jme3.texture.Image;
import com.jme3.util.BufferUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Native image loader to deal with filetypes that support alpha channels.
* The Android Bitmap class premultiplies the channels by the alpha when
* loading. This loader does not.
*
* @author iwgeric
*/
public class AndroidNativeImageLoader implements AssetLoader {
private static final Logger logger = Logger.getLogger(AndroidNativeImageLoader.class.getName());
public Image load(InputStream in, boolean flipY) throws IOException{
int result;
byte[] bytes = getBytes(in);
int origSize = bytes.length;
// logger.log(Level.INFO, "png file length: {0}", size);
ByteBuffer origDataBuffer = BufferUtils.createByteBuffer(origSize);
origDataBuffer.clear();
origDataBuffer.put(bytes, 0, origSize);
origDataBuffer.flip();
int headerSize = 12;
ByteBuffer headerDataBuffer = BufferUtils.createByteBuffer(headerSize);
headerDataBuffer.asIntBuffer();
headerDataBuffer.clear();
result = getImageInfo(origDataBuffer, origSize, headerDataBuffer, headerSize);
if (result != 0) {
logger.log(Level.SEVERE, "Image header could not be read: {0}", getFailureReason());
return null;
}
headerDataBuffer.rewind();
// logger.log(Level.INFO, "image header size: {0}", headerDataBuffer.capacity());
// int position = 0;
// while (headerDataBuffer.position() < headerDataBuffer.capacity()) {
// int value = headerDataBuffer.getInt();
// logger.log(Level.INFO, "position: {0}, value: {1}",
// new Object[]{position, value});
// position++;
// }
// headerDataBuffer.rewind();
int width = headerDataBuffer.getInt();
int height = headerDataBuffer.getInt();
int numComponents = headerDataBuffer.getInt();
int imageDataSize = width * height * numComponents;
// logger.log(Level.INFO, "width: {0}, height: {1}, numComponents: {2}, imageDataSize: {3}",
// new Object[]{width, height, numComponents, imageDataSize});
ByteBuffer imageDataBuffer = BufferUtils.createByteBuffer(imageDataSize);
imageDataBuffer.clear();
result = decodeBuffer(origDataBuffer, origSize, flipY, imageDataBuffer, imageDataSize);
if (result != 0) {
logger.log(Level.SEVERE, "Image could not be decoded: {0}", getFailureReason());
return null;
}
imageDataBuffer.rewind();
// logger.log(Level.INFO, "png outSize: {0}", imageDataBuffer.capacity());
// int pixelNum = 0;
// while (imageDataBuffer.position() < imageDataBuffer.capacity()) {
// short r = (short) (imageDataBuffer.get() & 0xFF);
// short g = (short) (imageDataBuffer.get() & 0xFF);
// short b = (short) (imageDataBuffer.get() & 0xFF);
// short a = (short) (imageDataBuffer.get() & 0xFF);
// logger.log(Level.INFO, "pixel: {0}, r: {1}, g: {2}, b: {3}, a: {4}",
// new Object[]{pixelNum, r, g, b, a});
// pixelNum++;
// }
// imageDataBuffer.rewind();
BufferUtils.destroyDirectBuffer(origDataBuffer);
BufferUtils.destroyDirectBuffer(headerDataBuffer);
Image img = new Image(getImageFormat(numComponents), width, height, imageDataBuffer);
return img;
}
public Image load(AssetInfo info) throws IOException {
// logger.log(Level.INFO, "Loading texture: {0}", ((TextureKey)info.getKey()).toString());
boolean flip = ((TextureKey) info.getKey()).isFlipY();
InputStream in = null;
try {
in = info.openStream();
Image img = load(in, flip);
if (img == null){
throw new AssetLoadException("The given image cannot be loaded " + info.getKey());
}
return img;
} finally {
if (in != null){
in.close();
}
}
}
private static Image.Format getImageFormat(int stbiNumComponents) {
// stb_image always returns 8 bit components
// N=#comp components
// 1 grey
// 2 grey, alpha
// 3 red, green, blue
// 4 red, green, blue, alpha
Image.Format format = null;
if (stbiNumComponents == 1) {
format = Image.Format.Luminance8;
} else if (stbiNumComponents == 2) {
format = Image.Format.Luminance8Alpha8;
} else if (stbiNumComponents == 3) {
format = Image.Format.RGB8;
} else if (stbiNumComponents == 4) {
format = Image.Format.RGBA8;
} else {
throw new IllegalArgumentException("Format returned by stbi is not valid. Returned value: " + stbiNumComponents);
}
return format;
}
public static byte[] getBytes(InputStream input) throws IOException {
byte[] buffer = new byte[32768];
int bytesRead;
ByteArrayOutputStream os = new ByteArrayOutputStream();
while ((bytesRead = input.read(buffer)) != -1)
{
os.write(buffer, 0, bytesRead);
}
byte[] output = os.toByteArray();
return output;
}
/** Load jni .so on initialization */
static {
System.loadLibrary("stbijme");
}
private static native int getImageInfo(ByteBuffer inBuffer, int inSize, ByteBuffer outBuffer, int outSize);
private static native int decodeBuffer(ByteBuffer inBuffer, int inSize, boolean flipY, ByteBuffer outBuffer, int outSize);
private static native String getFailureReason();
}
Loading…
Cancel
Save