Sfoglia il codice sorgente

Merge branch 'master' into adsk-contrib-fix-std-stream-overflow

ndotl 8 anni fa
parent
commit
00e13ccd77

+ 2 - 0
.gitignore

@@ -81,3 +81,5 @@ lib64/assimp-vc120-mtd.ilk
 lib64/assimp-vc120-mtd.exp
 lib64/assimp-vc120-mt.exp
 xcuserdata
+
+cmake-build-debug

+ 172 - 9
port/jassimp/jassimp-native/src/jassimp.cpp

@@ -214,7 +214,7 @@ static bool getStaticField(JNIEnv *env, const char* className, const char* field
 		return false;
 	}
 
-	jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature);
+	jfieldID fieldId = env->GetStaticFieldID(clazz, fieldName, signature);
 
 	if (NULL == fieldId)
 	{
@@ -1005,8 +1005,164 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 	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);
 
-static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobject* loadedNode = NULL) 
+        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());
 
@@ -1019,7 +1175,7 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj
 	wrapMatParams[0].l = jMatrixArr;
 	jobject jMatrix;
 	SmartLocalRef refMatrix(env, jMatrix);
-				
+
 	if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapMatParams, jMatrix))
 	{
 		return false;
@@ -1068,12 +1224,19 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj
 		}
 	}
 
-	if (NULL != loadedNode)
-	{
-		*loadedNode = jNode;
-	} else {
-	    env->DeleteLocalRef(jNode);
-	}
+    if (NULL != loadedNode)
+    {
+        if(cNode->mMetaData) {
+            if(!loadMetadata(env, cNode, jNode))
+            {
+                return false;
+            }
+        }
+
+        *loadedNode = jNode;
+    } else {
+        env->DeleteLocalRef(jNode);
+    }
 
 	return true;
 }

+ 118 - 0
port/jassimp/jassimp/src/jassimp/AiMetadataEntry.java

@@ -0,0 +1,118 @@
+package jassimp;
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library - Java Binding (jassimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the following 
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+public class AiMetadataEntry
+{
+   public enum AiMetadataType
+   {
+      AI_BOOL, AI_INT32, AI_UINT64, AI_FLOAT, AI_DOUBLE, AI_AISTRING, AI_AIVECTOR3D
+   }
+
+   private AiMetadataType mType;
+   private Object mData;
+
+   public AiMetadataType getMetaDataType()
+   {
+      return mType;
+   }
+
+   public Object getData()
+   {
+      return mData;
+   }
+
+   public static boolean getAiBoolAsBoolean(AiMetadataEntry metadataEntry)
+   {
+      checkTypeBeforeCasting(metadataEntry, AiMetadataType.AI_BOOL);
+
+      return (boolean) metadataEntry.mData;
+   }
+
+   public static int getAiInt32AsInteger(AiMetadataEntry metadataEntry)
+   {
+      checkTypeBeforeCasting(metadataEntry, AiMetadataType.AI_INT32);
+
+      return (int) metadataEntry.mData;
+   }
+
+   public static long getAiUint64AsLong(AiMetadataEntry metadataEntry)
+   {
+      checkTypeBeforeCasting(metadataEntry, AiMetadataType.AI_UINT64);
+
+      return (long) metadataEntry.mData;
+   }
+
+   public static float getAiFloatAsFloat(AiMetadataEntry metadataEntry)
+   {
+      checkTypeBeforeCasting(metadataEntry, AiMetadataType.AI_FLOAT);
+
+      return (float) metadataEntry.mData;
+   }
+
+   public static double getAiDoubleAsDouble(AiMetadataEntry metadataEntry)
+   {
+      checkTypeBeforeCasting(metadataEntry, AiMetadataType.AI_DOUBLE);
+
+      return (double) metadataEntry.mData;
+   }
+
+   public static String getAiStringAsString(AiMetadataEntry metadataEntry)
+   {
+      checkTypeBeforeCasting(metadataEntry, AiMetadataType.AI_AISTRING);
+
+      return (String) metadataEntry.mData;
+   }
+
+   public static AiVector getAiAiVector3DAsAiVector(AiMetadataEntry metadataEntry)
+   {
+      checkTypeBeforeCasting(metadataEntry, AiMetadataType.AI_AIVECTOR3D);
+
+      return (AiVector) metadataEntry.mData;
+   }
+
+   private static void checkTypeBeforeCasting(AiMetadataEntry entry, AiMetadataType expectedType)
+   {
+      if(entry.mType != expectedType)
+      {
+         throw new RuntimeException("Cannot cast entry of type " + entry.mType.name() + " to " + expectedType.name());
+      }
+   }
+}

+ 19 - 0
port/jassimp/jassimp/src/jassimp/AiNode.java

@@ -41,7 +41,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 package jassimp;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -185,6 +187,18 @@ public final class AiNode {
     public int[] getMeshes() {
         return m_meshReferences;
     }
+
+    /**
+     * Returns the metadata entries for this node.<p>
+     *
+     * Consult the original Doxygen for importer_notes to
+     * see which formats have metadata and what to expect.
+     *
+     * @return A map of metadata names to entries.
+     */
+    public Map<String, AiMetadataEntry> getMetadata() {
+        return m_metaData;
+    }
     
     
     /**
@@ -219,6 +233,11 @@ public final class AiNode {
      * List of children.
      */
     private final List<AiNode> m_children = new ArrayList<AiNode>();
+
+    /**
+     * List of metadata entries.
+     */
+     private final Map<String, AiMetadataEntry> m_metaData = new HashMap<String, AiMetadataEntry>();
     
     
     /**

+ 25 - 0
test/unit/utObjImportExport.cpp

@@ -280,3 +280,28 @@ TEST_F( utObjImportExport, issue1453_segfault ) {
     const aiScene *scene = myimporter.ReadFileFromMemory( ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure );
     EXPECT_EQ( nullptr, scene );
 }
+
+TEST_F(utObjImportExport, relative_indices_Test) {
+    static const std::string ObjModel =
+        "v -0.500000 0.000000 0.400000\n"
+        "v -0.500000 0.000000 -0.800000\n"
+        "v -0.500000 1.000000 -0.800000\n"
+        "v -0.500000 1.000000 0.400000\n"
+        "f -4 -3 -2 -1\nB";
+
+    Assimp::Importer myimporter;
+    const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure);
+    EXPECT_NE(nullptr, scene);
+
+    EXPECT_EQ(scene->mNumMeshes, 1);
+    const aiMesh *mesh = scene->mMeshes[0];
+    EXPECT_EQ(mesh->mNumVertices, 4);
+    EXPECT_EQ(mesh->mNumFaces, 1);
+    const aiFace face = mesh->mFaces[0];
+    EXPECT_EQ(face.mNumIndices, 4);
+    for (unsigned int i = 0; i < face.mNumIndices; ++i)
+    {
+        EXPECT_EQ(face.mIndices[i], i);
+    }
+
+}