2012-07-24 19:11:04 +00:00
|
|
|
#include "jassimp.h"
|
|
|
|
|
|
|
|
#include <assimp/cimport.h>
|
|
|
|
#include <assimp/scene.h>
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef JNI_LOG
|
2015-03-12 19:37:33 +00:00
|
|
|
#ifdef ANDROID
|
|
|
|
#include <android/log.h>
|
|
|
|
#define lprintf(...) __android_log_print(ANDROID_LOG_VERBOSE, __func__, __VA_ARGS__)
|
|
|
|
#else
|
2012-07-24 19:11:04 +00:00
|
|
|
#define lprintf(...) printf (__VA_ARGS__)
|
2015-03-12 19:37:33 +00:00
|
|
|
#endif /* ANDROID */
|
2012-07-24 19:11:04 +00:00
|
|
|
#else
|
|
|
|
#define lprintf
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static bool createInstance(JNIEnv *env, const char* className, jobject& newInstance)
|
|
|
|
{
|
|
|
|
jclass clazz = env->FindClass(className);
|
|
|
|
|
|
|
|
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);
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(clazz);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
if (NULL == newInstance)
|
|
|
|
{
|
|
|
|
lprintf("error calling no-arg constructor for class %s\n", className);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-12 19:37:33 +00:00
|
|
|
static bool createInstance(JNIEnv *env, const char* className, const char* signature,/* const*/ jvalue* params, jobject& newInstance)
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
jclass clazz = env->FindClass(className);
|
|
|
|
|
|
|
|
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);
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(clazz);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (NULL == clazz)
|
|
|
|
{
|
|
|
|
lprintf("could not get class for object\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature);
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(clazz);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (NULL == clazz)
|
|
|
|
{
|
|
|
|
lprintf("could not get class for object\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jfieldID fieldId = env->GetFieldID(clazz, fieldName, "I");
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(clazz);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (NULL == clazz)
|
|
|
|
{
|
|
|
|
lprintf("could not get class for object\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jfieldID fieldId = env->GetFieldID(clazz, fieldName, "F");
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(clazz);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (NULL == clazz)
|
|
|
|
{
|
|
|
|
lprintf("could not get class for object\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature);
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(clazz);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (NULL == clazz)
|
|
|
|
{
|
|
|
|
lprintf("could not find class %s\n", className);
|
|
|
|
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->GetStaticObjectField(clazz, fieldId);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool call(JNIEnv *env, jobject object, const char* typeName, const char* methodName,
|
2015-03-12 19:37:33 +00:00
|
|
|
const char* signature,/* const*/ jvalue* params)
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
jclass clazz = env->FindClass(typeName);
|
|
|
|
|
|
|
|
if (NULL == clazz)
|
|
|
|
{
|
|
|
|
lprintf("could not find class %s\n", typeName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jmethodID mid = env->GetMethodID(clazz, methodName, signature);
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(clazz);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
if (NULL == mid)
|
|
|
|
{
|
|
|
|
lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-12 19:37:33 +00:00
|
|
|
jboolean jReturnValue = env->CallBooleanMethod(object, mid, params[0].l);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (NULL == clazz) {
|
|
|
|
lprintf("could not find class %s\n", typeName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jmethodID mid = env->GetMethodID(clazz, methodName, signature);
|
|
|
|
env->DeleteLocalRef(clazz);
|
|
|
|
|
|
|
|
if (NULL == mid) {
|
|
|
|
lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-24 19:11:04 +00:00
|
|
|
env->CallVoidMethodA(object, mid, params);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool callStaticObject(JNIEnv *env, const char* typeName, const char* methodName,
|
2015-03-12 19:37:33 +00:00
|
|
|
const char* signature,/* const*/ jvalue* params, jobject& returnValue)
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
jclass clazz = env->FindClass(typeName);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (!getField(env, jMesh, jBufferName, "Ljava/nio/ByteBuffer;", jBuffer))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (env->GetDirectBufferCapacity(jBuffer) != size)
|
|
|
|
{
|
2015-03-28 13:45:21 +00:00
|
|
|
lprintf("invalid direct buffer, expected %u, got %llu\n", size, env->GetDirectBufferCapacity(jBuffer));
|
2012-07-24 19:11:04 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
if (!getField(env, jMesh, jBufferName, "[Ljava/nio/ByteBuffer;", jBufferArray))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
jobject jBuffer = env->GetObjectArrayElement((jobjectArray) jBufferArray, index);
|
|
|
|
|
|
|
|
if (env->GetDirectBufferCapacity(jBuffer) != size)
|
|
|
|
{
|
2015-03-28 13:45:21 +00:00
|
|
|
lprintf("invalid direct buffer, expected %u, got %llu\n", size, env->GetDirectBufferCapacity(jBuffer));
|
2012-07-24 19:11:04 +00:00
|
|
|
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 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;
|
|
|
|
|
|
|
|
if (!createInstance(env, "jassimp/AiMesh", jMesh))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* add mesh to m_meshes java.util.List */
|
|
|
|
jobject jMeshes = NULL;
|
|
|
|
|
|
|
|
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;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMesh, "jassimp/AiMesh", "setPrimitiveTypes", "(I)V", setTypesParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!setIntField(env, jMesh, "m_materialIndex", cMesh->mMaterialIndex))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!setObjectField(env, jMesh, "m_name", "Ljava/lang/String;", env->NewStringUTF(cMesh->mName.C_Str())))
|
|
|
|
{
|
|
|
|
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;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMesh, "jassimp/AiMesh", "allocateBuffers", "(IIZI)V", allocateBuffersParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
if (!createInstance(env, "jassimp/AiBone", jBone))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add bone to bone list */
|
|
|
|
jobject jBones = NULL;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
if (!setObjectField(env, jBone, "m_name", "Ljava/lang/String;", env->NewStringUTF(cBone->mName.C_Str())))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add bone weights */
|
|
|
|
for (unsigned int w = 0; w < cBone->mNumWeights; w++)
|
|
|
|
{
|
|
|
|
jobject jBoneWeight;
|
|
|
|
if (!createInstance(env, "jassimp/AiBoneWeight", jBoneWeight))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add boneweight to bone list */
|
|
|
|
jobject jBoneWeights = NULL;
|
|
|
|
|
|
|
|
if (!getField(env, jBone, "m_boneWeights", "Ljava/util/List;", jBoneWeights))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* copy offset matrix */
|
|
|
|
jfloatArray jMatrixArr = env->NewFloatArray(16);
|
|
|
|
env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cBone->mOffsetMatrix);
|
|
|
|
|
|
|
|
jvalue wrapParams[1];
|
|
|
|
wrapParams[0].l = jMatrixArr;
|
|
|
|
jobject jMatrix;
|
|
|
|
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapParams, jMatrix))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-12 19:37:33 +00:00
|
|
|
env->DeleteLocalRef(jMeshes);
|
|
|
|
env->DeleteLocalRef(jMesh);
|
2012-07-24 19:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cNode->mTransformation);
|
|
|
|
|
|
|
|
jvalue wrapMatParams[1];
|
|
|
|
wrapMatParams[0].l = jMatrixArr;
|
|
|
|
jobject jMatrix;
|
|
|
|
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapMatParams, jMatrix))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* create mesh references array */
|
|
|
|
jintArray jMeshrefArr = env->NewIntArray(cNode->mNumMeshes);
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
|
|
/* wrap scene node */
|
|
|
|
jvalue wrapNodeParams[4];
|
|
|
|
wrapNodeParams[0].l = parent;
|
|
|
|
wrapNodeParams[1].l = jMatrix;
|
|
|
|
wrapNodeParams[2].l = jMeshrefArr;
|
|
|
|
wrapNodeParams[3].l = jNodeName;
|
|
|
|
jobject jNode;
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapSceneNode",
|
2012-07-24 19:11:04 +00:00
|
|
|
"(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)
|
|
|
|
{
|
|
|
|
*loadedNode = jNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool loadSceneGraph(JNIEnv *env, const aiScene* cScene, jobject& jScene)
|
|
|
|
{
|
|
|
|
lprintf("converting scene graph ...\n");
|
|
|
|
|
|
|
|
if (NULL != cScene->mRootNode)
|
|
|
|
{
|
|
|
|
jobject 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];
|
|
|
|
|
2015-03-28 13:45:21 +00:00
|
|
|
lprintf("converting material %d ...\n", m);
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
jobject jMaterial = NULL;
|
|
|
|
|
|
|
|
if (!createInstance(env, "jassimp/AiMaterial", jMaterial))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add material to m_materials java.util.List */
|
|
|
|
jobject jMaterials = NULL;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callv(env, jMaterial, "jassimp/AiMaterial", "setTextureNumber", "(II)V", setNumberParams))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
jvalue constructorParams[5];
|
|
|
|
constructorParams[0].l = env->NewStringUTF(cProperty->mKey.C_Str());
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* 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];
|
2015-03-12 19:37:33 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jData))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* 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];
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor4", "(FFFF)Ljava/lang/Object;", wrapColorParams, jData))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
jvalue newAnimParams[3];
|
|
|
|
newAnimParams[0].l = env->NewStringUTF(cAnimation->mName.C_Str());
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
jvalue newNodeAnimParams[6];
|
|
|
|
newNodeAnimParams[0].l = env->NewStringUTF(cNodeAnim->mNodeName.C_Str());
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jDiffuse))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrapColorParams[0].f = cLight->mColorSpecular.r;
|
|
|
|
wrapColorParams[1].f = cLight->mColorSpecular.g;
|
|
|
|
wrapColorParams[2].f = cLight->mColorSpecular.b;
|
|
|
|
jobject jSpecular;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jSpecular))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrapColorParams[0].f = cLight->mColorAmbient.r;
|
|
|
|
wrapColorParams[1].f = cLight->mColorAmbient.g;
|
|
|
|
wrapColorParams[2].f = cLight->mColorAmbient.b;
|
|
|
|
jobject jAmbient;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jAmbient))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
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;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jPosition))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrapVec3Params[0].f = cLight->mPosition.x;
|
|
|
|
wrapVec3Params[1].f = cLight->mPosition.y;
|
|
|
|
wrapVec3Params[2].f = cLight->mPosition.z;
|
|
|
|
jobject jDirection;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jDirection))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
jobject jLight;
|
|
|
|
|
|
|
|
jvalue params[12];
|
|
|
|
params[0].l = env->NewStringUTF(cLight->mName.C_Str());;
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jPosition))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrapPositionParams[0].f = cCamera->mUp.x;
|
|
|
|
wrapPositionParams[1].f = cCamera->mUp.y;
|
|
|
|
wrapPositionParams[2].f = cCamera->mUp.z;
|
|
|
|
jobject jUp;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jUp))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrapPositionParams[0].f = cCamera->mLookAt.x;
|
|
|
|
wrapPositionParams[1].f = cCamera->mLookAt.y;
|
|
|
|
wrapPositionParams[2].f = cCamera->mLookAt.z;
|
|
|
|
jobject jLookAt;
|
2015-03-13 11:52:03 +00:00
|
|
|
if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jLookAt))
|
2012-07-24 19:11:04 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
jobject jCamera;
|
|
|
|
|
|
|
|
jvalue params[8];
|
|
|
|
params[0].l = env->NewStringUTF(cCamera->mName.C_Str());
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-27 17:09:39 +00:00
|
|
|
JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getVKeysize
|
|
|
|
(JNIEnv *env, jclass jClazz)
|
|
|
|
{
|
|
|
|
const int res = sizeof(aiVectorKey);
|
2015-03-28 13:21:47 +00:00
|
|
|
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;
|
|
|
|
}
|
2015-03-27 17:09:39 +00:00
|
|
|
|
2015-03-28 13:21:47 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-03-28 14:01:01 +00:00
|
|
|
JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getdoublesize
|
2015-03-28 13:21:47 +00:00
|
|
|
(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);
|
2015-03-27 17:09:39 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2012-07-24 19:11:04 +00:00
|
|
|
JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
|
|
|
|
(JNIEnv *env, jclass jClazz)
|
|
|
|
{
|
|
|
|
const char *err = aiGetErrorString();
|
|
|
|
|
|
|
|
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 jScene = NULL;
|
|
|
|
|
|
|
|
/* convert params */
|
|
|
|
const char* cFilename = env->GetStringUTFChars(jFilename, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
lprintf("opening file: %s\n", cFilename);
|
|
|
|
|
|
|
|
/* do import */
|
|
|
|
const aiScene *cScene = aiImportFile(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:
|
2014-12-06 14:52:44 +00:00
|
|
|
{
|
2012-07-24 19:11:04 +00:00
|
|
|
jclass exception = env->FindClass("java/io/IOException");
|
|
|
|
|
|
|
|
if (NULL == exception)
|
|
|
|
{
|
|
|
|
/* thats really a problem because we cannot throw in this case */
|
|
|
|
env->FatalError("could not throw java.io.IOException");
|
|
|
|
}
|
|
|
|
|
|
|
|
env->ThrowNew(exception, aiGetErrorString());
|
|
|
|
|
|
|
|
lprintf("problem detected\n");
|
2014-12-06 14:52:44 +00:00
|
|
|
}
|
2012-07-24 19:11:04 +00:00
|
|
|
|
|
|
|
end:
|
|
|
|
/*
|
|
|
|
* NOTE: this releases all memory used in the native domain.
|
|
|
|
* Ensure all data has been passed to java before!
|
|
|
|
*/
|
|
|
|
aiReleaseImport(cScene);
|
|
|
|
|
|
|
|
|
|
|
|
/* free params */
|
|
|
|
env->ReleaseStringUTFChars(jFilename, cFilename);
|
|
|
|
|
|
|
|
lprintf("return from native\n");
|
|
|
|
|
|
|
|
return jScene;
|
2014-12-06 14:52:44 +00:00
|
|
|
}
|