From aab9376628d2ee11c908f3bcc2836dab370288f7 Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Fri, 23 May 2008 12:30:52 +0000 Subject: [PATCH] Updated jAssimp API. 40% are complete now, some JNI wrappers are ready git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@34 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/Importer.cpp | 8 + code/jAssimp/BuildHeader.bat | 1 + code/jAssimp/JNICalls.cpp | 236 ++++++++++++- code/jAssimp/assimp_Animation.h | 13 + code/jAssimp/assimp_Importer.h | 8 +- code/jAssimp/assimp_Scene.h | 16 +- include/aiMaterial.h | 2 +- include/assimp.hpp | 9 + port/jAssimp/src/assimp/Importer.java | 61 +++- port/jAssimp/src/assimp/Mesh.java | 465 +++++++++++++++++++++++++- port/jAssimp/src/assimp/Scene.java | 116 +++---- workspaces/jidea5.1/jAssimp.ipr | 8 +- workspaces/vc8/assimp.vcproj | 4 +- 13 files changed, 852 insertions(+), 95 deletions(-) create mode 100644 code/jAssimp/assimp_Animation.h diff --git a/code/Importer.cpp b/code/Importer.cpp index 2dbe85fc3..578814073 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -200,6 +200,14 @@ const aiScene* Importer::ReadFile( const std::string& pFile, unsigned int pFlags // validate the flags ai_assert(ValidateFlags(pFlags)); + // check whether this Importer instance has already loaded + // a scene. In this case we need to delete the old one + if (this->mScene) + { + delete mScene; + this->mScene = NULL; + } + // first check if the file is accessable at all if( !mIOHandler->Exists( pFile)) { diff --git a/code/jAssimp/BuildHeader.bat b/code/jAssimp/BuildHeader.bat index 5c595057a..abe9cd4a0 100644 --- a/code/jAssimp/BuildHeader.bat +++ b/code/jAssimp/BuildHeader.bat @@ -4,3 +4,4 @@ javah -classpath ".\..\..\port\jAssimp\classes" -d "." "assimp.Node" javah -classpath ".\..\..\port\jAssimp\classes" -d "." "assimp.Scene" javah -classpath ".\..\..\port\jAssimp\classes" -d "." "assimp.Mesh" javah -classpath ".\..\..\port\jAssimp\classes" -d "." "assimp.Texture" +javah -classpath ".\..\..\port\jAssimp\classes" -d "." "assimp.Animation" diff --git a/code/jAssimp/JNICalls.cpp b/code/jAssimp/JNICalls.cpp index 4e5325f20..8b3ec12bf 100644 --- a/code/jAssimp/JNICalls.cpp +++ b/code/jAssimp/JNICalls.cpp @@ -43,7 +43,239 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if (defined ASSIMP_JNI_EXPORT) -// include the JNI API -#include +// include the header files generated by javah +#include "assimp_Importer.h" +#include "assimp_Animation.h" +#include "assimp_Node.h" +#include "assimp_Texture.h" +#include "assimp_Mesh.h" +#include "assimp_Material.h" +// include assimp +#include "../../include/aiTypes.h" +#include "../../include/aiMesh.h" +#include "../../include/aiAnim.h" +#include "../../include/aiScene.h" +#include "../../include/aiAssert.h" +#include "../../include/aiPostProcess.h" +#include "../../include/assimp.hpp" + +#include "../DefaultLogger.h" + +using namespace Assimp; + +#include + +namespace Assimp { +namespace JNIBridge { + +// used as error return code +#define AI_JNI_ERROR_RETURN 0xffffffff + +// typedef for a jassimp context, used to uniquely identify +// the Importer object which belongs to a java Importer + +typedef uint64_t JASSIMP_CONTEXT; + +#if (defined _DEBUG) + + typedef std::list< JASSIMP_CONTEXT > ImporterContextList; + static ImporterContextList g_listActiveContexts; + +// ------------------------------------------------------------------------------------------------ +/* Used in debug builds to validate a context +*/ +bool jValidateContext (JASSIMP_CONTEXT context) +{ + for (ImporterContextList::const_iterator + i = g_listActiveContexts.begin(); + i != g_listActiveContexts.end();++i) + { + if (context == *i)return true; + } + DefaultLogger::get()->error("[jnibridge] Invalid context"); + return false; +} +// ------------------------------------------------------------------------------------------------ +/* Used in debug builds to validate a given scene +*/ +bool jValidateScene (const aiScene* scene) +{ + if (!scene) + { + DefaultLogger::get()->error("[jnibridge] No asset loaded at the moment"); + return false; + } + return true; +} + +#endif // ! ASSIMP_DEBUG +// ------------------------------------------------------------------------------------------------ +/* Used in debug builds to validate a given scene +*/ +Assimp::Importer* jGetValidImporterScenePair (JASSIMP_CONTEXT jvmcontext) +{ +#if (defined _DEBUG) + if (!jValidateContext((JASSIMP_CONTEXT)jvmcontext))return NULL; +#endif // ! ASSIMP_DEBUG + + // get the importer instance from the context + Assimp::Importer* pcImp = (Assimp::Importer*)jvmcontext; + +#if (defined _DEBUG) + if (!jValidateScene(pcImp->GetScene()))return NULL; +#endif // ! ASSIMP_DEBUG + return pcImp; +} +// ------------------------------------------------------------------------------------------------ +/* + * Class: assimp_Importer + * Method: _NativeInitContext + * Signature: ()I + */ +JNIEXPORT jlong JNICALL Java_assimp_Importer__1NativeInitContext + (JNIEnv * jvmenv, jobject jvmthis) +{ + ai_assert(NULL != jvmenv && NULL != jvmthis); + + // 2^64-1 indicates error + JASSIMP_CONTEXT context = 0xffffffffffffffffL; + + // create a new Importer instance + Assimp::Importer* pcImp = new Assimp::Importer(); + context = (JASSIMP_CONTEXT)(uintptr_t)pcImp; + +#if (defined _DEBUG) + g_listActiveContexts.push_back(context); +#endif // ! ASSIMP_DEBUG + return context; +} +// ------------------------------------------------------------------------------------------------ +/* + * Class: assimp_Importer + * Method: _NativeFreeContext + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_assimp_Importer__1NativeFreeContext + (JNIEnv * jvmenv, jobject jvmthis, jlong jvmcontext) +{ + ai_assert(NULL != jvmenv && NULL != jvmthis); + +#if (defined _DEBUG) + if (!jValidateContext((JASSIMP_CONTEXT)jvmcontext))return AI_JNI_ERROR_RETURN; +#endif // ! ASSIMP_DEBUG + + // delete the Importer instance + Assimp::Importer* pcImp = (Assimp::Importer*)jvmcontext; + delete pcImp; + +#if (defined _DEBUG) + g_listActiveContexts.remove(jvmcontext); +#endif // ! ASSIMP_DEBUG + return 0; +} +// ------------------------------------------------------------------------------------------------ +/* + * Class: assimp_Importer + * Method: _NativeLoad + * Signature: (Ljava/lang/String;II)I + */ +JNIEXPORT jint JNICALL Java_assimp_Importer__1NativeLoad + (JNIEnv *jvmenv, jobject jvmthis, jstring jvmpath, jint jvmflags, jlong jvmcontext) +{ + ai_assert(NULL != jvmenv && NULL != jvmthis); + jint iRet = 0; + +#if (defined _DEBUG) + if (!jValidateContext((JASSIMP_CONTEXT)jvmcontext))return AI_JNI_ERROR_RETURN; +#endif // ! ASSIMP_DEBUG + + // get the path from the jstring + const char* szPath = jvmenv->GetStringUTFChars(jvmpath,NULL); + if (!szPath) + { + DefaultLogger::get()->error("[jnibridge] Unable to get path string from the java vm"); + return AI_JNI_ERROR_RETURN; + } + // get the importer instance from the context + Assimp::Importer* pcImp = (Assimp::Importer*)jvmcontext; + + // and load the file. The aiScene object itself remains accessible + // via Importer.GetScene(). + if(NULL == pcImp->ReadFile(std::string(szPath),(unsigned int)jvmflags)) + { + DefaultLogger::get()->error("[jnibridge] Unable to load asset"); + + // release the path again + jvmenv->ReleaseStringUTFChars(jvmpath,szPath); + return AI_JNI_ERROR_RETURN; + } + // release the path again + jvmenv->ReleaseStringUTFChars(jvmpath,szPath); + return iRet; +} +// ------------------------------------------------------------------------------------------------ +/* + * Class: assimp_Scene + * Method: _NativeGetNumMeshes + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumMeshes + (JNIEnv *jvmenv, jobject jvmthis, jlong jvmcontext) +{ + ai_assert(NULL != jvmenv && NULL != jvmthis); + // we need a valid scene for this + Assimp::Importer* pcImp = jGetValidImporterScenePair(jvmcontext); + if (!pcImp)return AI_JNI_ERROR_RETURN; + return (jint)pcImp->GetScene()->mNumMeshes; +} +// ------------------------------------------------------------------------------------------------ +/* + * Class: assimp_Scene + * Method: _NativeGetNumAnimations + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumAnimations + (JNIEnv *jvmenv, jobject jvmthis, jlong jvmcontext) +{ + + ai_assert(NULL != jvmenv && NULL != jvmthis); + // we need a valid scene for this + Assimp::Importer* pcImp = jGetValidImporterScenePair(jvmcontext); + if (!pcImp)return AI_JNI_ERROR_RETURN; + return (jint)pcImp->GetScene()->mNumAnimations; +} +// ------------------------------------------------------------------------------------------------ +/* + * Class: assimp_Scene + * Method: _NativeGetNumTextures + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumTextures + (JNIEnv *jvmenv, jobject jvmthis, jlong jvmcontext) +{ + ai_assert(NULL != jvmenv && NULL != jvmthis); + // we need a valid scene for this + Assimp::Importer* pcImp = jGetValidImporterScenePair(jvmcontext); + if (!pcImp)return AI_JNI_ERROR_RETURN; + return (jint)pcImp->GetScene()->mNumTextures; +} +// ------------------------------------------------------------------------------------------------ +/* + * Class: assimp_Scene + * Method: _NativeGetNumMaterials + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumMaterials + (JNIEnv *jvmenv, jobject jvmthis, jlong jvmcontext) +{ + ai_assert(NULL != jvmenv && NULL != jvmthis); + // we need a valid scene for this + Assimp::Importer* pcImp = jGetValidImporterScenePair(jvmcontext); + if (!pcImp)return AI_JNI_ERROR_RETURN; + return (jint)pcImp->GetScene()->mNumMaterials; +} + +}; //! namespace JNIBridge +}; //! namespace Assimp #endif // !ASSIMP_JNI_EXPORT \ No newline at end of file diff --git a/code/jAssimp/assimp_Animation.h b/code/jAssimp/assimp_Animation.h new file mode 100644 index 000000000..332bb6398 --- /dev/null +++ b/code/jAssimp/assimp_Animation.h @@ -0,0 +1,13 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class assimp_Animation */ + +#ifndef _Included_assimp_Animation +#define _Included_assimp_Animation +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/code/jAssimp/assimp_Importer.h b/code/jAssimp/assimp_Importer.h index 47f2010d7..5e7a3af50 100644 --- a/code/jAssimp/assimp_Importer.h +++ b/code/jAssimp/assimp_Importer.h @@ -18,18 +18,18 @@ JNIEXPORT jint JNICALL Java_assimp_Importer__1NativeInitContext /* * Class: assimp_Importer * Method: _NativeFreeContext - * Signature: (I)I + * Signature: (J)I */ JNIEXPORT jint JNICALL Java_assimp_Importer__1NativeFreeContext - (JNIEnv *, jobject, jint); + (JNIEnv *, jobject, jlong); /* * Class: assimp_Importer * Method: _NativeLoad - * Signature: (Ljava/lang/String;II)I + * Signature: (Ljava/lang/String;IJ)I */ JNIEXPORT jint JNICALL Java_assimp_Importer__1NativeLoad - (JNIEnv *, jobject, jstring, jint, jint); + (JNIEnv *, jobject, jstring, jint, jlong); #ifdef __cplusplus } diff --git a/code/jAssimp/assimp_Scene.h b/code/jAssimp/assimp_Scene.h index f17fe16b4..5a6a5a713 100644 --- a/code/jAssimp/assimp_Scene.h +++ b/code/jAssimp/assimp_Scene.h @@ -10,34 +10,34 @@ extern "C" { /* * Class: assimp_Scene * Method: _NativeGetNumMeshes - * Signature: (I)I + * Signature: (J)I */ JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumMeshes - (JNIEnv *, jobject, jint); + (JNIEnv *, jobject, jlong); /* * Class: assimp_Scene * Method: _NativeGetNumAnimations - * Signature: (I)I + * Signature: (J)I */ JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumAnimations - (JNIEnv *, jobject, jint); + (JNIEnv *, jobject, jlong); /* * Class: assimp_Scene * Method: _NativeGetNumTextures - * Signature: (I)I + * Signature: (J)I */ JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumTextures - (JNIEnv *, jobject, jint); + (JNIEnv *, jobject, jlong); /* * Class: assimp_Scene * Method: _NativeGetNumMaterials - * Signature: (I)I + * Signature: (J)I */ JNIEXPORT jint JNICALL Java_assimp_Scene__1NativeGetNumMaterials - (JNIEnv *, jobject, jint); + (JNIEnv *, jobject, jlong); #ifdef __cplusplus } diff --git a/include/aiMaterial.h b/include/aiMaterial.h index 56b51682b..64e3889ef 100644 --- a/include/aiMaterial.h +++ b/include/aiMaterial.h @@ -522,7 +522,7 @@ aiReturn aiGetMaterialString(const C_STRUCT aiMaterial* pMat, #define AI_TEXTYPE_DIFFUSE 0x7 // --------------------------------------------------------------------------- -/** Helper function to get a diffuse texture from a material +/** Helper function to get a texture from a material * * This function is provided just for convinience. * @param pMat Pointer to the input material. May not be NULL diff --git a/include/assimp.hpp b/include/assimp.hpp index cc7e725d0..61eab27df 100644 --- a/include/assimp.hpp +++ b/include/assimp.hpp @@ -161,6 +161,15 @@ public: */ void GetExtensionList(std::string& szOut); + + // ------------------------------------------------------------------- + /** Returns the scene loaded by the last successful call to ReadFile() + * + * @return Current scene or NULL if there is currently no scene loaded + */ + inline const aiScene* GetScene() + {return this->mScene;} + private: /** Empty copy constructor. */ Importer(const Importer &other); diff --git a/port/jAssimp/src/assimp/Importer.java b/port/jAssimp/src/assimp/Importer.java index 7bd259937..c9793ad57 100644 --- a/port/jAssimp/src/assimp/Importer.java +++ b/port/jAssimp/src/assimp/Importer.java @@ -70,7 +70,7 @@ public class Importer { * Assimp::Importer object. For 64 bit platforms it is something else .. * at least it is guaranted to be unique ;-) */ - private int m_iNativeHandle = 0xffffffff; + private long m_iNativeHandle = 0xffffffffffffffffl; /** * Loaded scene. It can't be used after the Importer class instance @@ -88,9 +88,10 @@ public class Importer { * ASSIMP library. A native Assimp::Importer object is constructed and * initialized. The flag list is set to zero, a default I/O handler * is constructed. + * * @throws NativeError Thrown if the jassimp library could not be loaded - * or if the entry point to the module wasn't found. if this exception - * is not thrown, you can assume that jAssimp is fully available. + * or if the entry point to the module wasn't found. if this exception + * is not thrown, you can assume that jAssimp is fully available. */ public Importer() throws NativeError { /** try to load the jassimp library. First try to load the @@ -110,16 +111,16 @@ public class Importer { // now create the native Importer class and setup our internal // data structures outside the VM. try { - if (0xffffffff == (this.m_iNativeHandle = _NativeInitContext())) { + if (0xffffffffffffffffl == (this.m_iNativeHandle = _NativeInitContext())) { throw new NativeError( "Unable to initialize the native library context." + - "The initialization routine has failed"); + "The initialization routine has failed"); } } catch (UnsatisfiedLinkError exc) { throw new NativeError( "Unable to initialize the native library context." + - "The initialization routine has not been found"); + "The initialization routine has not been found"); } return; } @@ -183,17 +184,20 @@ public class Importer { * a default implementation is used. This implementation uses fopen()/ * fread()/fwrite()/fclose()/ftell()/fseek() and provides no support * for archives like ZIP or PAK. + * * @param path Path to the file to be read * @return null if the import failed, otherwise a valid Scene instance + * @throws NativeError This exception is thrown when an unknown error + * occurs in the JNI bridge module. */ - public Scene readFile(String path) { + public Scene readFile(String path) throws NativeError { this.scene = new Scene(this); this.path = path; // we need to build a path that is valid for the current OS char sep = System.getProperty("file.separator").charAt(0); - if(sep != '\\') this.path = this.path.replace('\\',sep); - if(sep != '/') this.path = this.path.replace('/',sep); + if (sep != '\\') this.path = this.path.replace('\\', sep); + if (sep != '/') this.path = this.path.replace('/', sep); // need to build a list of postprocess step as bitflag combination // Of course, this could have been implemented directly. However, @@ -212,11 +216,20 @@ public class Importer { } // now load the mesh - if(0xffffffff == this._NativeLoad(this.path,flags,this.m_iNativeHandle) || - ! this.scene.construct()) { + if (0xffffffff == this._NativeLoad(this.path, flags, this.m_iNativeHandle)) { this.scene = null; this.path = null; - return null; + throw new NativeError("Failed to load the mesh"); + } + // and setup our Scene object + try { + this.scene.construct(); + } + catch (NativeError exc) { + + this.scene = null; + this.path = null; + throw exc; } return this.scene; } @@ -260,17 +273,29 @@ public class Importer { /** * Implementation of java.lang.Object.hashCode() - * + *

* The native handle obtained from the JNI bridge is used as hash code. - * It is assumed to be unique, in fact it is normall the address of + * It is assumed to be unique, in fact it is normally the address of * the native Assimp::Importer object. + * * @return An unique value representing the object */ @Override public int hashCode() { + return (int) (m_iNativeHandle >> 32) ^ (int) (m_iNativeHandle); + } + + + /** + * Retrieves the native context of the class. This is normally the + * address of the native Importer object. + * @return Native context + */ + public long getContext() { return m_iNativeHandle; } + /** * JNI bridge call. For internal use only * The method initializes the ASSIMP-JNI bridge for use. No native @@ -288,16 +313,18 @@ public class Importer { * JNI bridge call. For internal use only * The method destroys the ASSIMP-JNI bridge. No native function call * to assimp will be successful after this method has been called. + * * @return 0xffffffff if an error occured */ - private native int _NativeFreeContext(int iContext); + private native int _NativeFreeContext(long iContext); /** * JNI bridge call. For internal use only * The method loads the model into memory, but does not map it into the VM - * @param path Path (valid separators for the OS) to the model to be loaded + * + * @param path Path (valid separators for the OS) to the model to be loaded * @param flags List of postprocess steps to be executed * @return 0xffffffff if an error occured */ - private native int _NativeLoad(String path,int flags, int iContext); + private native int _NativeLoad(String path, int flags, long iContext); } diff --git a/port/jAssimp/src/assimp/Mesh.java b/port/jAssimp/src/assimp/Mesh.java index ddbd7051f..b9b0866bb 100644 --- a/port/jAssimp/src/assimp/Mesh.java +++ b/port/jAssimp/src/assimp/Mesh.java @@ -74,18 +74,481 @@ public class Mesh extends IMappable { */ private static final int MAX_NUMBER_OF_COLOR_SETS = 0x4; + + /** + * Specifies which vertex components are existing in + * the native implementation. If a member is null here, + * although it is existing, it hasn't yet been mapped + * into memory + */ + private int m_iPresentFlags = 0; + + private static final int PF_POSITION = 0x1; + private static final int PF_NORMAL = 0x2; + private static final int PF_TANGENTBITANGENT = 0x4; + private static final int PF_VERTEXCOLOR = 0x1000; + private static final int PF_UVCOORD = 0x10000; + + private static int PF_VERTEXCOLORn(int n) { + assert(n <= MAX_NUMBER_OF_COLOR_SETS); + return PF_VERTEXCOLOR << n; + } + + private static int PF_UVCOORDn(int n) { + assert(n <= MAX_NUMBER_OF_TEXTURECOORDS); + return PF_UVCOORD << n; + } + + /** + * Contains the vertices loaded from the model + */ + private float[] m_vVertices = null; + + /** + * Contains the normal vectors loaded from the model or + * computed by postprocess steps. Needn't be existing + */ + private float[] m_vNormals = null; + + /** + * Contains the tangent vectors computed by Assimp + * Needn't be existing + */ + private float[] m_vTangents = null; + + /** + * Contains the bitangent vectors computed by Assimp + * Needn't be existing + */ + private float[] m_vBitangents = null; + + /** + * Contains the texture coordinate sets that have been loaded + * Needn't be existing + */ + private float[][] m_avUVs = new float[MAX_NUMBER_OF_TEXTURECOORDS][]; + + /** + * Specifies how many texture coordinate components are valid + * in an UV channel. Normally this will be 2, but 3d texture + * coordinates for cubic or volumetric mapping are also supported. + */ + private int[] m_aiNumUVComponents = new int[MAX_NUMBER_OF_TEXTURECOORDS]; + + /** + * Contains the vertex color sets that have been loaded + * Needn't be existing + */ + private float[][] m_avColors = new float[MAX_NUMBER_OF_COLOR_SETS][]; + + /** + * Number of vertices in the mesh + */ + private int m_iNumVertices; + + /** * Construction from a given parent object and array index * * @param parent Parent object * @param index Valied index in the parent's list */ - public Mesh(Object parent, int index) { + public Mesh(Object parent, int index) throws NativeError { super(parent, index); + + assert (parent instanceof Scene); + + Scene sc = (Scene) parent; + if (0xffffffff == (this.m_iPresentFlags = this._NativeGetPresenceFlags( + sc.getImporter().getContext()))) { + throw new NativeError("Unable to obtain a list of vertex presence flags"); + } + if (0xffffffff == (this.m_iNumVertices = this._NativeGetNumVertices( + sc.getImporter().getContext()))) { + throw new NativeError("Unable to obtain the number of vertices in the mesh"); + } + if (0xffffffff == this._NativeGetNumUVComponents( + sc.getImporter().getContext(), this.m_aiNumUVComponents)) { + throw new NativeError("Unable to obtain the number of UV components"); + } + } + + /** + * Check whether there are vertex positions in the model + * getVertex() will assert this. + * + * @return true if vertex positions are available. + */ + public boolean hasPositions() { + return 0 != (this.m_iPresentFlags & PF_POSITION); + } + + /** + * Check whether there are normal vectors in the model + * getNormal() will assert this. + * + * @return true if vertex normals are available. + */ + public boolean hasNormals() { + return 0 != (this.m_iPresentFlags & PF_NORMAL); + } + + /** + * Check whether there are tangents/bitangents in the model + * getTangent() and GetBitangent() will assert this. + * + * @return true if vertex tangents and bitangents are available. + */ + public boolean hasTangentsAndBitangents() { + return 0 != (this.m_iPresentFlags & PF_TANGENTBITANGENT); + } + + /** + * Check whether a given UV set is existing the model + * getUV() will assert this. + * + * @param n UV coordinate set index + * @return true the uv coordinate set is available. + */ + public boolean hasUVCoords(int n) { + return 0 != (this.m_iPresentFlags & PF_UVCOORDn(n)); + } + + /** + * Check whether a given vertex color set is existing the model + * getColor() will assert this. + * + * @param n Vertex color set index + * @return true the vertex color set is available. + */ + public boolean hasVertexColors(int n) { + return 0 != (this.m_iPresentFlags & PF_VERTEXCOLORn(n)); + } + + + /** + * Get the number of vertices in the model + * + * @return Number of vertices in the asset. This could be 0 in some + * extreme cases although loaders should filter such cases out + */ + public int getNumVertices() { + return m_iNumVertices; + } + + /** + * Get a vertex position in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * Receives the vertex position components in x,y,z order + */ + public void getPosition(int iIndex, float[] afOut) { + assert(this.hasPositions()); + assert(afOut.length >= 3); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vVertices) this.mapVertices(); + + iIndex *= 3; + afOut[0] = this.m_vVertices[iIndex]; + afOut[1] = this.m_vVertices[iIndex + 1]; + afOut[2] = this.m_vVertices[iIndex + 2]; + } + + /** + * Get a vertex position in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * @param iOutBase Start index in the output array + * Receives the vertex position components in x,y,z order + */ + public void getPosition(int iIndex, float[] afOut, int iOutBase) { + assert(this.hasPositions()); + assert(afOut.length >= 3); + assert(iOutBase + 3 <= afOut.length); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vVertices) this.mapVertices(); + + iIndex *= 3; + afOut[iOutBase] = this.m_vVertices[iIndex]; + afOut[iOutBase + 1] = this.m_vVertices[iIndex + 1]; + afOut[iOutBase + 2] = this.m_vVertices[iIndex + 2]; + } + + /** + * Provides direct access to the vertex position array of the mesh + * This is the recommended way of accessing the data. + * + * @return Array of floats, size is numverts * 3. Component ordering + * is xyz. + */ + public float[] getPositionArray() { + assert(this.hasPositions()); + if (null == this.m_vVertices) this.mapVertices(); + return this.m_vVertices; + } + + /** + * Get a vertex normal in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * Receives the vertex normal components in x,y,z order + */ + public void getNormal(int iIndex, float[] afOut) { + assert(this.hasNormals()); + assert(afOut.length >= 3); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vNormals) this.mapNormals(); + + iIndex *= 3; + afOut[0] = this.m_vNormals[iIndex]; + afOut[1] = this.m_vNormals[iIndex + 1]; + afOut[2] = this.m_vNormals[iIndex + 2]; + } + + /** + * Get a vertex normal in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * @param iOutBase Start index in the output array + * Receives the vertex normal components in x,y,z order + */ + public void getNormal(int iIndex, float[] afOut, int iOutBase) { + assert(this.hasNormals()); + assert(afOut.length >= 3); + assert(iOutBase + 3 <= afOut.length); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vNormals) this.mapNormals(); + + iIndex *= 3; + afOut[iOutBase] = this.m_vNormals[iIndex]; + afOut[iOutBase + 1] = this.m_vNormals[iIndex + 1]; + afOut[iOutBase + 2] = this.m_vNormals[iIndex + 2]; + } + + /** + * Provides direct access to the vertex normal array of the mesh + * This is the recommended way of accessing the data. + * + * @return Array of floats, size is numverts * 3. Component ordering + * is xyz. + */ + public float[] getNormalArray() { + assert(this.hasNormals()); + if (null == this.m_vNormals) this.mapNormals(); + return this.m_vNormals; + } + + /** + * Get a vertex tangent in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * Receives the vertex tangent components in x,y,z order + */ + public void getTangent(int iIndex, float[] afOut) { + assert(this.hasTangentsAndBitangents()); + assert(afOut.length >= 3); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vTangents) this.mapTangents(); + + iIndex *= 3; + afOut[0] = this.m_vTangents[iIndex]; + afOut[1] = this.m_vTangents[iIndex + 1]; + afOut[2] = this.m_vTangents[iIndex + 2]; + } + + /** + * Get a vertex tangent in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * @param iOutBase Start index in the output array + * Receives the vertex tangent components in x,y,z order + */ + public void getTangent(int iIndex, float[] afOut, int iOutBase) { + assert(this.hasTangentsAndBitangents()); + assert(afOut.length >= 3); + assert(iOutBase + 3 <= afOut.length); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vTangents) this.mapTangents(); + + iIndex *= 3; + afOut[iOutBase] = this.m_vTangents[iIndex]; + afOut[iOutBase + 1] = this.m_vTangents[iIndex + 1]; + afOut[iOutBase + 2] = this.m_vTangents[iIndex + 2]; + } + + /** + * Provides direct access to the vertex tangent array of the mesh + * This is the recommended way of accessing the data. + * + * @return Array of floats, size is numverts * 3. Component ordering + * is xyz. + */ + public float[] getTangentArray() { + assert(this.hasTangentsAndBitangents()); + if (null == this.m_vTangents) this.mapTangents(); + return this.m_vTangents; + } + + /** + * Get a vertex bitangent in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * Receives the vertex bitangent components in x,y,z order + */ + public void getBitangent(int iIndex, float[] afOut) { + assert(this.hasTangentsAndBitangents()); + assert(afOut.length >= 3); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vBitangents) this.mapBitangents(); + + iIndex *= 3; + afOut[0] = this.m_vBitangents[iIndex]; + afOut[1] = this.m_vBitangents[iIndex + 1]; + afOut[2] = this.m_vBitangents[iIndex + 2]; + } + + /** + * Get a vertex bitangent in the mesh + * + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be 3 + * @param iOutBase Start index in the output array + * Receives the vertex bitangent components in x,y,z order + */ + public void getBitangent(int iIndex, float[] afOut, int iOutBase) { + assert(this.hasTangentsAndBitangents()); + assert(afOut.length >= 3); + assert(iOutBase + 3 <= afOut.length); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_vBitangents) this.mapBitangents(); + + iIndex *= 3; + afOut[iOutBase] = this.m_vBitangents[iIndex]; + afOut[iOutBase + 1] = this.m_vBitangents[iIndex + 1]; + afOut[iOutBase + 2] = this.m_vBitangents[iIndex + 2]; + } + + /** + * Provides direct access to the vertex bitangent array of the mesh + * This is the recommended way of accessing the data. + * + * @return Array of floats, size is numverts * 3. Component ordering + * is xyz. + */ + public float[] getBitangentArray() { + assert(this.hasTangentsAndBitangents()); + if (null == this.m_vBitangents) this.mapBitangents(); + return this.m_vBitangents; + } + + /** + * Get a vertex texture coordinate in the mesh + * + * @param channel Texture coordinate channel + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be equal to the value + * getNumUVComponents returns for channel + * Receives the vertex texture coordinate, components are in u,v,w order + */ + public void getTexCoord(int channel, int iIndex, float[] afOut) { + assert(this.hasUVCoords(channel)); + assert(afOut.length >= this.m_aiNumUVComponents[channel]); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_avUVs[channel]) this.mapUVs(channel); + + iIndex *= this.m_aiNumUVComponents[channel]; + for (int i = 0; i < this.m_aiNumUVComponents[channel];++i) { + afOut[i] = this.m_avUVs[channel][iIndex+i]; + } + } + + /** + * Get a vertex texture coordinate in the mesh + * + * @param channel Texture coordinate channel + * @param iIndex Zero-based index of the vertex + * @param afOut Output array, size must at least be equal to the value + * getNumUVComponents returns for channel + * Receives the vertex texture coordinate, components are in u,v,w order + * @param iOutBase Start index in the output array + */ + public void getTexCoord(int channel, int iIndex, float[] afOut, int iOutBase) { + assert(this.hasUVCoords(channel)); + assert(afOut.length >= this.m_aiNumUVComponents[channel]); + assert(iOutBase + this.m_aiNumUVComponents[channel] <= afOut.length); + assert(iIndex < this.getNumVertices()); // explicitly assert here, no AIOOBE + + if (null == this.m_avUVs[channel]) this.mapUVs(channel); + + iIndex *= this.m_aiNumUVComponents[channel]; + for (int i = 0; i < this.m_aiNumUVComponents[channel];++i) { + afOut[i+iOutBase] = this.m_avUVs[channel][iIndex+i]; + } + } + + /** + * Provides direct access to a texture coordinate channel of the mesh + * This is the recommended way of accessing the data. + * + * @return Array of floats, size is numverts * getNumUVComponents + * (channel). Component ordering is uvw. + */ + public float[] getTexCoordArray(int channel) { + assert(this.hasUVCoords(channel)); + if (null == this.m_avUVs[channel]) this.mapUVs(channel); + return this.m_avUVs[channel]; } protected void OnMap() throws NativeError { + // map all vertex component arrays into our memory + } + + + /** + * JNI bridge function - for internal use only + * Retrieve a bit combination which indicates which vertex + * components are existing in the model. + * + * @param context Current importer context (imp.hashCode) + * @return Combination of the PF_XXX constants + */ + private native int _NativeGetPresenceFlags(long context); + + /** + * JNI bridge function - for internal use only + * Retrieve the number of vertices in the mesh + * + * @param context Current importer context (imp.hashCode) + * @return Number of vertices in the mesh + */ + private native int _NativeGetNumVertices(long context); + + /** + * JNI bridge function - for internal use only + * Retrieve the number of uvw components for a channel + * + * @param context Current importer context (imp.hashCode) + * @param out Output array. Size must be MAX_NUMBER_OF_TEXTURECOORDS. + * @return 0xffffffff if an error occured + */ + private native int _NativeGetNumUVComponents(long context, int[] out); } diff --git a/port/jAssimp/src/assimp/Scene.java b/port/jAssimp/src/assimp/Scene.java index 2317573af..6238b7432 100644 --- a/port/jAssimp/src/assimp/Scene.java +++ b/port/jAssimp/src/assimp/Scene.java @@ -124,88 +124,92 @@ public class Scene { /** * Used to initialize the class instance. Called by Importer. Will maybe * be replaced with a RAII solution ... + * * @return true if we're successful */ - protected boolean construct() { + protected void construct() throws NativeError { int i; - // load all meshes - int iTemp = this._NativeGetNumMeshes(imp.hashCode()); - if (0xffffffff == iTemp) return false; - this.m_vMeshes.setSize(iTemp); - // Mesh, Animation, Texture, Material and Node constructors // throw exceptions if they fail - try { - for (i = 0; i < iTemp; ++i) { - this.m_vMeshes.set(i, new Mesh(this, i)); - } - - // load all animations - iTemp = this._NativeGetNumAnimations(imp.hashCode()); - if (0xffffffff == iTemp) return false; - this.m_vAnimations.setSize(iTemp); - - for (i = 0; i < iTemp; ++i) { - this.m_vAnimations.set(i, new Animation(this, i)); - } - - // load all textures - iTemp = this._NativeGetNumTextures(imp.hashCode()); - if (0xffffffff == iTemp) return false; - this.m_vTextures.setSize(iTemp); - - for (i = 0; i < iTemp; ++i) { - this.m_vTextures.set(i, new Texture(this, i)); - } - - // load all materials - iTemp = this._NativeGetNumMaterials(imp.hashCode()); - if (0xffffffff == iTemp) return false; - this.m_vMaterials.setSize(iTemp); - - for (i = 0; i < iTemp; ++i) { - this.m_vMaterials.set(i, new Material(this, i)); - } - - // now load all nodes - //this.m_rootNode = new Node(this, 0xffffffff); + // load all meshes + int iTemp = this._NativeGetNumMeshes(imp.hashCode()); + if (0xffffffff == iTemp) throw new NativeError("Unable to obtain number of meshes in the scene"); + this.m_vMeshes.setSize(iTemp); + for (i = 0; i < iTemp; ++i) { + this.m_vMeshes.set(i, new Mesh(this, i)); } - catch (Exception ex) { - // LOG - return false; + + // load all animations + iTemp = this._NativeGetNumAnimations(imp.getContext()); + if (0xffffffff == iTemp) throw new NativeError("Unable to obtain number of animations in the scene"); + this.m_vAnimations.setSize(iTemp); + + for (i = 0; i < iTemp; ++i) { + this.m_vAnimations.set(i, new Animation(this, i)); } - return true; + + // load all textures + iTemp = this._NativeGetNumTextures(imp.getContext()); + if (0xffffffff == iTemp) throw new NativeError("Unable to obtain number of textures in the scene"); + this.m_vTextures.setSize(iTemp); + + for (i = 0; i < iTemp; ++i) { + this.m_vTextures.set(i, new Texture(this, i)); + } + + // load all materials + iTemp = this._NativeGetNumMaterials(imp.getContext()); + if (0xffffffff == iTemp) throw new NativeError("Unable to obtain number of materials in the scene"); + this.m_vMaterials.setSize(iTemp); + + for (i = 0; i < iTemp; ++i) { + this.m_vMaterials.set(i, new Material(this, i)); + } + + // now load all nodes + //this.m_rootNode = new Node(this, 0xffffffff); + + + return; } - /** JNI bridge function - for internal use only + /** + * JNI bridge function - for internal use only * Retrieve the number of meshes in a scene + * * @param context Current importer context (imp.hashCode) - * @return Number of meshes in the scene that belongs to the context + * @return Number of meshes in the scene that belongs to the context */ - private native int _NativeGetNumMeshes(int context); + private native int _NativeGetNumMeshes(long context); - /** JNI bridge function - for internal use only + /** + * JNI bridge function - for internal use only * Retrieve the number of animations in a scene + * * @param context Current importer context (imp.hashCode) - * @return Number of animations in the scene that belongs to the context + * @return Number of animations in the scene that belongs to the context */ - private native int _NativeGetNumAnimations(int context); + private native int _NativeGetNumAnimations(long context); - /** JNI bridge function - for internal use only + /** + * JNI bridge function - for internal use only * Retrieve the number of textures in a scene + * * @param context Current importer context (imp.hashCode) - * @return Number of textures in the scene that belongs to the context + * @return Number of textures in the scene that belongs to the context */ - private native int _NativeGetNumTextures(int context); + private native int _NativeGetNumTextures(long context); - /** JNI bridge function - for internal use only + /** + * JNI bridge function - for internal use only * Retrieve the number of materials in a scene + * * @param context Current importer context (imp.hashCode) - * @return Number of materials in the scene that belongs to the context + * @return Number of materials in the scene that belongs to the context */ - private native int _NativeGetNumMaterials(int context); + private native int _NativeGetNumMaterials(long context); } diff --git a/workspaces/jidea5.1/jAssimp.ipr b/workspaces/jidea5.1/jAssimp.ipr index 0fd5cf8bc..20eae075e 100644 --- a/workspaces/jidea5.1/jAssimp.ipr +++ b/workspaces/jidea5.1/jAssimp.ipr @@ -49,18 +49,18 @@