From db81b925d776103326128bf629cbdda576a223e7 Mon Sep 17 00:00:00 2001
From: sanine <sanine.not@pm.me>
Date: Sat, 16 Apr 2022 11:55:09 -0500
Subject: move 3rd-party librarys into libs/ and add built-in honeysuckle

---
 .../port/jassimp/jassimp-native/src/jassimp.cpp    | 1995 ++++++++++++++++++++
 .../port/jassimp/jassimp-native/src/jassimp.h      |   47 +
 2 files changed, 2042 insertions(+)
 create mode 100644 libs/assimp/port/jassimp/jassimp-native/src/jassimp.cpp
 create mode 100644 libs/assimp/port/jassimp/jassimp-native/src/jassimp.h

(limited to 'libs/assimp/port/jassimp/jassimp-native/src')

diff --git a/libs/assimp/port/jassimp/jassimp-native/src/jassimp.cpp b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.cpp
new file mode 100644
index 0000000..6661ce9
--- /dev/null
+++ b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.cpp
@@ -0,0 +1,1995 @@
+#include "jassimp.h"
+
+#include <assimp/Importer.hpp>
+#include <assimp/ProgressHandler.hpp>
+#include <assimp/scene.h>
+#include <assimp/IOStream.hpp>
+#include <assimp/IOSystem.hpp>
+
+
+#ifdef JNI_LOG
+#ifdef ANDROID
+#include <android/log.h>
+#define lprintf(...) __android_log_print(ANDROID_LOG_VERBOSE, __func__, __VA_ARGS__)
+#else
+#define lprintf(...) printf (__VA_ARGS__)
+#endif /* ANDROID */
+#else
+#define lprintf
+#endif
+
+static std::string gLastErrorString;
+
+// Automatically deletes a local ref when it goes out of scope
+class SmartLocalRef {
+private:
+    JNIEnv* mJniEnv;
+    jobject& mJavaObj;
+    SmartLocalRef(const SmartLocalRef&); // non construction-copyable
+    SmartLocalRef& operator=(const SmartLocalRef&); // non copyable
+
+public:
+    template<class T> SmartLocalRef(JNIEnv* env, T& object)
+    : mJniEnv(env)
+    , mJavaObj((jobject&)object)
+    {
+    };
+
+    ~SmartLocalRef() {
+        if (mJavaObj != NULL) {
+            mJniEnv->DeleteLocalRef(mJavaObj);
+        }
+    }
+};
+
+static bool createInstance(JNIEnv *env, const char* className, jobject& newInstance)
+{
+	jclass clazz = env->FindClass(className);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", className);
+		return false;
+	}
+
+	jmethodID ctr_id = env->GetMethodID(clazz, "<init>", "()V");
+
+	if (NULL == ctr_id)
+	{
+		lprintf("could not find no-arg constructor for class %s\n", className);
+		return false;
+	}
+
+	newInstance = env->NewObject(clazz, ctr_id);
+
+	if (NULL == newInstance)
+	{
+		lprintf("error calling no-arg constructor for class %s\n", className);
+		return false;
+	}
+
+	return true;
+}
+
+
+static bool createInstance(JNIEnv *env, const char* className, const char* signature,/* const*/ jvalue* params, jobject& newInstance)
+{
+	jclass clazz = env->FindClass(className);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", className);
+		return false;
+	}
+
+	jmethodID ctr_id = env->GetMethodID(clazz, "<init>", signature);
+
+	if (NULL == ctr_id)
+	{
+		lprintf("could not find no-arg constructor for class %s\n", className);
+		return false;
+	}
+
+	newInstance = env->NewObjectA(clazz, ctr_id, params);
+
+	if (NULL == newInstance)
+	{
+		lprintf("error calling  constructor for class %s, signature %s\n", className, signature);
+		return false;
+	}
+
+	return true;
+}
+
+
+static bool getField(JNIEnv *env, jobject object, const char* fieldName, const char* signature, jobject& field)
+{
+	jclass clazz = env->GetObjectClass(object);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not get class for object\n");
+		return false;
+	}
+
+	jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature);
+
+	if (NULL == fieldId)
+	{
+		lprintf("could not get field %s with signature %s\n", fieldName, signature);
+		return false;
+	}
+
+	field = env->GetObjectField(object, fieldId);
+
+	return true;
+}
+
+
+static bool setIntField(JNIEnv *env, jobject object, const char* fieldName, jint value)
+{
+	jclass clazz = env->GetObjectClass(object);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not get class for object\n");
+		return false;
+	}
+
+	jfieldID fieldId = env->GetFieldID(clazz, fieldName, "I");
+
+	if (NULL == fieldId)
+	{
+		lprintf("could not get field %s with signature I\n", fieldName);
+		return false;
+	}
+
+	env->SetIntField(object, fieldId, value);
+
+	return true;
+}
+
+
+static bool setFloatField(JNIEnv *env, jobject object, const char* fieldName, jfloat value)
+{
+	jclass clazz = env->GetObjectClass(object);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not get class for object\n");
+		return false;
+	}
+
+	jfieldID fieldId = env->GetFieldID(clazz, fieldName, "F");
+
+	if (NULL == fieldId)
+	{
+		lprintf("could not get field %s with signature F\n", fieldName);
+		return false;
+	}
+
+	env->SetFloatField(object, fieldId, value);
+
+	return true;
+}
+
+
+static bool setObjectField(JNIEnv *env, jobject object, const char* fieldName, const char* signature, jobject value)
+{
+	jclass clazz = env->GetObjectClass(object);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not get class for object\n");
+		return false;
+	}
+
+	jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature);
+
+	if (NULL == fieldId)
+	{
+		lprintf("could not get field %s with signature %s\n", fieldName, signature);
+		return false;
+	}
+
+	env->SetObjectField(object, fieldId, value);
+
+	return true;
+}
+
+
+static bool getStaticField(JNIEnv *env, const char* className, const char* fieldName, const char* signature, jobject& field)
+{
+	jclass clazz = env->FindClass(className);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", className);
+		return false;
+	}
+
+	jfieldID fieldId = env->GetStaticFieldID(clazz, fieldName, signature);
+
+	if (NULL == fieldId)
+	{
+		lprintf("could not get field %s with signature %s\n", fieldName, signature);
+		return false;
+	}
+
+	field = env->GetStaticObjectField(clazz, fieldId);
+
+	return true;
+}
+
+
+static bool call(JNIEnv *env, jobject object, const char* typeName, const char* methodName,
+	const char* signature,/* const*/ jvalue* params)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
+	jboolean jReturnValue = env->CallBooleanMethodA(object, mid, params);
+
+	return (bool)jReturnValue;
+}
+static bool callv(JNIEnv *env, jobject object, const char* typeName,
+		const char* methodName, const char* signature,/* const*/ jvalue* params) {
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz) {
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid) {
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
+	env->CallVoidMethodA(object, mid, params);
+
+	return true;
+}
+
+static jobject callo(JNIEnv *env, jobject object, const char* typeName, const char* methodName,
+	const char* signature,/* const*/ jvalue* params)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return NULL;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return NULL;
+	}
+
+	jobject jReturnValue = env->CallObjectMethodA(object, mid, params);
+
+	return jReturnValue;
+}
+
+static int calli(JNIEnv *env, jobject object, const char* typeName, const char* methodName,
+	const char* signature)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
+	jint jReturnValue = env->CallIntMethod(object, mid);
+
+	return (int) jReturnValue;
+}
+
+static int callc(JNIEnv *env, jobject object, const char* typeName, const char* methodName,
+	const char* signature)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
+	jint jReturnValue = env->CallCharMethod(object, mid);
+
+	return (int) jReturnValue;
+}
+
+
+static bool callStaticObject(JNIEnv *env, const char* typeName, const char* methodName,
+	const char* signature,/* const*/ jvalue* params, jobject& returnValue)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetStaticMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
+	returnValue = env->CallStaticObjectMethodA(clazz, mid, params);
+
+	return true;
+}
+
+
+static bool copyBuffer(JNIEnv *env, jobject jMesh, const char* jBufferName, void* cData, size_t size)
+{
+	jobject jBuffer = NULL;
+	SmartLocalRef bufferRef(env, jBuffer);
+
+	if (!getField(env, jMesh, jBufferName, "Ljava/nio/ByteBuffer;", jBuffer))
+	{
+		return false;
+	}
+
+	if (env->GetDirectBufferCapacity(jBuffer) != size)
+	{
+		lprintf("invalid direct buffer, expected %u, got %llu\n", size, env->GetDirectBufferCapacity(jBuffer));
+		return false;
+	}
+
+	void* jBufferPtr = env->GetDirectBufferAddress(jBuffer);
+
+	if (NULL == jBufferPtr)
+	{
+		lprintf("could not access direct buffer\n");
+		return false;
+	}
+
+	memcpy(jBufferPtr, cData, size);
+
+	return true;
+}
+
+
+static bool copyBufferArray(JNIEnv *env, jobject jMesh, const char* jBufferName, int index, void* cData, size_t size)
+{
+	jobject jBufferArray = NULL;
+	SmartLocalRef bufferArrayRef(env, jBufferArray);
+
+	if (!getField(env, jMesh, jBufferName, "[Ljava/nio/ByteBuffer;", jBufferArray))
+	{
+		return false;
+	}
+
+	jobject jBuffer = env->GetObjectArrayElement((jobjectArray) jBufferArray, index);
+	SmartLocalRef bufferRef(env, jBuffer);
+
+	if (env->GetDirectBufferCapacity(jBuffer) != size)
+	{
+		lprintf("invalid direct buffer, expected %u, got %llu\n", size, env->GetDirectBufferCapacity(jBuffer));
+		return false;
+	}
+
+	void* jBufferPtr = env->GetDirectBufferAddress(jBuffer);
+
+	if (NULL == jBufferPtr)
+	{
+		lprintf("could not access direct buffer\n");
+		return false;
+	}
+
+	memcpy(jBufferPtr, cData, size);
+
+	return true;
+}
+
+class JavaIOStream : public Assimp::IOStream
+{
+private:
+	size_t pos;
+	size_t size;
+	char* buffer;
+	jobject jIOStream;
+
+
+public:
+	JavaIOStream(size_t size, char* buffer, jobject jIOStream) :
+	pos(0),
+	size(size),
+	buffer(buffer),
+	jIOStream(jIOStream)
+	{};
+
+
+    ~JavaIOStream(void)
+    {
+    	free(buffer);
+    };
+
+    size_t Read(void* pvBuffer, size_t pSize, size_t pCount)
+    {
+    	const size_t cnt = std::min(pCount,(size - pos)/pSize);
+		const size_t ofs = pSize*cnt;
+
+	    memcpy(pvBuffer, buffer + pos, ofs);
+	    pos += ofs;
+
+	    return cnt;
+    };
+    size_t Write(const void* pvBuffer, size_t pSize, size_t pCount)
+    {
+        return 0;
+    };
+
+    aiReturn Seek(size_t pOffset, aiOrigin pOrigin)
+    {
+	    if (aiOrigin_SET == pOrigin) {
+	        if (pOffset >= size) {
+	            return AI_FAILURE;
+	        }
+	        pos = pOffset;
+	    }
+	    else if (aiOrigin_END == pOrigin) {
+	        if (pOffset >= size) {
+	            return AI_FAILURE;
+	        }
+	        pos = size-pOffset;
+	    }
+	    else {
+	        if (pOffset + pos >= size) {
+	            return AI_FAILURE;
+	        }
+	        pos += pOffset;
+	    }
+	    return AI_SUCCESS;
+    };
+
+    size_t Tell(void) const
+    {
+    	return pos;
+    };
+
+    size_t FileSize() const
+    {
+    	return size;
+    };
+
+    void Flush() {};
+
+
+    jobject javaObject()
+    {
+    	return jIOStream;
+    };
+
+
+};
+
+
+class JavaIOSystem : public Assimp::IOSystem {
+	private:
+    JNIEnv* mJniEnv;
+	jobject& mJavaIOSystem;
+
+	public:
+	JavaIOSystem(JNIEnv* env, jobject& javaIOSystem) :
+		mJniEnv(env),
+		mJavaIOSystem(javaIOSystem)
+	{};
+
+    bool Exists( const char* pFile) const
+    {
+    	jvalue params[1];
+		params[0].l = mJniEnv->NewStringUTF(pFile);
+	    return call(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "exists", "(Ljava/lang/String;)Z", params);
+
+    };
+    char getOsSeparator() const
+    {
+	    return (char) callc(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "getOsSeparator", "()C");
+    };
+
+    Assimp::IOStream* Open(const char* pFile,const char* pMode = "rb")
+    {
+        jvalue params[2];
+		params[0].l = mJniEnv->NewStringUTF(pFile);
+		params[1].l = mJniEnv->NewStringUTF(pMode);
+
+
+	    jobject jStream = callo(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "open", "(Ljava/lang/String;Ljava/lang/String;)Ljassimp/AiIOStream;", params);
+	    if(NULL == jStream)
+	    {
+	    	lprintf("NULL object from AiIOSystem.open\n");
+	    	return NULL;
+	    }
+	
+	    size_t size = calli(mJniEnv, jStream, "jassimp/AiIOStream", "getFileSize", "()I");
+	    lprintf("Model file size is %d\n", size);
+	
+	    char* buffer = (char*)malloc(size);
+	    jobject javaBuffer = mJniEnv->NewDirectByteBuffer(buffer, size);
+	
+	    jvalue readParams[1];
+	    readParams[0].l = javaBuffer;
+	    if(call(mJniEnv, jStream, "jassimp/AiIOStream", "read", "(Ljava/nio/ByteBuffer;)Z", readParams))
+	    {
+	    	return new JavaIOStream(size, buffer, jStream);
+		}
+		else
+		{
+			lprintf("Read failure on AiIOStream.read");
+			free(buffer);
+			return NULL;
+		}
+
+    };
+    void Close( Assimp::IOStream* pFile)
+    {
+
+		jvalue params[1];
+		params[0].l = ((JavaIOStream*) pFile)->javaObject();
+		callv(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "close", "(Ljassimp/AiIOStream;)V", params);
+    	delete pFile;
+    };
+
+
+
+};
+
+class JavaProgressHandler : public Assimp::ProgressHandler {
+	private:
+    JNIEnv* mJniEnv;
+	jobject& mJavaProgressHandler;
+
+	public:
+	JavaProgressHandler(JNIEnv* env, jobject& javaProgressHandler) :
+		mJniEnv(env),
+		mJavaProgressHandler(javaProgressHandler)
+	{};
+
+    bool Update(float percentage)
+    {
+    	jvalue params[1];
+		params[0].f = percentage;
+	    return call(mJniEnv, mJavaProgressHandler, "jassimp/AiProgressHandler", "update", "(F)Z", params);
+    }
+};
+
+static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
+{
+	for (unsigned int meshNr = 0; meshNr < cScene->mNumMeshes; meshNr++)
+	{
+		const aiMesh *cMesh = cScene->mMeshes[meshNr];
+
+		lprintf("converting mesh %s ...\n", cMesh->mName.C_Str());
+
+		/* create mesh */
+		jobject jMesh = NULL;
+		SmartLocalRef refMesh(env, jMesh);
+
+		if (!createInstance(env, "jassimp/AiMesh", jMesh))
+		{
+			return false;
+		}
+
+
+		/* add mesh to m_meshes java.util.List */
+		jobject jMeshes = NULL;
+		SmartLocalRef refMeshes(env, jMeshes);
+
+		if (!getField(env, jScene, "m_meshes", "Ljava/util/List;", jMeshes))
+		{
+			return false;
+		}
+
+		jvalue addParams[1];
+		addParams[0].l = jMesh;
+		if (!call(env, jMeshes, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams))
+		{
+			return false;
+		}
+
+
+		/* set general mesh data in java */
+		jvalue setTypesParams[1];
+		setTypesParams[0].i = cMesh->mPrimitiveTypes;
+		if (!callv(env, jMesh, "jassimp/AiMesh", "setPrimitiveTypes", "(I)V", setTypesParams))
+		{
+			return false;
+		}
+
+
+		if (!setIntField(env, jMesh, "m_materialIndex", cMesh->mMaterialIndex))
+		{
+			return false;
+		}
+
+		jstring nameString = env->NewStringUTF(cMesh->mName.C_Str());
+		SmartLocalRef refNameString(env, nameString);
+		if (!setObjectField(env, jMesh, "m_name", "Ljava/lang/String;", nameString))
+		{
+			return false;
+		}
+
+
+		/* determine face buffer size */
+		bool isPureTriangle = cMesh->mPrimitiveTypes == aiPrimitiveType_TRIANGLE;
+		size_t faceBufferSize;
+		if (isPureTriangle)
+		{
+			faceBufferSize = cMesh->mNumFaces * 3 * sizeof(unsigned int);
+		}
+		else
+		{
+			int numVertexReferences = 0;
+			for (unsigned int face = 0; face < cMesh->mNumFaces; face++)
+			{
+				numVertexReferences += cMesh->mFaces[face].mNumIndices;
+			}
+
+			faceBufferSize = numVertexReferences * sizeof(unsigned int);
+		}
+
+
+		/* allocate buffers - we do this from java so they can be garbage collected */
+		jvalue allocateBuffersParams[4];
+		allocateBuffersParams[0].i = cMesh->mNumVertices;
+		allocateBuffersParams[1].i = cMesh->mNumFaces;
+		allocateBuffersParams[2].z = isPureTriangle;
+		allocateBuffersParams[3].i = (jint) faceBufferSize;
+		if (!callv(env, jMesh, "jassimp/AiMesh", "allocateBuffers", "(IIZI)V", allocateBuffersParams))
+		{
+			return false;
+		}
+
+
+		if (cMesh->mNumVertices > 0)
+		{
+			/* push vertex data to java */
+			if (!copyBuffer(env, jMesh, "m_vertices", cMesh->mVertices, cMesh->mNumVertices * sizeof(aiVector3D)))
+			{
+				lprintf("could not copy vertex data\n");
+				return false;
+			}
+
+			lprintf("    with %u vertices\n", cMesh->mNumVertices);
+		}
+
+
+		/* push face data to java */
+		if (cMesh->mNumFaces > 0)
+		{
+			if (isPureTriangle)
+			{
+				char* faceBuffer = (char*) malloc(faceBufferSize);
+
+				size_t faceDataSize = 3 * sizeof(unsigned int);
+				for (unsigned int face = 0; face < cMesh->mNumFaces; face++)
+				{
+					memcpy(faceBuffer + face * faceDataSize, cMesh->mFaces[face].mIndices, faceDataSize);
+				}
+
+				bool res = copyBuffer(env, jMesh, "m_faces", faceBuffer, faceBufferSize);
+
+				free(faceBuffer);
+
+				if (!res)
+				{
+					lprintf("could not copy face data\n");
+					return false;
+				}
+			}
+			else
+			{
+				char* faceBuffer = (char*) malloc(faceBufferSize);
+				char* offsetBuffer = (char*) malloc(cMesh->mNumFaces * sizeof(unsigned int));
+
+				size_t faceBufferPos = 0;
+				for (unsigned int face = 0; face < cMesh->mNumFaces; face++)
+				{
+					size_t faceBufferOffset = faceBufferPos / sizeof(unsigned int);
+					memcpy(offsetBuffer + face * sizeof(unsigned int), &faceBufferOffset, sizeof(unsigned int));
+
+					size_t faceDataSize = cMesh->mFaces[face].mNumIndices * sizeof(unsigned int);
+					memcpy(faceBuffer + faceBufferPos, cMesh->mFaces[face].mIndices, faceDataSize);
+					faceBufferPos += faceDataSize;
+				}
+
+				if (faceBufferPos != faceBufferSize)
+				{
+					/* this should really not happen */
+					lprintf("faceBufferPos %u, faceBufferSize %u\n", faceBufferPos, faceBufferSize);
+					env->FatalError("error copying face data");
+					exit(-1);
+				}
+
+
+				bool res = copyBuffer(env, jMesh, "m_faces", faceBuffer, faceBufferSize);
+				res &= copyBuffer(env, jMesh, "m_faceOffsets", offsetBuffer, cMesh->mNumFaces * sizeof(unsigned int));
+
+				free(faceBuffer);
+				free(offsetBuffer);
+
+				if (!res)
+				{
+					lprintf("could not copy face data\n");
+					return false;
+				}
+			}
+
+			lprintf("    with %u faces\n", cMesh->mNumFaces);
+		}
+
+
+		/* push normals to java */
+		if (cMesh->HasNormals())
+		{
+			jvalue allocateDataChannelParams[2];
+			allocateDataChannelParams[0].i = 0;
+			allocateDataChannelParams[1].i = 0;
+			if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+			{
+				lprintf("could not allocate normal data channel\n");
+				return false;
+			}
+			if (!copyBuffer(env, jMesh, "m_normals", cMesh->mNormals, cMesh->mNumVertices * 3 * sizeof(float)))
+			{
+				lprintf("could not copy normal data\n");
+				return false;
+			}
+
+			lprintf("    with normals\n");
+		}
+
+
+		/* push tangents to java */
+		if (cMesh->mTangents != NULL)
+		{
+			jvalue allocateDataChannelParams[2];
+			allocateDataChannelParams[0].i = 1;
+			allocateDataChannelParams[1].i = 0;
+			if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+			{
+				lprintf("could not allocate tangents data channel\n");
+				return false;
+			}
+			if (!copyBuffer(env, jMesh, "m_tangents", cMesh->mTangents, cMesh->mNumVertices * 3 * sizeof(float)))
+			{
+				lprintf("could not copy tangents data\n");
+				return false;
+			}
+
+			lprintf("    with tangents\n");
+		}
+
+
+		/* push bitangents to java */
+		if (cMesh->mBitangents != NULL)
+		{
+			jvalue allocateDataChannelParams[2];
+			allocateDataChannelParams[0].i = 2;
+			allocateDataChannelParams[1].i = 0;
+			if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+			{
+				lprintf("could not allocate bitangents data channel\n");
+				return false;
+			}
+			if (!copyBuffer(env, jMesh, "m_bitangents", cMesh->mBitangents, cMesh->mNumVertices * 3 * sizeof(float)))
+			{
+				lprintf("could not copy bitangents data\n");
+				return false;
+			}
+
+			lprintf("    with bitangents\n");
+		}
+
+
+		/* push color sets to java */
+		for (int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++)
+		{
+			if (cMesh->mColors[c] != NULL)
+			{
+				jvalue allocateDataChannelParams[2];
+				allocateDataChannelParams[0].i = 3;
+				allocateDataChannelParams[1].i = c;
+				if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+				{
+					lprintf("could not allocate colorset data channel\n");
+					return false;
+				}
+				if (!copyBufferArray(env, jMesh, "m_colorsets", c, cMesh->mColors[c], cMesh->mNumVertices * 4 * sizeof(float)))
+				{
+					lprintf("could not copy colorset data\n");
+					return false;
+				}
+
+				lprintf("    with colorset[%d]\n", c);
+			}
+		}
+
+
+		/* push tex coords to java */
+		for (int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++)
+		{
+			if (cMesh->mTextureCoords[c] != NULL)
+			{
+				jvalue allocateDataChannelParams[2];
+
+				switch (cMesh->mNumUVComponents[c])
+				{
+				case 1:
+					allocateDataChannelParams[0].i = 4;
+					break;
+				case 2:
+					allocateDataChannelParams[0].i = 5;
+					break;
+				case 3:
+					allocateDataChannelParams[0].i = 6;
+					break;
+				default:
+					return false;
+				}
+
+				allocateDataChannelParams[1].i = c;
+				if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+				{
+					lprintf("could not allocate texture coordinates data channel\n");
+					return false;
+				}
+
+				/* gather data */
+				size_t coordBufferSize = cMesh->mNumVertices * cMesh->mNumUVComponents[c] * sizeof(float);
+				char* coordBuffer = (char*) malloc(coordBufferSize);
+				size_t coordBufferOffset = 0;
+
+				for (unsigned int v = 0; v < cMesh->mNumVertices; v++)
+				{
+					memcpy(coordBuffer + coordBufferOffset, &cMesh->mTextureCoords[c][v], cMesh->mNumUVComponents[c] * sizeof(float));
+					coordBufferOffset += cMesh->mNumUVComponents[c] * sizeof(float);
+				}
+
+				if (coordBufferOffset != coordBufferSize)
+				{
+					/* this should really not happen */
+					lprintf("coordBufferPos %u, coordBufferSize %u\n", coordBufferOffset, coordBufferSize);
+					env->FatalError("error copying coord data");
+					exit(-1);
+				}
+
+				bool res = copyBufferArray(env, jMesh, "m_texcoords", c, coordBuffer, coordBufferSize);
+
+				free(coordBuffer);
+
+				if (!res)
+				{
+					lprintf("could not copy texture coordinates data\n");
+					return false;
+				}
+
+				lprintf("    with %uD texcoord[%d]\n", cMesh->mNumUVComponents[c], c);
+			}
+		}
+
+
+		for (unsigned int b = 0; b < cMesh->mNumBones; b++)
+		{
+			aiBone *cBone = cMesh->mBones[b];
+
+			jobject jBone;
+			SmartLocalRef refBone(env, jBone);
+			if (!createInstance(env, "jassimp/AiBone", jBone))
+			{
+				return false;
+			}
+
+			/* add bone to bone list */
+			jobject jBones = NULL;
+			SmartLocalRef refBones(env, jBones);
+			if (!getField(env, jMesh, "m_bones", "Ljava/util/List;", jBones))
+			{
+				return false;
+			}
+
+			jvalue addParams[1];
+			addParams[0].l = jBone;
+			if (!call(env, jBones, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams))
+			{
+				return false;
+			}
+
+			/* set bone data */
+			jstring boneNameString = env->NewStringUTF(cBone->mName.C_Str());
+			SmartLocalRef refNameString(env, boneNameString);
+			if (!setObjectField(env, jBone, "m_name", "Ljava/lang/String;", boneNameString))
+			{
+				return false;
+			}
+
+			/* add bone weights */
+			for (unsigned int w = 0; w < cBone->mNumWeights; w++)
+			{
+				jobject jBoneWeight;
+				SmartLocalRef refBoneWeight(env, jBoneWeight);
+				if (!createInstance(env, "jassimp/AiBoneWeight", jBoneWeight))
+				{
+					return false;
+				}
+
+				/* add boneweight to bone list */
+				jobject jBoneWeights = NULL;
+				SmartLocalRef refBoneWeights(env, jBoneWeights);
+				if (!getField(env, jBone, "m_boneWeights", "Ljava/util/List;", jBoneWeights))
+				{
+					return false;
+				}
+
+				/* copy offset matrix */
+				jfloatArray jMatrixArr = env->NewFloatArray(16);
+				SmartLocalRef refMatrixArr(env, jMatrixArr);
+				env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cBone->mOffsetMatrix);
+
+				jvalue wrapParams[1];
+				wrapParams[0].l = jMatrixArr;
+				jobject jMatrix;
+				SmartLocalRef refMatrix(env, jMatrix);
+
+				if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapParams, jMatrix))
+				{
+					return false;
+				}
+
+				if (!setObjectField(env, jBone, "m_offsetMatrix", "Ljava/lang/Object;", jMatrix))
+				{
+					return false;
+				}
+
+
+				jvalue addBwParams[1];
+				addBwParams[0].l = jBoneWeight;
+				if (!call(env, jBoneWeights, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addBwParams))
+				{
+					return false;
+				}
+
+
+				if (!setIntField(env, jBoneWeight, "m_vertexId", cBone->mWeights[w].mVertexId))
+				{
+					return false;
+				}
+
+				if (!setFloatField(env, jBoneWeight, "m_weight", cBone->mWeights[w].mWeight))
+				{
+					return false;
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+static bool loadMetadata(JNIEnv *env, const aiNode* cNode, jobject& jNode)
+{
+    aiMetadata *cMetadata = cNode->mMetaData;
+
+	for(unsigned i = 0; i<cMetadata->mNumProperties; i++) {
+
+        aiString& metaDataKey = cMetadata->mKeys[i];
+		void* cData = cMetadata->mValues[i].mData;
+		aiMetadataType cMetadataType = cMetadata->mValues[i].mType;
+
+		jobject jAiMetadataEntry = NULL;
+		SmartLocalRef refMetadataEntry(env, jAiMetadataEntry);
+
+		if(!createInstance(env, "jassimp/AiMetadataEntry", jAiMetadataEntry)) {
+			return false;
+		}
+
+		jobject jAiMetadataTypeEnumValue = NULL;
+		SmartLocalRef refMetadataTypeEnumValue(env, jAiMetadataTypeEnumValue);
+
+		jobject jMetadataData = NULL;
+		SmartLocalRef refMetadataData(env, jMetadataData);
+
+		bool getMetadataTypeSuccess = false;
+		bool getMetadataDataSuccess = false;
+
+		jvalue boxingMethodArgument[1];
+
+        jboolean exceptionThrown;
+
+		switch (cMetadataType) {
+
+			case AI_BOOL: {
+                getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_BOOL", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue);
+                boxingMethodArgument[0].z = (jboolean) *static_cast<bool*>(cData);
+                getMetadataDataSuccess = callStaticObject(env, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", boxingMethodArgument, jMetadataData);
+                break;
+            }
+            case AI_INT32: {
+                getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_INT32", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue);
+                boxingMethodArgument[0].i = (jint) *static_cast<int32_t*>(cData);
+                getMetadataDataSuccess = callStaticObject(env, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", boxingMethodArgument, jMetadataData);
+                break;
+            }
+            case AI_UINT64: {
+                getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_UINT64", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue);
+                boxingMethodArgument[0].j = (jlong) *static_cast<uint64_t*>(cData);
+                getMetadataDataSuccess = callStaticObject(env, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", boxingMethodArgument, jMetadataData);
+                break;
+            }
+            case AI_FLOAT: {
+                getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_FLOAT", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue);
+                boxingMethodArgument[0].f = (jfloat) *static_cast<float*>(cData);
+                getMetadataDataSuccess = callStaticObject(env, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", boxingMethodArgument, jMetadataData);
+                break;
+            }
+            case AI_DOUBLE: {
+                getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_DOUBLE", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue);
+                boxingMethodArgument[0].d = (jdouble) *static_cast<double*>(cData);
+                getMetadataDataSuccess = callStaticObject(env, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", boxingMethodArgument, jMetadataData);
+                break;
+            }
+            case AI_AISTRING: {
+                getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_AISTRING", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue);
+                jMetadataData = env->NewStringUTF(static_cast<aiString*>(cData)->C_Str());
+                getMetadataDataSuccess = (jMetadataData != NULL);
+                break;
+            }
+            case AI_AIVECTOR3D: {
+                getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_AIVECTOR3D",
+                                                        "Ljassimp/AiMetadataEntry$AiMetadataType;",
+                                                        jAiMetadataTypeEnumValue);
+                jvalue wrapVec3Args[3];
+                aiVector3D *vector3D = static_cast<aiVector3D *>(cData);
+                wrapVec3Args[0].f = vector3D->x;
+                wrapVec3Args[1].f = vector3D->y;
+                wrapVec3Args[2].f = vector3D->z;
+                getMetadataDataSuccess = callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;",
+                                                          wrapVec3Args, jMetadataData);
+                break;
+            }
+            default: {
+                getMetadataTypeSuccess = false;
+                getMetadataDataSuccess = false;
+                break;
+            }
+        }
+
+        exceptionThrown = env->ExceptionCheck();
+
+        if(!getMetadataTypeSuccess || !getMetadataDataSuccess) {
+            if(exceptionThrown)
+            {
+                env->ExceptionDescribe();
+            }
+
+            return false;
+        }
+
+        if(!setObjectField(env, jAiMetadataEntry, "mType", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue)) {
+            exceptionThrown = env->ExceptionCheck();
+
+            if(exceptionThrown)
+            {
+                env->ExceptionDescribe();
+            }
+
+            return false;
+        }
+
+        if(!setObjectField(env, jAiMetadataEntry, "mData", "Ljava/lang/Object;", jMetadataData)) {
+            exceptionThrown = env->ExceptionCheck();
+
+            if(exceptionThrown)
+            {
+                env->ExceptionDescribe();
+            }
+
+            return false;
+        }
+
+        jobject jNodeMetadata = NULL;
+        SmartLocalRef refMetadata(env, jNodeMetadata);
+
+        if(!getField(env, jNode, "m_metaData", "Ljava/util/Map;", jNodeMetadata)) {
+            exceptionThrown = env->ExceptionCheck();
+
+            if(exceptionThrown)
+            {
+                env->ExceptionDescribe();
+            }
+
+            return false;
+        }
+
+        jclass hashMapClass = env->FindClass("java/util/HashMap");
+        jmethodID jHashMapPutMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+        jstring jKey = env->NewStringUTF(metaDataKey.C_Str());
+        SmartLocalRef keyRef(env, jKey);
+
+        // Only check exception instead of result here because maps will return
+        // null on success if they did not overwrite an existing mapping for the given key.
+        env->CallObjectMethod(jNodeMetadata, jHashMapPutMethod, jKey, jAiMetadataEntry);
+
+        exceptionThrown = env->ExceptionCheck();
+
+        if(exceptionThrown) {
+            env->ExceptionDescribe();
+            return false;
+        }
+
+    }
+
+    return true;
+}
+
+static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobject* loadedNode = NULL)
+{
+	lprintf("   converting node %s ...\n", cNode->mName.C_Str());
+
+	/* wrap matrix */
+	jfloatArray jMatrixArr = env->NewFloatArray(16);
+	SmartLocalRef refMatrixArr(env, jMatrixArr);
+	env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cNode->mTransformation);
+
+	jvalue wrapMatParams[1];
+	wrapMatParams[0].l = jMatrixArr;
+	jobject jMatrix;
+	SmartLocalRef refMatrix(env, jMatrix);
+
+	if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapMatParams, jMatrix))
+	{
+		return false;
+	}
+
+
+	/* create mesh references array */
+	jintArray jMeshrefArr = env->NewIntArray(cNode->mNumMeshes);
+	SmartLocalRef refMeshrefArr(env, jMeshrefArr);
+
+	jint *temp = (jint*) malloc(sizeof(jint) * cNode->mNumMeshes);
+
+	for (unsigned int i = 0; i < cNode->mNumMeshes; i++)
+	{
+		temp[i] = cNode->mMeshes[i];
+	}
+	env->SetIntArrayRegion(jMeshrefArr, 0, cNode->mNumMeshes, (jint*) temp);
+
+	free(temp);
+
+
+	/* convert name */
+	jstring jNodeName = env->NewStringUTF(cNode->mName.C_Str());
+	SmartLocalRef refNodeName(env, jNodeName);
+
+	/* wrap scene node */
+	jvalue wrapNodeParams[4];
+	wrapNodeParams[0].l = parent;
+	wrapNodeParams[1].l = jMatrix;
+	wrapNodeParams[2].l = jMeshrefArr;
+	wrapNodeParams[3].l = jNodeName;
+	jobject jNode;
+	if (!callStaticObject(env, "jassimp/Jassimp", "wrapSceneNode",
+		"(Ljava/lang/Object;Ljava/lang/Object;[ILjava/lang/String;)Ljava/lang/Object;", wrapNodeParams, jNode))
+	{
+		return false;
+	}
+
+
+	/* and recurse */
+	for (unsigned int c = 0; c < cNode->mNumChildren; c++)
+	{
+		if (!loadSceneNode(env, cNode->mChildren[c], jNode))
+		{
+			return false;
+		}
+	}
+
+    if (NULL != loadedNode)
+    {
+        if(cNode->mMetaData) {
+            if(!loadMetadata(env, cNode, jNode))
+            {
+                return false;
+            }
+        }
+
+        *loadedNode = jNode;
+    } else {
+        env->DeleteLocalRef(jNode);
+    }
+
+	return true;
+}
+
+
+static bool loadSceneGraph(JNIEnv *env, const aiScene* cScene, jobject& jScene)
+{
+	lprintf("converting scene graph ...\n");
+
+	if (NULL != cScene->mRootNode)
+	{
+		jobject jRoot;
+		SmartLocalRef refRoot(env, jRoot);
+
+		if (!loadSceneNode(env, cScene->mRootNode, NULL, &jRoot))
+		{
+			return false;
+		}
+
+		if (!setObjectField(env, jScene, "m_sceneRoot", "Ljava/lang/Object;", jRoot))
+		{
+			return false;
+		}
+	}
+
+	lprintf("converting scene graph finished\n");
+
+	return true;
+}
+
+
+static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene)
+{
+	for (unsigned int m = 0; m < cScene->mNumMaterials; m++)
+	{
+		const aiMaterial* cMaterial = cScene->mMaterials[m];
+
+		lprintf("converting material %d ...\n", m);
+
+		jobject jMaterial = NULL;
+		SmartLocalRef refMaterial(env, jMaterial);
+
+		if (!createInstance(env, "jassimp/AiMaterial", jMaterial))
+		{
+			return false;
+		}
+
+		/* add material to m_materials java.util.List */
+		jobject jMaterials = NULL;
+		SmartLocalRef refMaterials(env, jMaterials);
+
+		if (!getField(env, jScene, "m_materials", "Ljava/util/List;", jMaterials))
+		{
+			return false;
+		}
+
+		jvalue addMatParams[1];
+		addMatParams[0].l = jMaterial;
+		if (!call(env, jMaterials, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addMatParams))
+		{
+			return false;
+		}
+
+		/* set texture numbers */
+		for (int ttInd = aiTextureType_DIFFUSE; ttInd < aiTextureType_UNKNOWN; ttInd++)
+		{
+			aiTextureType tt = static_cast<aiTextureType>(ttInd);
+
+			unsigned int num = cMaterial->GetTextureCount(tt);
+
+			lprintf("   found %d textures of type %d ...\n", num, ttInd);
+
+			jvalue setNumberParams[2];
+			setNumberParams[0].i = ttInd;
+			setNumberParams[1].i = num;
+
+			if (!callv(env, jMaterial, "jassimp/AiMaterial", "setTextureNumber", "(II)V", setNumberParams))
+			{
+				return false;
+			}
+		}
+
+
+		for (unsigned int p = 0; p < cMaterial->mNumProperties; p++)
+		{
+			//printf("%s - %u - %u\n", cScene->mMaterials[m]->mProperties[p]->mKey.C_Str(),
+			//	cScene->mMaterials[m]->mProperties[p]->mSemantic,
+			//	cScene->mMaterials[m]->mProperties[p]->mDataLength);
+
+			const aiMaterialProperty* cProperty = cMaterial->mProperties[p];
+
+			lprintf("   converting property %s ...\n", cProperty->mKey.C_Str());
+
+			jobject jProperty = NULL;
+			SmartLocalRef refProperty(env, jProperty);
+
+			jvalue constructorParams[5];
+			jstring keyString = env->NewStringUTF(cProperty->mKey.C_Str());
+			SmartLocalRef refKeyString(env, keyString);
+			constructorParams[0].l = keyString;
+			constructorParams[1].i = cProperty->mSemantic;
+			constructorParams[2].i = cProperty->mIndex;
+			constructorParams[3].i = cProperty->mType;
+
+
+			/* special case conversion for color3 */
+			if (NULL != strstr(cProperty->mKey.C_Str(), "clr") &&
+				cProperty->mType == aiPTI_Float &&
+				cProperty->mDataLength == 3 * sizeof(float))
+			{
+				jobject jData = NULL;
+				SmartLocalRef refData(env, jData);
+
+				/* wrap color */
+				jvalue wrapColorParams[3];
+				wrapColorParams[0].f = ((float*) cProperty->mData)[0];
+				wrapColorParams[1].f = ((float*) cProperty->mData)[1];
+				wrapColorParams[2].f = ((float*) cProperty->mData)[2];
+				if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jData))
+				{
+					return false;
+				}
+
+				constructorParams[4].l = jData;
+				if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V",
+					constructorParams, jProperty))
+				{
+					return false;
+				}
+			}
+			/* special case conversion for color4 */
+			else if (NULL != strstr(cProperty->mKey.C_Str(), "clr") &&
+				cProperty->mType == aiPTI_Float &&
+				cProperty->mDataLength == 4 * sizeof(float))
+			{
+				jobject jData = NULL;
+				SmartLocalRef refData(env, jData);
+
+				/* wrap color */
+				jvalue wrapColorParams[4];
+				wrapColorParams[0].f = ((float*) cProperty->mData)[0];
+				wrapColorParams[1].f = ((float*) cProperty->mData)[1];
+				wrapColorParams[2].f = ((float*) cProperty->mData)[2];
+				wrapColorParams[3].f = ((float*) cProperty->mData)[3];
+				if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor4", "(FFFF)Ljava/lang/Object;", wrapColorParams, jData))
+				{
+					return false;
+				}
+
+				constructorParams[4].l = jData;
+				if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V",
+					constructorParams, jProperty))
+				{
+					return false;
+				}
+			}
+			else if (cProperty->mType == aiPTI_Float && cProperty->mDataLength == sizeof(float))
+			{
+				jobject jData = NULL;
+				SmartLocalRef refData(env, jData);
+
+				jvalue newFloatParams[1];
+				newFloatParams[0].f = ((float*) cProperty->mData)[0];
+				if (!createInstance(env, "java/lang/Float", "(F)V", newFloatParams, jData))
+				{
+					return false;
+				}
+
+				constructorParams[4].l = jData;
+				if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V",
+					constructorParams, jProperty))
+				{
+					return false;
+				}
+			}
+			else if (cProperty->mType == aiPTI_Integer && cProperty->mDataLength == sizeof(int))
+			{
+				jobject jData = NULL;
+				SmartLocalRef refData(env, jData);
+
+				jvalue newIntParams[1];
+				newIntParams[0].i = ((int*) cProperty->mData)[0];
+				if (!createInstance(env, "java/lang/Integer", "(I)V", newIntParams, jData))
+				{
+					return false;
+				}
+
+				constructorParams[4].l = jData;
+				if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V",
+					constructorParams, jProperty))
+				{
+					return false;
+				}
+			}
+			else if (cProperty->mType == aiPTI_String)
+			{
+				/* skip length prefix */
+				jobject jData = env->NewStringUTF(cProperty->mData + 4);
+				SmartLocalRef refData(env, jData);
+
+				constructorParams[4].l = jData;
+				if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V",
+					constructorParams, jProperty))
+				{
+					return false;
+				}
+			}
+			else
+			{
+				constructorParams[4].i = cProperty->mDataLength;
+
+				/* generic copy code, uses dump ByteBuffer on java side */
+				if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIII)V", constructorParams, jProperty))
+				{
+					return false;
+				}
+
+				jobject jBuffer = NULL;
+				SmartLocalRef refBuffer(env, jBuffer);
+				if (!getField(env, jProperty, "m_data", "Ljava/lang/Object;", jBuffer))
+				{
+					return false;
+				}
+
+				if (env->GetDirectBufferCapacity(jBuffer) != cProperty->mDataLength)
+				{
+					lprintf("invalid direct buffer\n");
+					return false;
+				}
+
+				void* jBufferPtr = env->GetDirectBufferAddress(jBuffer);
+
+				if (NULL == jBufferPtr)
+				{
+					lprintf("could not access direct buffer\n");
+					return false;
+				}
+
+				memcpy(jBufferPtr, cProperty->mData, cProperty->mDataLength);
+			}
+
+
+			/* add property */
+			jobject jProperties = NULL;
+			SmartLocalRef refProperties(env, jProperties);
+			if (!getField(env, jMaterial, "m_properties", "Ljava/util/List;", jProperties))
+			{
+				return false;
+			}
+
+			jvalue addPropParams[1];
+			addPropParams[0].l = jProperty;
+			if (!call(env, jProperties, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addPropParams))
+			{
+				return false;
+			}
+		}
+	}
+
+	lprintf("materials finished\n");
+
+	return true;
+}
+
+
+static bool loadAnimations(JNIEnv *env, const aiScene* cScene, jobject& jScene)
+{
+	lprintf("converting %d animations ...\n", cScene->mNumAnimations);
+
+	for (unsigned int a = 0; a < cScene->mNumAnimations; a++)
+	{
+		const aiAnimation *cAnimation = cScene->mAnimations[a];
+
+		lprintf("   converting animation %s ...\n", cAnimation->mName.C_Str());
+
+		jobject jAnimation;
+		SmartLocalRef refAnimation(env, jAnimation);
+
+		jvalue newAnimParams[3];
+		jstring nameString = env->NewStringUTF(cAnimation->mName.C_Str());
+		SmartLocalRef refNameString(env, nameString);
+		newAnimParams[0].l = nameString;
+		newAnimParams[1].d = cAnimation->mDuration;
+		newAnimParams[2].d = cAnimation->mTicksPerSecond;
+
+		if (!createInstance(env, "jassimp/AiAnimation", "(Ljava/lang/String;DD)V", newAnimParams, jAnimation))
+		{
+			return false;
+		}
+
+		/* add animation to m_animations java.util.List */
+		jobject jAnimations = NULL;
+		SmartLocalRef refAnimations(env, jAnimations);
+
+		if (!getField(env, jScene, "m_animations", "Ljava/util/List;", jAnimations))
+		{
+			return false;
+		}
+
+		jvalue addParams[1];
+		addParams[0].l = jAnimation;
+		if (!call(env, jAnimations, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams))
+		{
+			return false;
+		}
+
+
+		for (unsigned int c = 0; c < cAnimation->mNumChannels; c++)
+		{
+			const aiNodeAnim *cNodeAnim = cAnimation->mChannels[c];
+
+			jobject jNodeAnim;
+			SmartLocalRef refNodeAnim(env, jNodeAnim);
+
+			jvalue newNodeAnimParams[6];
+			jstring animationName = env->NewStringUTF(cNodeAnim->mNodeName.C_Str());
+			SmartLocalRef refAnimationName(env, animationName);
+			newNodeAnimParams[0].l = animationName;
+			newNodeAnimParams[1].i = cNodeAnim->mNumPositionKeys;
+			newNodeAnimParams[2].i = cNodeAnim->mNumRotationKeys;
+			newNodeAnimParams[3].i = cNodeAnim->mNumScalingKeys;
+			newNodeAnimParams[4].i = cNodeAnim->mPreState;
+			newNodeAnimParams[5].i = cNodeAnim->mPostState;
+
+			if (!createInstance(env, "jassimp/AiNodeAnim", "(Ljava/lang/String;IIIII)V", newNodeAnimParams, jNodeAnim))
+			{
+				return false;
+			}
+
+
+			/* add nodeanim to m_animations java.util.List */
+			jobject jNodeAnims = NULL;
+			SmartLocalRef refNodeAnims(env, jNodeAnims);
+
+			if (!getField(env, jAnimation, "m_nodeAnims", "Ljava/util/List;", jNodeAnims))
+			{
+				return false;
+			}
+
+			jvalue addParams[1];
+			addParams[0].l = jNodeAnim;
+			if (!call(env, jNodeAnims, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams))
+			{
+				return false;
+			}
+
+			/* copy keys */
+			if (!copyBuffer(env, jNodeAnim, "m_posKeys", cNodeAnim->mPositionKeys,
+				cNodeAnim->mNumPositionKeys * sizeof(aiVectorKey)))
+			{
+				return false;
+			}
+
+			if (!copyBuffer(env, jNodeAnim, "m_rotKeys", cNodeAnim->mRotationKeys,
+				cNodeAnim->mNumRotationKeys * sizeof(aiQuatKey)))
+			{
+				return false;
+			}
+
+			if (!copyBuffer(env, jNodeAnim, "m_scaleKeys", cNodeAnim->mScalingKeys,
+				cNodeAnim->mNumScalingKeys * sizeof(aiVectorKey)))
+			{
+				return false;
+			}
+		}
+	}
+
+	lprintf("converting animations finished\n");
+
+	return true;
+}
+
+
+static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene)
+{
+	lprintf("converting %d lights ...\n", cScene->mNumLights);
+
+	for (unsigned int l = 0; l < cScene->mNumLights; l++)
+	{
+		const aiLight *cLight = cScene->mLights[l];
+
+		lprintf("converting light %s ...\n", cLight->mName.C_Str());
+
+		/* wrap color nodes */
+		jvalue wrapColorParams[3];
+		wrapColorParams[0].f = cLight->mColorDiffuse.r;
+		wrapColorParams[1].f = cLight->mColorDiffuse.g;
+		wrapColorParams[2].f = cLight->mColorDiffuse.b;
+		jobject jDiffuse;
+		SmartLocalRef refDiffuse(env, jDiffuse);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jDiffuse))
+		{
+			return false;
+		}
+
+		wrapColorParams[0].f = cLight->mColorSpecular.r;
+		wrapColorParams[1].f = cLight->mColorSpecular.g;
+		wrapColorParams[2].f = cLight->mColorSpecular.b;
+		jobject jSpecular;
+		SmartLocalRef refSpecular(env, jSpecular);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jSpecular))
+		{
+			return false;
+		}
+
+		wrapColorParams[0].f = cLight->mColorAmbient.r;
+		wrapColorParams[1].f = cLight->mColorAmbient.g;
+		wrapColorParams[2].f = cLight->mColorAmbient.b;
+		jobject jAmbient;
+		SmartLocalRef refAmbient(env, jAmbient);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jAmbient))
+		{
+			return false;
+		}
+
+
+		/* wrap vec3 nodes */
+		jvalue wrapVec3Params[3];
+		wrapVec3Params[0].f = cLight->mPosition.x;
+		wrapVec3Params[1].f = cLight->mPosition.y;
+		wrapVec3Params[2].f = cLight->mPosition.z;
+		jobject jPosition;
+		SmartLocalRef refPosition(env, jPosition);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jPosition))
+		{
+			return false;
+		}
+
+		wrapVec3Params[0].f = cLight->mPosition.x;
+		wrapVec3Params[1].f = cLight->mPosition.y;
+		wrapVec3Params[2].f = cLight->mPosition.z;
+		jobject jDirection;
+		SmartLocalRef refDirection(env, jDirection);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jDirection))
+		{
+			return false;
+		}
+
+
+		jobject jLight;
+		SmartLocalRef refLight(env, jLight);
+		jvalue params[12];
+		jstring lightName = env->NewStringUTF(cLight->mName.C_Str());
+		SmartLocalRef refLightName(env, lightName);
+		params[0].l = lightName;
+		params[1].i = cLight->mType;
+		params[2].l = jPosition;
+		params[3].l = jDirection;
+		params[4].f = cLight->mAttenuationConstant;
+		params[5].f = cLight->mAttenuationLinear;
+		params[6].f = cLight->mAttenuationQuadratic;
+		params[7].l = jDiffuse;
+		params[8].l = jSpecular;
+		params[9].l = jAmbient;
+		params[10].f = cLight->mAngleInnerCone;
+		params[11].f = cLight->mAngleOuterCone;
+
+		if (!createInstance(env, "jassimp/AiLight", "(Ljava/lang/String;ILjava/lang/Object;Ljava/lang/Object;FFFLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;FF)V",
+			params, jLight))
+		{
+			return false;
+		}
+
+		/* add light to m_lights java.util.List */
+		jobject jLights = NULL;
+		SmartLocalRef refLights(env, jLights);
+
+		if (!getField(env, jScene, "m_lights", "Ljava/util/List;", jLights))
+		{
+			return false;
+		}
+
+		jvalue addParams[1];
+		addParams[0].l = jLight;
+		if (!call(env, jLights, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams))
+		{
+			return false;
+		}
+	}
+
+	lprintf("converting lights finished ...\n");
+
+	return true;
+}
+
+
+static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene)
+{
+	lprintf("converting %d cameras ...\n", cScene->mNumCameras);
+
+	for (unsigned int c = 0; c < cScene->mNumCameras; c++)
+	{
+		const aiCamera *cCamera = cScene->mCameras[c];
+
+		lprintf("converting camera %s ...\n", cCamera->mName.C_Str());
+
+		/* wrap color nodes */
+		jvalue wrapPositionParams[3];
+		wrapPositionParams[0].f = cCamera->mPosition.x;
+		wrapPositionParams[1].f = cCamera->mPosition.y;
+		wrapPositionParams[2].f = cCamera->mPosition.z;
+		jobject jPosition;
+		SmartLocalRef refPosition(env, jPosition);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jPosition))
+		{
+			return false;
+		}
+
+		wrapPositionParams[0].f = cCamera->mUp.x;
+		wrapPositionParams[1].f = cCamera->mUp.y;
+		wrapPositionParams[2].f = cCamera->mUp.z;
+		jobject jUp;
+		SmartLocalRef refUp(env, jUp);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jUp))
+		{
+			return false;
+		}
+
+		wrapPositionParams[0].f = cCamera->mLookAt.x;
+		wrapPositionParams[1].f = cCamera->mLookAt.y;
+		wrapPositionParams[2].f = cCamera->mLookAt.z;
+		jobject jLookAt;
+		SmartLocalRef refLookAt(env, jLookAt);
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jLookAt))
+		{
+			return false;
+		}
+
+
+		jobject jCamera;
+		SmartLocalRef refCamera(env, jCamera);
+
+		jvalue params[8];
+		jstring cameraName = env->NewStringUTF(cCamera->mName.C_Str());
+		SmartLocalRef refCameraName(env, cameraName);
+		params[0].l = cameraName;
+		params[1].l = jPosition;
+		params[2].l = jUp;
+		params[3].l = jLookAt;
+		params[4].f = cCamera->mHorizontalFOV;
+		params[5].f = cCamera->mClipPlaneNear;
+		params[6].f = cCamera->mClipPlaneFar;
+		params[7].f = cCamera->mAspect;
+
+		if (!createInstance(env, "jassimp/AiCamera", "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;FFFF)V",
+			params, jCamera))
+		{
+			return false;
+		}
+
+		/* add camera to m_cameras java.util.List */
+		jobject jCameras = NULL;
+		SmartLocalRef refCameras(env, jCameras);
+		if (!getField(env, jScene, "m_cameras", "Ljava/util/List;", jCameras))
+		{
+			return false;
+		}
+
+		jvalue addParams[1];
+		addParams[0].l = jCamera;
+		if (!call(env, jCameras, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams))
+		{
+			return false;
+		}
+	}
+
+	lprintf("converting cameras finished\n");
+
+	return true;
+}
+
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getVKeysize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(aiVectorKey);
+	return res;
+}
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getQKeysize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(aiQuatKey);
+	return res;
+}
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getV3Dsize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(aiVector3D);
+	return res;
+}
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getfloatsize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(float);
+	return res;
+}
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getintsize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(int);
+	return res;
+}
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getuintsize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(unsigned int);
+	return res;
+}
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getdoublesize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(double);
+	return res;
+}
+
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getlongsize
+  (JNIEnv *env, jclass jClazz)
+{
+	const int res = sizeof(long);
+	return res;
+}
+
+JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
+  (JNIEnv *env, jclass jClazz)
+{
+	const char *err = gLastErrorString.c_str();
+
+	if (NULL == err)
+	{
+		return env->NewStringUTF("");
+	}
+
+	return env->NewStringUTF(err);
+}
+
+
+JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile
+  (JNIEnv *env, jclass jClazz, jstring jFilename, jlong postProcess, jobject ioSystem, jobject progressHandler)
+{
+	jobject jScene = NULL;
+
+	/* convert params */
+	const char* cFilename = env->GetStringUTFChars(jFilename, NULL);
+
+    Assimp::Importer imp;
+
+
+	if(ioSystem != NULL)
+	{
+		imp.SetIOHandler(new JavaIOSystem(env, ioSystem));
+		lprintf("Created aiFileIO\n");
+	}
+
+	if(progressHandler != NULL)
+	{
+		imp.SetProgressHandler(new JavaProgressHandler(env, progressHandler));
+	}
+
+	lprintf("opening file: %s\n", cFilename);
+
+	/* do import */
+	const aiScene *cScene = imp.ReadFile(cFilename, (unsigned int) postProcess);
+
+	if (!cScene)
+	{
+		lprintf("import file returned null\n");
+		goto error;
+	}
+
+	if (!createInstance(env, "jassimp/AiScene", jScene))
+	{
+		goto error;
+	}
+
+	if (!loadMeshes(env, cScene, jScene))
+	{
+		goto error;
+	}
+
+	if (!loadMaterials(env, cScene, jScene))
+	{
+		goto error;
+	}
+
+	if (!loadAnimations(env, cScene, jScene))
+	{
+		goto error;
+	}
+
+	if (!loadLights(env, cScene, jScene))
+	{
+		goto error;
+	}
+
+	if (!loadCameras(env, cScene, jScene))
+	{
+		goto error;
+	}
+
+	if (!loadSceneGraph(env, cScene, jScene))
+	{
+		goto error;
+	}
+
+	/* jump over error handling section */
+	goto end;
+
+error:
+	{
+	jclass exception = env->FindClass("java/io/IOException");
+
+	if (NULL == exception)
+	{
+		/* that's really a problem because we cannot throw in this case */
+		env->FatalError("could not throw java.io.IOException");
+	}
+	gLastErrorString = imp.GetErrorString();
+	env->ThrowNew(exception, gLastErrorString.c_str());
+
+	lprintf("problem detected\n");
+	}
+
+end:
+
+	/* free params */
+	env->ReleaseStringUTFChars(jFilename, cFilename);
+
+	lprintf("return from native\n");
+
+	return jScene;
+}
diff --git a/libs/assimp/port/jassimp/jassimp-native/src/jassimp.h b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.h
new file mode 100644
index 0000000..2a4a845
--- /dev/null
+++ b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.h
@@ -0,0 +1,47 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+#include <stdlib.h>
+/* Header for class jassimp_Jassimp */
+
+#ifndef _Included_jassimp_Jassimp
+#define _Included_jassimp_Jassimp
+#ifdef __cplusplus
+extern "C" {
+#endif
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getVKeysize
+  (JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getQKeysize
+  (JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getV3Dsize
+  (JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getfloatsize
+  (JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getintsize
+  (JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getuintsize
+  (JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getdoublesize
+  (JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getlongsize
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jassimp_Jassimp
+ * Method:    getErrorString
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jassimp_Jassimp
+ * Method:    aiImportFile
+ * Signature: (Ljava/lang/String;J)Ljassimp/AiScene;
+ */
+JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile
+  (JNIEnv *, jclass, jstring, jlong, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
-- 
cgit v1.2.1