diff options
Diffstat (limited to 'libs/assimp/port')
202 files changed, 27214 insertions, 0 deletions
diff --git a/libs/assimp/port/AndroidJNI/AndroidJNIIOSystem.cpp b/libs/assimp/port/AndroidJNI/AndroidJNIIOSystem.cpp new file mode 100644 index 0000000..e0f8123 --- /dev/null +++ b/libs/assimp/port/AndroidJNI/AndroidJNIIOSystem.cpp @@ -0,0 +1,210 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2021, 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. +--------------------------------------------------------------------------- +*/ + +/** @file Android extension of DefaultIOSystem using the standard C file functions */ + + +#include <assimp/config.h> +#include <android/api-level.h> +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + +#include <libgen.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <android/log.h> +#include <android/asset_manager.h> +#include <android/asset_manager_jni.h> +#include <android/native_activity.h> +#include <assimp/ai_assert.h> +#include <assimp/port/AndroidJNI/AndroidJNIIOSystem.h> +#include <assimp/DefaultIOStream.h> +#include <fstream> + +using namespace Assimp; + +// ------------------------------------------------------------------------------------------------ +// Constructor. +AndroidJNIIOSystem::AndroidJNIIOSystem(ANativeActivity* activity) +{ + AndroidActivityInit(activity); +} + +AndroidJNIIOSystem::AndroidJNIIOSystem(const char *internalPath, AAssetManager* assetManager) : + mApkWorkspacePath(internalPath), + mApkAssetManager(assetManager) { + // empty +} + +// ------------------------------------------------------------------------------------------------ +// Destructor. +AndroidJNIIOSystem::~AndroidJNIIOSystem() { + // nothing to do here +} + +// ------------------------------------------------------------------------------------------------ +// Tests for the existence of a file at the given path. +bool AndroidJNIIOSystem::Exists( const char* pFile) const { + AAsset* asset = AAssetManager_open(mApkAssetManager, pFile, AASSET_MODE_UNKNOWN); + FILE* file = ::fopen( (mApkWorkspacePath + getOsSeparator() + std::string(pFile)).c_str(), "rb"); + + if (!asset && !file) { + __android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset manager can not find: %s", pFile); + return false; + } + + __android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset exists"); + if (file) { + ::fclose( file); + } + + return true; +} + +// ------------------------------------------------------------------------------------------------ +// Inits Android extractor +void AndroidJNIIOSystem::AndroidActivityInit(ANativeActivity* activity) { + if (activity == nullptr) { + return; + } + mApkWorkspacePath = activity->internalDataPath; + mApkAssetManager = activity->assetManager; +} + +// ------------------------------------------------------------------------------------------------ +// Create the directory for the extracted resource +static int mkpath(std::string path, mode_t mode) { + if (mkdir(path.c_str(), mode) == -1) { + switch(errno) { + case ENOENT: + if (mkpath(path.substr(0, path.find_last_of('/')), mode) == -1) + return -1; + else + return mkdir(path.c_str(), mode); + case EEXIST: + return 0; + default: + return -1; + } + } + + return 0; +} + +// ------------------------------------------------------------------------------------------------ +// Extracts android asset +bool AndroidJNIIOSystem::AndroidExtractAsset(std::string name) { + std::string newPath = mApkWorkspacePath + getOsSeparator() + name; + + DefaultIOSystem io; + + // Do not extract if extracted already + if ( io.Exists(newPath.c_str()) ) { + __android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset already extracted"); + return true; + } + + // Open file + AAsset* asset = AAssetManager_open(mApkAssetManager, name.c_str(), + AASSET_MODE_UNKNOWN); + std::vector<char> assetContent; + + if (asset != NULL) { + // Find size + off_t assetSize = AAsset_getLength(asset); + + // Prepare input buffer + assetContent.resize(assetSize); + + // Store input buffer + AAsset_read(asset, &assetContent[0], assetSize); + + // Close + AAsset_close(asset); + + // Prepare directory for output buffer + std::string directoryNewPath = newPath; + directoryNewPath = dirname(&directoryNewPath[0]); + + if (mkpath(directoryNewPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) { + __android_log_print(ANDROID_LOG_ERROR, "assimp", "Can not create the directory for the output file"); + } + + // Prepare output buffer + std::ofstream assetExtracted(newPath.c_str(), std::ios::out | std::ios::binary); + if (!assetExtracted) { + __android_log_print(ANDROID_LOG_ERROR, "assimp", "Can not open output file"); + } + + // Write output buffer into a file + assetExtracted.write(&assetContent[0], assetContent.size()); + assetExtracted.close(); + + __android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset extracted"); + } else { + __android_log_print(ANDROID_LOG_ERROR, "assimp", "Asset not found: %s", name.c_str()); + return false; + } + + return true; +} + +// ------------------------------------------------------------------------------------------------ +// Open a new file with a given path. +IOStream* AndroidJNIIOSystem::Open( const char* strFile, const char* strMode) { + ai_assert(nullptr != strFile); + ai_assert(nullptr != strMode); + + std::string fullPath(mApkWorkspacePath + getOsSeparator() + std::string(strFile)); + if (Exists(strFile)) { + AndroidExtractAsset(std::string(strFile)); + } + + FILE* file = ::fopen( fullPath.c_str(), strMode); + if (nullptr == file) { + return nullptr; + } + + __android_log_print(ANDROID_LOG_ERROR, "assimp", "AndroidIOSystem: file %s opened", fullPath.c_str()); + return new DefaultIOStream(file, fullPath); +} + +#undef PATHLIMIT +#endif // __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) diff --git a/libs/assimp/port/AndroidJNI/BundledAssetIOSystem.cpp b/libs/assimp/port/AndroidJNI/BundledAssetIOSystem.cpp new file mode 100644 index 0000000..39daf99 --- /dev/null +++ b/libs/assimp/port/AndroidJNI/BundledAssetIOSystem.cpp @@ -0,0 +1,80 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2021, 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. +--------------------------------------------------------------------------- +*/ + +/** @file Android extension of DefaultIOSystem using the standard C file functions */ + +#include <assimp/ai_assert.h> +#include <android/asset_manager.h> +#include <assimp/DefaultIOStream.h> + +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + +#include <assimp/port/AndroidJNI/BundledAssetIOSystem.h> + +using namespace Assimp; + +/** Tests for the existence of a file at the given path. */ +bool BundledAssetIOSystem::Exists(const char* pFile) const { + ai_assert(NULL != mApkAssetManager); + AAsset * asset = AAssetManager_open(mApkAssetManager, pFile, AASSET_MODE_UNKNOWN); + if (!asset) { return false; } + if (asset) AAsset_close(asset); + return true; +} + +// ------------------------------------------------------------------- +/** Open a new file with a given path. */ +Assimp::IOStream* BundledAssetIOSystem::Open(const char* pFile, const char* pMode) { + ai_assert(NULL != mApkAssetManager); + AAsset * asset = AAssetManager_open(mApkAssetManager, pFile, AASSET_MODE_UNKNOWN); + if (!asset) { return NULL; } + + return new AssetIOStream(asset); +} + +// ------------------------------------------------------------------- +/** Closes the given file and releases all resources associated with it. */ +void BundledAssetIOSystem::Close(Assimp::IOStream* pFile) { + delete reinterpret_cast<AssetIOStream *>(pFile); +} + +#endif // __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + diff --git a/libs/assimp/port/AndroidJNI/CMakeLists.txt b/libs/assimp/port/AndroidJNI/CMakeLists.txt new file mode 100644 index 0000000..8c821c7 --- /dev/null +++ b/libs/assimp/port/AndroidJNI/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.10) + +include_directories(./) +include_directories(./../../) +add_library( # Defines the name of the library. + android_jniiosystem + + # Implements a static library. + STATIC + + # relative path to source file(s). + AndroidJNIIOSystem.cpp + BundledAssetIOSystem.cpp +) +TARGET_LINK_LIBRARIES(android_jniiosystem android log) +INSTALL(TARGETS android_jniiosystem EXPORT "${TARGETS_EXPORT_NAME}") diff --git a/libs/assimp/port/AndroidJNI/README.md b/libs/assimp/port/AndroidJNI/README.md new file mode 100644 index 0000000..003b1da --- /dev/null +++ b/libs/assimp/port/AndroidJNI/README.md @@ -0,0 +1,32 @@ +Build Asset Importer Lib for Android +==================================== +This module provides a facade for the io-stream-access to files behind the android-asset-management within +an Android-native application. +- It is built as a static library +- It requires Android NDK with android API > 9 support. + +### Building ### +To use this module please provide following cmake defines: +``` +-DASSIMP_ANDROID_JNIIOSYSTEM=ON +-DCMAKE_TOOLCHAIN_FILE=$SOME_PATH/android.toolchain.cmake +``` + +"SOME_PATH" is a path to your cmake android toolchain script. + + +The build script for this port is based on [android-cmake](https://github.com/taka-no-me/android-cmake). +See its documentation for more Android-specific cmake options (e.g. -DANDROID_ABI for the target ABI). +Check [Asset-Importer-Docs](https://assimp-docs.readthedocs.io/en/latest/) for more information. + +### Code ### +A small example how to wrap assimp for Android: +```cpp +#include <assimp/port/AndroidJNI/AndroidJNIIOSystem.h> + +Assimp::Importer* importer = new Assimp::Importer(); +Assimp::AndroidJNIIOSystem *ioSystem = new Assimp::AndroidJNIIOSystem(app->activity); +if ( nullptr != iosSystem ) { + importer->SetIOHandler(ioSystem); +} +``` diff --git a/libs/assimp/port/AssimpDelphi/Readme.txt b/libs/assimp/port/AssimpDelphi/Readme.txt new file mode 100644 index 0000000..1ec6d21 --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/Readme.txt @@ -0,0 +1,6 @@ +This is a set of Delphi units for using the Assimp C DLL. This was created for use with Delphi 7, but should be usable as-is or with minimal modifications with later Delphi versions. + +This set of headers is enough to load and display a model with external textures. Since I'm not familiar with animated models and some of the other functionality of the assimp library, I did not convert the headers for those features. + +See http://sourceforge.net/tracker/?func=detail&aid=3212646&group_id=226462&atid=1067634 for the original patch + diff --git a/libs/assimp/port/AssimpDelphi/aiColor4D.pas b/libs/assimp/port/AssimpDelphi/aiColor4D.pas new file mode 100644 index 0000000..0bc5d2a --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiColor4D.pas @@ -0,0 +1,17 @@ +unit aiColor4D;
+
+interface
+
+const AI_MAX_NUMBER_OF_COLOR_SETS = $04;
+
+type TaiColor4D = packed record
+ r, g, b, a: single;
+end;
+type PaiColor4D = ^TaiColor4D;
+
+type TaiColor4DArray = array[0..0] of TaiColor4D;
+type PTaiColor4DArray = ^TaiColor4DArray;
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiMaterial.pas b/libs/assimp/port/AssimpDelphi/aiMaterial.pas new file mode 100644 index 0000000..ffd8109 --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiMaterial.pas @@ -0,0 +1,153 @@ +unit aiMaterial;
+
+interface
+
+uses aiTypes, aiVector2D, aiVector3D;
+
+{This following directive causes enums to be stored as double words (32bit), to be compatible with
+ the assimp C Dll}
+{$Z4}
+
+type TaiTextureOp = (
+ aiTextureOp_Multiply = $0,
+ aiTextureOp_Add = $1,
+ aiTextureOp_Subtract = $2,
+ aiTextureOp_Divide = $3,
+ aiTextureOp_SmoothAdd = $4,
+ aiTextureOp_SignedAdd = $5
+ //_aiTextureOp_Force32Bit = 0x9fffffff
+);
+
+type TaiTextureMapMode = (
+ aiTextureMapMode_Wrap = $0,
+ aiTextureMapMode_Clamp = $1,
+ aiTextureMapMode_Decal = $3,
+ aiTextureMapMode_Mirror = $2
+ //_aiTextureMapMode_Force32Bit = 0x9fffffff
+);
+
+type TaiTextureMapping = (
+ aiTextureMapping_UV = $0,
+ aiTextureMapping_SPHERE = $1,
+ aiTextureMapping_CYLINDER = $2,
+ aiTextureMapping_BOX = $3,
+ aiTextureMapping_PLANE = $4,
+ aiTextureMapping_OTHER = $5
+ //_aiTextureMapping_Force32Bit = 0x9fffffff
+);
+
+type TaiTextureType = (
+ aiTextureType_NONE = $0,
+ aiTextureType_DIFFUSE = $1,
+ aiTextureType_SPECULAR = $2,
+ aiTextureType_AMBIENT = $3,
+ aiTextureType_EMISSIVE = $4,
+ aiTextureType_HEIGHT = $5,
+ aiTextureType_NORMALS = $6,
+ aiTextureType_SHININESS = $7,
+ aiTextureType_OPACITY = $8,
+ aiTextureType_DISPLACEMENT = $9,
+ aiTextureType_LIGHTMAP = $A,
+ aiTextureType_REFLECTION = $B,
+ aiTextureType_UNKNOWN = $C
+ //_aiTextureType_Force32Bit = 0x9fffffff
+);
+
+const AI_TEXTURE_TYPE_MAX = aiTextureType_UNKNOWN;
+
+type TaiShadingMode = (
+ aiShadingMode_Flat = $1,
+ aiShadingMode_Gouraud = $2,
+ aiShadingMode_Phong = $3,
+ aiShadingMode_Blinn = $4,
+ aiShadingMode_Toon = $5,
+ aiShadingMode_OrenNayar = $6,
+ aiShadingMode_Minnaert = $7,
+ aiShadingMode_CookTorrance = $8,
+ aiShadingMode_NoShading = $9,
+ aiShadingMode_Fresnel = $A
+ //_aiShadingMode_Force32Bit = 0x9fffffff
+);
+
+
+type TaiTextureFlags = (
+ aiTextureFlags_Invert = $1,
+ aiTextureFlags_UseAlpha = $2,
+ aiTextureFlags_IgnoreAlpha = $4
+ //_aiTextureFlags_Force32Bit = 0x9fffffff
+);
+
+type TaiBlendMode = (
+ aiBlendMode_Default = $0,
+ aiBlendMode_Additive = $1
+ //_aiBlendMode_Force32Bit = 0x9fffffff
+);
+
+type TaiUVTransform = packed record
+ mTranslation: TaiVector2D;
+ mScaling: TaiVector2D;
+ mRotation: single;
+end;
+
+type TaiPropertyTypeInfo = (
+ aiPTI_Float = $1,
+ aiPTI_String = $3,
+ aiPTI_Integer = $4,
+ aiPTI_Buffer = $5
+ // _aiPTI_Force32Bit = 0x9fffffff
+);
+
+type TaiMaterialProperty = packed record
+ mKey: aiString;
+ mSemantic: Cardinal;
+ mIndex: Cardinal;
+ mDataLength: Cardinal;
+ mType: TaiPropertyTypeInfo;
+ mData: PChar;
+end;
+type PaiMaterialProperty = ^TaiMaterialProperty;
+
+type TaiMaterial = packed record
+ mProperties: pointer;
+ mNumProperties: Cardinal;
+ mNumAllocated: Cardinal;
+end;
+type PaiMaterial = ^TaiMaterial;
+type PaiMaterialArray = array[0..0] of PaiMaterial;
+type PPaiMaterialArray = ^PaiMaterialArray;
+
+const AI_MATKEY_NAME = '?mat.name';
+const AI_MATKEY_TWOSIDED = '$mat.twosided';
+const AI_MATKEY_SHADING_MODEL = '$mat.shadingm';
+const AI_MATKEY_ENABLE_WIREFRAME = '$mat.wireframe';
+const AI_MATKEY_BLEND_FUNC = '$mat.blend';
+const AI_MATKEY_OPACITY = '$mat.opacity';
+const AI_MATKEY_BUMPSCALING = '$mat.bumpscaling';
+const AI_MATKEY_SHININESS = '$mat.shininess';
+const AI_MATKEY_REFLECTIVITY = '$mat.reflectivity';
+const AI_MATKEY_SHININESS_STRENGTH = '$mat.shinpercent';
+const AI_MATKEY_REFRACTI = '$mat.refracti';
+const AI_MATKEY_COLOR_DIFFUSE = '$clr.diffuse';
+const AI_MATKEY_COLOR_AMBIENT = '$clr.ambient';
+const AI_MATKEY_COLOR_SPECULAR = '$clr.specular';
+const AI_MATKEY_COLOR_EMISSIVE = '$clr.emissive';
+const AI_MATKEY_COLOR_TRANSPARENT = '$clr.transparent';
+const AI_MATKEY_COLOR_REFLECTIVE = '$clr.reflective';
+const AI_MATKEY_GLOBAL_BACKGROUND_IMAGE = '?bg.global';
+
+const _AI_MATKEY_TEXTURE_BASE = '$tex.file';
+const _AI_MATKEY_UVWSRC_BASE = '$tex.uvwsrc';
+const _AI_MATKEY_TEXOP_BASE = '$tex.op';
+const _AI_MATKEY_MAPPING_BASE = '$tex.mapping';
+const _AI_MATKEY_TEXBLEND_BASE = '$tex.blend';
+const _AI_MATKEY_MAPPINGMODE_U_BASE = '$tex.mapmodeu';
+const _AI_MATKEY_MAPPINGMODE_V_BASE = '$tex.mapmodev';
+const _AI_MATKEY_TEXMAP_AXIS_BASE = '$tex.mapaxis';
+const _AI_MATKEY_UVTRANSFORM_BASE = '$tex.uvtrafo';
+const _AI_MATKEY_TEXFLAGS_BASE = '$tex.flags';
+
+
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiMatrix3x3.pas b/libs/assimp/port/AssimpDelphi/aiMatrix3x3.pas new file mode 100644 index 0000000..a90f11f --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiMatrix3x3.pas @@ -0,0 +1,16 @@ +unit aiMatrix3x3;
+
+interface
+
+type TaiMatrix3x3 = packed record
+ a1, a2, a3, a4: single;
+ b1, b2, b3, b4: single;
+ c1, c2, c3, c4: single;
+end;
+PaiMatrix3x3 = ^TaiMatrix3x3;
+
+
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiMatrix4x4.pas b/libs/assimp/port/AssimpDelphi/aiMatrix4x4.pas new file mode 100644 index 0000000..45e0faf --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiMatrix4x4.pas @@ -0,0 +1,16 @@ +unit aiMatrix4x4;
+
+interface
+
+type TaiMatrix4x4 = packed record
+ a1, a2, a3, a4: single;
+ b1, b2, b3, b4: single;
+ c1, c2, c3, c4: single;
+ d1, d2, d3, d4: single;
+end;
+PaiMatrix4x4 = ^TaiMatrix4x4;
+
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiMesh.pas b/libs/assimp/port/AssimpDelphi/aiMesh.pas new file mode 100644 index 0000000..a05a0f2 --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiMesh.pas @@ -0,0 +1,71 @@ +unit aiMesh;
+
+interface
+
+uses aiTypes, aiMatrix4x4, aiVector3D, aiColor4D;
+
+const
+ AI_MAX_NUMBER_OF_COLOR_SETS = $4;
+ AI_MAX_NUMBER_OF_TEXTURECOORDS = $4;
+
+type TaiFace = packed record
+ mNumIndicies: cardinal;
+ mIndices: PCardinalArray;
+end;
+type PaiFace = ^TaiFace;
+type PaiFaceArray = array [0..0] of PaiFace;
+
+type TaiFaceArray = array [0..0] of TaiFace;
+type PTaiFaceArray = ^TaiFaceArray;
+
+type TaiVertexWeight = packed record
+ mVertexId: cardinal;
+ mWeight: single;
+end;
+
+type TaiBone = packed record
+ mName: aiString;
+ mNumWeights: cardinal;
+ mWeights: Pointer;
+ mOffsetMatrix: TaiMatrix4x4;
+end;
+type PaiBone = ^TaiBone;
+
+type TaiPrimitiveType =
+ (
+ aiPrimitiveType_POINT = $1,
+ aiPrimitiveType_LINE = $2,
+ aiPrimitiveType_TRIANGLE = $4,
+ aiPrimitiveType_POLYGON = $8
+ //,_aiPrimitiveType_Force32Bit = $9fffffff
+ );
+
+type TaiMesh = packed record
+ mPrimitiveTypes: cardinal;
+ mNumVertices: cardinal;
+ mNumFaces: cardinal;
+ mVertices: PTaiVector3DArray;
+ mNormals: PTaiVector3DArray;
+ mTangents: PaiVector3DArray;
+ mBitangents: PaiVector3DArray;
+ mColors: array[0..3] of PTaiColor4Darray; //array [0..3] of PaiColor4DArray; //array of 4
+ mTextureCoords: array [0..3] of PTaiVector3DArray; //array of 4
+ mNumUVComponents: array[0..AI_MAX_NUMBER_OF_TEXTURECOORDS -1] of cardinal;
+ mFaces: PTaiFaceArray;
+ mNumBones: cardinal;
+ mBones: PaiBone;
+ mMaterialIndex: cardinal;
+ mName: aiString;
+ mNumAniMeshes: cardinal;
+ mAniMeshes: pointer;
+end;
+type PaiMesh = ^TaiMesh;
+type PPaiMesh = ^PaiMesh;
+type PaiMeshArray = array [0..0] of PaiMesh;
+type PPaiMeshArray = ^PaiMeshArray;
+
+
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiQuaternion.pas b/libs/assimp/port/AssimpDelphi/aiQuaternion.pas new file mode 100644 index 0000000..d5550de --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiQuaternion.pas @@ -0,0 +1,12 @@ +unit aiQuaternion;
+
+interface
+
+type TaiQuaternion = packed record
+ w, x, y, z: single;
+end;
+type PaiQuaternion = ^TaiQuaternion;
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiScene.pas b/libs/assimp/port/AssimpDelphi/aiScene.pas new file mode 100644 index 0000000..28cebf1 --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiScene.pas @@ -0,0 +1,46 @@ +unit aiScene;
+
+interface
+
+uses aiTypes, aiMatrix4x4, aiMesh, aiMaterial, aiTexture;
+
+
+type
+ PaiNode = ^TaiNode;
+ PPaiNode = ^PaiNode;
+ PaiNodeArray = array[0..0] of PaiNode;
+ PPaiNodeArray = ^PaiNodeArray;
+
+ TaiNode = packed record
+ mName: aiString;
+ mTransformation: TaiMatrix4x4;
+ mParent: PPaiNode;
+ mNumChildren: cardinal;
+ mChildren: PPaiNodeArray;
+ mNumMeshes: cardinal;
+ mMeshes: PCardinalArray;
+ end;
+
+
+
+type TaiScene = packed record
+ mFlags: cardinal;
+ mRootNode: PaiNode;
+ mNumMeshes: Cardinal;
+ mMeshes: PPaiMeshArray; //?
+ mNumMaterials: Cardinal;
+ mMaterials: PPaiMaterialArray;
+ mNumAnimations: Cardinal;
+ mAnimations: Pointer;
+ mNumTextures: Cardinal;
+ mTextures: PPaiTextureArray;
+ mNumLights: Cardinal;
+ mLights: Pointer;
+ mNumCameras: Cardinal;
+ mCameras: Pointer;
+end;
+type PaiScene = ^TaiScene;
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiTexture.pas b/libs/assimp/port/AssimpDelphi/aiTexture.pas new file mode 100644 index 0000000..55e246f --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiTexture.pas @@ -0,0 +1,26 @@ +unit aiTexture;
+
+interface
+
+type TaiTexel = packed record
+ b, g, r, a: byte;
+end;
+PaiTexel = ^TaiTexel;
+TaiTexelArray = array[0..0] of TaiTexel;
+PaiTexelArray = ^TaiTexelArray;
+
+type TaiTexture = packed record
+ mWidth: Cardinal; //width in pixels, OR total embedded file size if texture is a jpg/png/etc
+ mHeight: Cardinal; //0 if texture is an embedded file
+ achFormatHint: array[0..3] of byte;
+ pcData: PaiTexelArray;
+end;
+PaiTexture = ^TaiTexture;
+PaiTextureArray = array [0..0] of PaiTexture;
+PPaiTextureArray = ^PaiTextureArray;
+
+
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiTypes.pas b/libs/assimp/port/AssimpDelphi/aiTypes.pas new file mode 100644 index 0000000..b7924e8 --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiTypes.pas @@ -0,0 +1,53 @@ +unit aiTypes;
+
+interface
+
+//added for Delphi interface
+type
+ TCardinalArray = array [0..0] of Cardinal;
+ PCardinalArray = ^TCardinalArray;
+
+ TSingleArray = array[0..0] of Single;
+ PSingleArray = ^TSingleArray;
+
+type aiString = packed record
+ length: Cardinal;
+ data: array [0..1023] of char;
+end;
+type PaiString = ^aiString;
+
+type aiReturn = (
+ aiReturn_SUCCESS = $0,
+ aiReturn_FAILURE = -$1,
+ aiReturn_OUTOFMEMORY = -$3,
+ _AI_ENFORCE_ENUM_SIZE = $7fffffff
+);
+
+const AI_SUCCESS = aiReturn_SUCCESS;
+const AI_FAILURE = aiReturn_FAILURE;
+const AI_OUTOFMEMORY = aiReturn_OUTOFMEMORY;
+
+
+
+
+function aiStringToDelphiString( a: aiString): AnsiString;
+
+
+implementation
+
+function aiStringToDelphiString( a: aiString): AnsiString;
+var
+ i: integer;
+begin
+ result := '';
+ if a.length > 0 then
+ begin
+ SetLength( result, a.length);
+ for i := 1 to a.length do
+ begin
+ result[i] := a.data[i-1];
+ end;
+ end;
+end;
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiVector2D.pas b/libs/assimp/port/AssimpDelphi/aiVector2D.pas new file mode 100644 index 0000000..1e88209 --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiVector2D.pas @@ -0,0 +1,13 @@ +unit aiVector2D;
+
+interface
+
+type TaiVector2D = packed record
+ x, y: single;
+end;
+type PaiVector2D = ^TaiVector2D;
+
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/aiVector3D.pas b/libs/assimp/port/AssimpDelphi/aiVector3D.pas new file mode 100644 index 0000000..2081bb4 --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/aiVector3D.pas @@ -0,0 +1,16 @@ +unit aiVector3D;
+
+interface
+
+type TaiVector3D = packed record
+ x, y, z: single;
+end;
+type PaiVector3D = ^TaiVector3D;
+type PaiVector3DArray = array [0..0] of PaiVector3D;
+
+type TaiVector3DArray = array[0..0] of TaiVector3D;
+type PTaiVector3DArray = ^TaiVector3DArray;
+
+implementation
+
+end.
diff --git a/libs/assimp/port/AssimpDelphi/assimp.pas b/libs/assimp/port/AssimpDelphi/assimp.pas new file mode 100644 index 0000000..d5bf31d --- /dev/null +++ b/libs/assimp/port/AssimpDelphi/assimp.pas @@ -0,0 +1,58 @@ +unit assimp;
+
+interface
+
+uses aiTypes, aiMatrix4x4, aiMatrix3x3, aiMesh, aiScene, aiMaterial, aiColor4d, aiVector3D;
+
+const ASSIMP_DLL = 'assimp32.dll';
+
+function aiImportFile(filename: pchar; pFlags: integer): PaiScene; cdecl; external ASSIMP_DLL;
+procedure aiReleaseImport( pScene: pointer); cdecl; external ASSIMP_DLL;
+function aiGetErrorString(): PChar; cdecl; external ASSIMP_DLL;
+
+//procedure aiDecomposeMatrix( var mat: TaiMatrix4x4; var scaling: TaiVector3D; var rotation: TaiQuaternion; var position: TaiVector3D); cdecl; external ASSIMP_DLL;
+procedure aiTransposeMatrix4( var mat: TaiMatrix4x4); cdecl; external ASSIMP_DLL;
+procedure aiTransposeMatrix3( var mat: TaiMatrix3x3); cdecl; external ASSIMP_DLL;
+procedure aiTransformVecByMatrix3( var vec: TaiVector3D; var mat: TaiMatrix3x3); cdecl; external ASSIMP_DLL;
+procedure aiTransformVecByMatrix4( var vec: TaiVector3D; var mat: TaiMatrix4x4); cdecl; external ASSIMP_DLL;
+
+procedure aiMultiplyMatrix4(var dst: TaiMatrix4x4; var src: TaiMatrix4x4); cdecl; external ASSIMP_DLL;
+procedure aiMultiplyMatrix3(var dst: TaiMatrix3x3; var src: TaiMatrix3x3); cdecl; external ASSIMP_DLL;
+
+
+procedure aiIdentityMatrix3(var mat: TaiMatrix3x3); cdecl; external ASSIMP_DLL;
+procedure aiIdentityMatrix4(var mat: TaiMatrix4x4); cdecl; external ASSIMP_DLL;
+
+
+//----- from aiMaterial.h
+function aiGetMaterialProperty( pMat: PaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; pPropOut: pointer): aiReturn; cdecl; external ASSIMP_DLL;
+function aiGetMaterialFloatArray( var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Single; var pMax: Cardinal): aiReturn; cdecl; external ASSIMP_DLL;
+function aiGetMaterialFloat( var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Single): aiReturn;
+function aiGetMaterialIntegerArray(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Integer; var pMax: Cardinal): aiReturn; cdecl; external ASSIMP_DLL;
+function aiGetMaterialInteger(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Integer): aiReturn;
+function aiGetMaterialColor(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: TaiColor4d): aiReturn; cdecl; external ASSIMP_DLL;
+function aiGetMaterialString(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: aiString): aiReturn; cdecl; external ASSIMP_DLL;
+function aiGetMaterialTextureCount(var pMat: TaiMaterial; nType: TaiTextureType): Cardinal; cdecl; external ASSIMP_DLL;
+function aiGetMaterialTexture(var mat: TaiMaterial; nType: TaiTextureType; nIndex: Cardinal; var path: aiString; var mapping: TaiTextureMapping; var uvindex: Cardinal; var blend: single; var op: TaiTextureOp; var mapmode: TaiTextureMapMode; var flags: Cardinal): aiReturn; cdecl; external ASSIMP_DLL;
+
+
+
+implementation
+
+function aiGetMaterialFloat( var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Single): aiReturn;
+var
+ n: cardinal;
+begin
+ n := 0;
+ result := aiGetMaterialFloatArray( pMat, pKey, nType, nIndex, pOut, n);
+end;
+
+function aiGetMaterialInteger(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: integer): aiReturn;
+var
+ n: cardinal;
+begin
+ n := 0;
+ result := aiGetMaterialIntegerArray( pMat, pKey, nType, nIndex, pOut, n);
+end;
+
+end.
diff --git a/libs/assimp/port/AssimpNET/Readme.md b/libs/assimp/port/AssimpNET/Readme.md new file mode 100644 index 0000000..814cab3 --- /dev/null +++ b/libs/assimp/port/AssimpNET/Readme.md @@ -0,0 +1 @@ +Please check the following git-repo for the source: https://github.com/kebby/assimp-net diff --git a/libs/assimp/port/AssimpPascal/Readme.md b/libs/assimp/port/AssimpPascal/Readme.md new file mode 100644 index 0000000..9dfc652 --- /dev/null +++ b/libs/assimp/port/AssimpPascal/Readme.md @@ -0,0 +1 @@ +See the [AssimpPascal headers here](https://github.com/ev1313/Pascal-Assimp-Headers) (by Tim Blume / ev1313). diff --git a/libs/assimp/port/PyAssimp/3d_viewer_screenshot.png b/libs/assimp/port/PyAssimp/3d_viewer_screenshot.png Binary files differnew file mode 100644 index 0000000..2031faf --- /dev/null +++ b/libs/assimp/port/PyAssimp/3d_viewer_screenshot.png diff --git a/libs/assimp/port/PyAssimp/README.md b/libs/assimp/port/PyAssimp/README.md new file mode 100644 index 0000000..c9944f7 --- /dev/null +++ b/libs/assimp/port/PyAssimp/README.md @@ -0,0 +1,86 @@ +PyAssimp Readme +=============== + +A simple Python wrapper for Assimp using `ctypes` to access the library. +Requires Python >= 2.6. + +Python 3 support is mostly here, but not well tested. + +Note that pyassimp is not complete. Many ASSIMP features are missing. + +USAGE +----- + +### Complete example: 3D viewer + +`pyassimp` comes with a simple 3D viewer that shows how to load and display a 3D +model using a shader-based OpenGL pipeline. + +![Screenshot](3d_viewer_screenshot.png) + +To use it, from within `/port/PyAssimp`: + +```console +$ cd scripts +$ python ./3D-viewer <path to your model> +``` + +You can use this code as starting point in your applications. + +### Writing your own code + +To get started with `pyassimp`, examine the simpler `sample.py` script in `scripts/`, +which illustrates the basic usage. All Assimp data structures are wrapped using +`ctypes`. All the data+length fields in Assimp's data structures (such as +`aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python +lists, so you can call `len()` on them to get their respective size and access +members using `[]`. + +For example, to load a file named `hello.3ds` and print the first +vertex of the first mesh, you would do (proper error handling +substituted by assertions ...): + +```python + +from pyassimp import load +with load('hello.3ds') as scene: + + assert len(scene.meshes) + mesh = scene.meshes[0] + + assert len(mesh.vertices) + print(mesh.vertices[0]) + +``` + +Another example to list the 'top nodes' in a +scene: + +```python + +from pyassimp import load +with load('hello.3ds') as scene: + + for c in scene.rootnode.children: + print(str(c)) + +``` + +INSTALL +------- + +Install `pyassimp` by running: + +```console +$ python setup.py install +``` + +PyAssimp requires a assimp dynamic library (`DLL` on windows, +`.so` on linux, `.dynlib` on macOS) in order to work. The default search directories are: + - the current directory + - on linux additionally: `/usr/lib`, `/usr/local/lib`, + `/usr/lib/x86_64-linux-gnu` + +To build that library, refer to the Assimp master `INSTALL` +instructions. To look in more places, edit `./pyassimp/helper.py`. +There's an `additional_dirs` list waiting for your entries. diff --git a/libs/assimp/port/PyAssimp/README.rst b/libs/assimp/port/PyAssimp/README.rst new file mode 100644 index 0000000..03b7968 --- /dev/null +++ b/libs/assimp/port/PyAssimp/README.rst @@ -0,0 +1,93 @@ +PyAssimp: Python bindings for libassimp +======================================= + +A simple Python wrapper for Assimp using ``ctypes`` to access the +library. Requires Python >= 2.6. + +Python 3 support is mostly here, but not well tested. + +Note that pyassimp is not complete. Many ASSIMP features are missing. + +USAGE +----- + +Complete example: 3D viewer +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``pyassimp`` comes with a simple 3D viewer that shows how to load and +display a 3D model using a shader-based OpenGL pipeline. + +.. figure:: 3d_viewer_screenshot.png + :alt: Screenshot + + Screenshot + +To use it, from within ``/port/PyAssimp``: + +:: + + $ cd scripts + $ python ./3D-viewer <path to your model> + +You can use this code as starting point in your applications. + +Writing your own code +~~~~~~~~~~~~~~~~~~~~~ + +To get started with ``pyassimp``, examine the simpler ``sample.py`` +script in ``scripts/``, which illustrates the basic usage. All Assimp +data structures are wrapped using ``ctypes``. All the data+length fields +in Assimp's data structures (such as ``aiMesh::mNumVertices``, +``aiMesh::mVertices``) are replaced by simple python lists, so you can +call ``len()`` on them to get their respective size and access members +using ``[]``. + +For example, to load a file named ``hello.3ds`` and print the first +vertex of the first mesh, you would do (proper error handling +substituted by assertions ...): + +.. code:: python + + + from pyassimp import load + with load('hello.3ds') as scene: + + assert len(scene.meshes) + mesh = scene.meshes[0] + + assert len(mesh.vertices) + print(mesh.vertices[0]) + + +Another example to list the 'top nodes' in a scene: + +.. code:: python + + + from pyassimp import load + with load('hello.3ds') as scene: + + for c in scene.rootnode.children: + print(str(c)) + + +INSTALL +------- + +Install ``pyassimp`` by running: + +:: + + $ python setup.py install + +PyAssimp requires a assimp dynamic library (``DLL`` on windows, ``.so`` +on linux, ``.dynlib`` on macOS) in order to work. The default search +directories are: + +- the current directory +- on linux additionally: ``/usr/lib``, ``/usr/local/lib``, + ``/usr/lib/x86_64-linux-gnu`` + +To build that library, refer to the Assimp master ``INSTALL`` +instructions. To look in more places, edit ``./pyassimp/helper.py``. +There's an ``additional_dirs`` list waiting for your entries. diff --git a/libs/assimp/port/PyAssimp/gen/materialgen.py b/libs/assimp/port/PyAssimp/gen/materialgen.py new file mode 100644 index 0000000..ef32d8e --- /dev/null +++ b/libs/assimp/port/PyAssimp/gen/materialgen.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# -*- Coding: UTF-8 -*- + +# --------------------------------------------------------------------------- +# Open Asset Import Library (ASSIMP) +# --------------------------------------------------------------------------- +# +# Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +# --------------------------------------------------------------------------- + +"""Update PyAssimp's texture type constants C/C++ headers. + +This script is meant to be executed in the source tree, directly from +port/PyAssimp/gen +""" + +import os +import re + +REenumTextureType = re.compile(r'' + r'enum\saiTextureType' # enum aiTextureType + r'[^{]*?\{' # { + r'(?P<code>.*?)' # code + r'\};' # }; + , re.IGNORECASE + re.DOTALL + re.MULTILINE) + +# Replace comments +RErpcom = re.compile(r'' + r'\s*(/\*+\s|\*+/|\B\*\s?|///?!?)' # /** + r'(?P<line>.*?)' # * line + , re.IGNORECASE + re.DOTALL) + +# Remove trailing commas +RErmtrailcom = re.compile(r',$', re.IGNORECASE + re.DOTALL) + +# Remove #ifdef __cplusplus +RErmifdef = re.compile(r'' + r'#ifndef SWIG' # #ifndef SWIG + r'(?P<code>.*)' # code + r'#endif(\s*//\s*!?\s*SWIG)*' # #endif + , re.IGNORECASE + re.DOTALL) + +path = '../../../include/assimp' + +files = os.listdir (path) +enumText = '' +for fileName in files: + if fileName.endswith('.h'): + text = open(os.path.join(path, fileName)).read() + for enum in REenumTextureType.findall(text): + enumText = enum + +text = '' +for line in enumText.split('\n'): + line = line.lstrip().rstrip() + line = RErmtrailcom.sub('', line) + text += RErpcom.sub('# \g<line>', line) + '\n' +text = RErmifdef.sub('', text) + +file = open('material.py', 'w') +file.write(text) +file.close() + +print("Generation done. You can now review the file 'material.py' and merge it.") diff --git a/libs/assimp/port/PyAssimp/gen/structsgen.py b/libs/assimp/port/PyAssimp/gen/structsgen.py new file mode 100644 index 0000000..f34ec19 --- /dev/null +++ b/libs/assimp/port/PyAssimp/gen/structsgen.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python +# -*- Coding: UTF-8 -*- + +# --------------------------------------------------------------------------- +# Open Asset Import Library (ASSIMP) +# --------------------------------------------------------------------------- +# +# Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +# --------------------------------------------------------------------------- + +"""Update PyAssimp's data structures to keep up with the +C/C++ headers. + +This script is meant to be executed in the source tree, directly from +port/PyAssimp/gen +""" + +import os +import re + +#==[regexps]================================================= + +# Clean desc +REdefine = re.compile(r'' + r'(?P<desc>)' # /** *desc */ + r'#\s*define\s(?P<name>[^(\n]+?)\s(?P<code>.+)$' # #define name value + , re.MULTILINE) + +# Get structs +REstructs = re.compile(r'' + #r'//\s?[\-]*\s(?P<desc>.*?)\*/\s' # /** *desc */ + #r'//\s?[\-]*(?P<desc>.*?)\*/(?:.*?)' # garbage + r'//\s?[\-]*\s(?P<desc>.*?)\*/\W*?' # /** *desc */ + r'struct\s(?:ASSIMP_API\s)?(?P<name>[a-z][a-z0-9_]\w+\b)' # struct name + r'[^{]*?\{' # { + r'(?P<code>.*?)' # code + r'\}\s*(PACK_STRUCT)?;' # }; + , re.IGNORECASE + re.DOTALL + re.MULTILINE) + +# Clean desc +REdesc = re.compile(r'' + r'^\s*?([*]|/\*\*)(?P<line>.*?)' # * line + , re.IGNORECASE + re.DOTALL + re.MULTILINE) + +# Remove #ifdef __cplusplus +RErmifdef = re.compile(r'' + r'#ifdef __cplusplus' # #ifdef __cplusplus + r'(?P<code>.*)' # code + r'#endif(\s*//\s*!?\s*__cplusplus)*' # #endif + , re.IGNORECASE + re.DOTALL) + +# Replace comments +RErpcom = re.compile(r'' + r'\s*(/\*+\s|\*+/|\B\*\s|///?!?)' # /** + r'(?P<line>.*?)' # * line + , re.IGNORECASE + re.DOTALL) + +# Restructure +def GetType(type, prefix='c_'): + t = type + while t.endswith('*'): + t = t[:-1] + if t[:5] == 'const': + t = t[5:] + + # skip some types + if t in skiplist: + return None + + t = t.strip() + types = {'unsigned int':'uint', 'unsigned char':'ubyte',} + if t in types: + t = types[t] + t = prefix + t + while type.endswith('*'): + t = "POINTER(" + t + ")" + type = type[:-1] + return t + +def restructure( match ): + type = match.group("type") + if match.group("struct") == "": + type = GetType(type) + elif match.group("struct") == "C_ENUM ": + type = "c_uint" + else: + type = GetType(type[2:], '') + if type is None: + return '' + if match.group("index"): + type = type + "*" + match.group("index") + + result = "" + for name in match.group("name").split(','): + result += "(\"" + name.strip() + "\", "+ type + ")," + + return result + +RErestruc = re.compile(r'' + r'(?P<struct>C_STRUCT\s|C_ENUM\s|)' # [C_STRUCT] + r'(?P<type>\w+\s?\w+?[*]*)\s' # type + #r'(?P<name>\w+)' # name + r'(?P<name>\w+|[a-z0-9_, ]+)' # name + r'(:?\[(?P<index>\w+)\])?;' # []; (optional) + , re.DOTALL) +#==[template]================================================ +template = """ +class $NAME$(Structure): + \"\"\" +$DESCRIPTION$ + \"\"\" +$DEFINES$ + _fields_ = [ + $FIELDS$ + ] +""" + +templateSR = """ +class $NAME$(Structure): + \"\"\" +$DESCRIPTION$ + \"\"\" +$DEFINES$ + +$NAME$._fields_ = [ + $FIELDS$ + ] +""" + +skiplist = ("FileIO", "File", "locateFromAssimpHeap",'LogStream','MeshAnim','AnimMesh') + +#============================================================ +def Structify(fileName): + file = open(fileName, 'r') + text = file.read() + result = [] + + # Get defines. + defs = REdefine.findall(text) + # Create defines + defines = "\n" + for define in defs: + # Clean desc + desc = REdesc.sub('', define[0]) + # Replace comments + desc = RErpcom.sub('#\g<line>', desc) + defines += desc + if len(define[2].strip()): + # skip non-integral defines, we can support them right now + try: + int(define[2],0) + except: + continue + defines += " "*4 + define[1] + " = " + define[2] + "\n" + + + # Get structs + rs = REstructs.finditer(text) + + fileName = os.path.basename(fileName) + print fileName + for r in rs: + name = r.group('name')[2:] + desc = r.group('desc') + + # Skip some structs + if name in skiplist: + continue + + text = r.group('code') + + # Clean desc + desc = REdesc.sub('', desc) + + desc = "See '"+ fileName +"' for details." #TODO + + # Remove #ifdef __cplusplus + text = RErmifdef.sub('', text) + + # Whether the struct contains more than just POD + primitive = text.find('C_STRUCT') == -1 + + # Restructure + text = RErestruc.sub(restructure, text) + # Replace comments + text = RErpcom.sub('# \g<line>', text) + text = text.replace("),#", "),\n#") + text = text.replace("#", "\n#") + text = "".join([l for l in text.splitlines(True) if not l.strip().endswith("#")]) # remove empty comment lines + + # Whether it's selfreferencing: ex. struct Node { Node* parent; }; + selfreferencing = text.find('POINTER('+name+')') != -1 + + complex = name == "Scene" + + # Create description + description = "" + for line in desc.split('\n'): + description += " "*4 + line.strip() + "\n" + description = description.rstrip() + + # Create fields + fields = "" + for line in text.split('\n'): + fields += " "*12 + line.strip() + "\n" + fields = fields.strip() + + if selfreferencing: + templ = templateSR + else: + templ = template + + # Put it all together + text = templ.replace('$NAME$', name) + text = text.replace('$DESCRIPTION$', description) + text = text.replace('$FIELDS$', fields) + + if ((name.lower() == fileName.split('.')[0][2:].lower()) and (name != 'Material')) or name == "String": + text = text.replace('$DEFINES$', defines) + else: + text = text.replace('$DEFINES$', '') + + + result.append((primitive, selfreferencing, complex, text)) + + return result + +text = "#-*- coding: UTF-8 -*-\n\n" +text += "from ctypes import POINTER, c_int, c_uint, c_size_t, c_char, c_float, Structure, c_char_p, c_double, c_ubyte\n\n" + +structs1 = "" +structs2 = "" +structs3 = "" +structs4 = "" + +path = '../../../include/assimp' +files = os.listdir (path) +#files = ["aiScene.h", "aiTypes.h"] +for fileName in files: + if fileName.endswith('.h'): + for struct in Structify(os.path.join(path, fileName)): + primitive, sr, complex, struct = struct + if primitive: + structs1 += struct + elif sr: + structs2 += struct + elif complex: + structs4 += struct + else: + structs3 += struct + +text += structs1 + structs2 + structs3 + structs4 + +file = open('structs.py', 'w') +file.write(text) +file.close() + +print("Generation done. You can now review the file 'structs.py' and merge it.") diff --git a/libs/assimp/port/PyAssimp/pyassimp/__init__.py b/libs/assimp/port/PyAssimp/pyassimp/__init__.py new file mode 100644 index 0000000..bb67a43 --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/__init__.py @@ -0,0 +1 @@ +from .core import * diff --git a/libs/assimp/port/PyAssimp/pyassimp/core.py b/libs/assimp/port/PyAssimp/pyassimp/core.py new file mode 100644 index 0000000..35ad882 --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/core.py @@ -0,0 +1,556 @@ +""" +PyAssimp + +This is the main-module of PyAssimp. +""" + +import sys +if sys.version_info < (2,6): + raise RuntimeError('pyassimp: need python 2.6 or newer') + +# xrange was renamed range in Python 3 and the original range from Python 2 was removed. +# To keep compatibility with both Python 2 and 3, xrange is set to range for version 3.0 and up. +if sys.version_info >= (3,0): + xrange = range + + +try: + import numpy +except ImportError: + numpy = None +import logging +import ctypes +from contextlib import contextmanager +logger = logging.getLogger("pyassimp") +# attach default null handler to logger so it doesn't complain +# even if you don't attach another handler to logger +logger.addHandler(logging.NullHandler()) + +from . import structs +from . import helper +from . import postprocess +from .errors import AssimpError + +class AssimpLib(object): + """ + Assimp-Singleton + """ + load, load_mem, export, export_blob, release, dll = helper.search_library() +_assimp_lib = AssimpLib() + +def make_tuple(ai_obj, type = None): + res = None + + #notes: + # ai_obj._fields_ = [ ("attr", c_type), ... ] + # getattr(ai_obj, e[0]).__class__ == float + + if isinstance(ai_obj, structs.Matrix4x4): + if numpy: + res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]).reshape((4,4)) + #import pdb;pdb.set_trace() + else: + res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] + res = [res[i:i+4] for i in xrange(0,16,4)] + elif isinstance(ai_obj, structs.Matrix3x3): + if numpy: + res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]).reshape((3,3)) + else: + res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] + res = [res[i:i+3] for i in xrange(0,9,3)] + else: + if numpy: + res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]) + else: + res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] + + return res + +# Returns unicode object for Python 2, and str object for Python 3. +def _convert_assimp_string(assimp_string): + if sys.version_info >= (3, 0): + return str(assimp_string.data, errors='ignore') + else: + return unicode(assimp_string.data, errors='ignore') + +# It is faster and more correct to have an init function for each assimp class +def _init_face(aiFace): + aiFace.indices = [aiFace.mIndices[i] for i in range(aiFace.mNumIndices)] +assimp_struct_inits = { structs.Face : _init_face } + +def call_init(obj, caller = None): + if helper.hasattr_silent(obj,'contents'): #pointer + _init(obj.contents, obj, caller) + else: + _init(obj,parent=caller) + +def _is_init_type(obj): + + if obj and helper.hasattr_silent(obj,'contents'): #pointer + return _is_init_type(obj[0]) + # null-pointer case that arises when we reach a mesh attribute + # like mBitangents which use mNumVertices rather than mNumBitangents + # so it breaks the 'is iterable' check. + # Basically: + # FIXME! + elif not bool(obj): + return False + tname = obj.__class__.__name__ + return not (tname[:2] == 'c_' or tname == 'Structure' \ + or tname == 'POINTER') and not isinstance(obj, (int, str, bytes)) + +def _init(self, target = None, parent = None): + """ + Custom initialize() for C structs, adds safely accessible member functionality. + + :param target: set the object which receive the added methods. Useful when manipulating + pointers, to skip the intermediate 'contents' deferencing. + """ + if not target: + target = self + + dirself = dir(self) + for m in dirself: + + if m.startswith("_"): + continue + + if m.startswith('mNum'): + if 'm' + m[4:] in dirself: + continue # will be processed later on + else: + name = m[1:].lower() + + obj = getattr(self, m) + setattr(target, name, obj) + continue + + if m == 'mName': + target.name = str(_convert_assimp_string(self.mName)) + target.__class__.__repr__ = lambda x: str(x.__class__) + "(" + getattr(x, 'name','') + ")" + target.__class__.__str__ = lambda x: getattr(x, 'name', '') + continue + + name = m[1:].lower() + + obj = getattr(self, m) + + # Create tuples + if isinstance(obj, structs.assimp_structs_as_tuple): + setattr(target, name, make_tuple(obj)) + logger.debug(str(self) + ": Added array " + str(getattr(target, name)) + " as self." + name.lower()) + continue + + if m.startswith('m') and len(m) > 1 and m[1].upper() == m[1]: + + if name == "parent": + setattr(target, name, parent) + logger.debug("Added a parent as self." + name) + continue + + if helper.hasattr_silent(self, 'mNum' + m[1:]): + + length = getattr(self, 'mNum' + m[1:]) + + # -> special case: properties are + # stored as a dict. + if m == 'mProperties': + setattr(target, name, _get_properties(obj, length)) + continue + + + if not length: # empty! + setattr(target, name, []) + logger.debug(str(self) + ": " + name + " is an empty list.") + continue + + + try: + if obj._type_ in structs.assimp_structs_as_tuple: + if numpy: + setattr(target, name, numpy.array([make_tuple(obj[i]) for i in range(length)], dtype=numpy.float32)) + + logger.debug(str(self) + ": Added an array of numpy arrays (type "+ str(type(obj)) + ") as self." + name) + else: + setattr(target, name, [make_tuple(obj[i]) for i in range(length)]) + + logger.debug(str(self) + ": Added a list of lists (type "+ str(type(obj)) + ") as self." + name) + + else: + setattr(target, name, [obj[i] for i in range(length)]) #TODO: maybe not necessary to recreate an array? + + logger.debug(str(self) + ": Added list of " + str(obj) + " " + name + " as self." + name + " (type: " + str(type(obj)) + ")") + + # initialize array elements + try: + init = assimp_struct_inits[type(obj[0])] + except KeyError: + if _is_init_type(obj[0]): + for e in getattr(target, name): + call_init(e, target) + else: + for e in getattr(target, name): + init(e) + + + except IndexError: + logger.error("in " + str(self) +" : mismatch between mNum" + name + " and the actual amount of data in m" + name + ". This may be due to version mismatch between libassimp and pyassimp. Quitting now.") + sys.exit(1) + + except ValueError as e: + + logger.error("In " + str(self) + "->" + name + ": " + str(e) + ". Quitting now.") + if "setting an array element with a sequence" in str(e): + logger.error("Note that pyassimp does not currently " + "support meshes with mixed triangles " + "and quads. Try to load your mesh with" + " a post-processing to triangulate your" + " faces.") + raise e + + + + else: # starts with 'm' but not iterable + setattr(target, m, obj) + logger.debug("Added " + name + " as self." + name + " (type: " + str(type(obj)) + ")") + + if _is_init_type(obj): + call_init(obj, target) + + if isinstance(self, structs.Mesh): + _finalize_mesh(self, target) + + if isinstance(self, structs.Texture): + _finalize_texture(self, target) + + if isinstance(self, structs.Metadata): + _finalize_metadata(self, target) + + + return self + + +def pythonize_assimp(type, obj, scene): + """ This method modify the Assimp data structures + to make them easier to work with in Python. + + Supported operations: + - MESH: replace a list of mesh IDs by reference to these meshes + - ADDTRANSFORMATION: add a reference to an object's transformation taken from their associated node. + + :param type: the type of modification to operate (cf above) + :param obj: the input object to modify + :param scene: a reference to the whole scene + """ + + if type == "MESH": + meshes = [] + for i in obj: + meshes.append(scene.meshes[i]) + return meshes + + if type == "ADDTRANSFORMATION": + def getnode(node, name): + if node.name == name: return node + for child in node.children: + n = getnode(child, name) + if n: return n + + node = getnode(scene.rootnode, obj.name) + if not node: + raise AssimpError("Object " + str(obj) + " has no associated node!") + setattr(obj, "transformation", node.transformation) + +def recur_pythonize(node, scene): + ''' + Recursively call pythonize_assimp on + nodes tree to apply several post-processing to + pythonize the assimp datastructures. + ''' + node.meshes = pythonize_assimp("MESH", node.meshes, scene) + for mesh in node.meshes: + mesh.material = scene.materials[mesh.materialindex] + for cam in scene.cameras: + pythonize_assimp("ADDTRANSFORMATION", cam, scene) + for c in node.children: + recur_pythonize(c, scene) + +def release(scene): + ''' + Release resources of a loaded scene. + ''' + _assimp_lib.release(ctypes.pointer(scene)) + +@contextmanager +def load(filename, + file_type = None, + processing = postprocess.aiProcess_Triangulate): + ''' + Load a model into a scene. On failure throws AssimpError. + + Arguments + --------- + filename: Either a filename or a file object to load model from. + If a file object is passed, file_type MUST be specified + Otherwise Assimp has no idea which importer to use. + This is named 'filename' so as to not break legacy code. + processing: assimp postprocessing parameters. Verbose keywords are imported + from postprocessing, and the parameters can be combined bitwise to + generate the final processing value. Note that the default value will + triangulate quad faces. Example of generating other possible values: + processing = (pyassimp.postprocess.aiProcess_Triangulate | + pyassimp.postprocess.aiProcess_OptimizeMeshes) + file_type: string of file extension, such as 'stl' + + Returns + --------- + Scene object with model data + ''' + + if hasattr(filename, 'read'): + # This is the case where a file object has been passed to load. + # It is calling the following function: + # const aiScene* aiImportFileFromMemory(const char* pBuffer, + # unsigned int pLength, + # unsigned int pFlags, + # const char* pHint) + if file_type is None: + raise AssimpError('File type must be specified when passing file objects!') + data = filename.read() + model = _assimp_lib.load_mem(data, + len(data), + processing, + file_type) + else: + # a filename string has been passed + model = _assimp_lib.load(filename.encode(sys.getfilesystemencoding()), processing) + + if not model: + raise AssimpError('Could not import file!') + scene = _init(model.contents) + recur_pythonize(scene.rootnode, scene) + try: + yield scene + finally: + release(scene) + +def export(scene, + filename, + file_type = None, + processing = postprocess.aiProcess_Triangulate): + ''' + Export a scene. On failure throws AssimpError. + + Arguments + --------- + scene: scene to export. + filename: Filename that the scene should be exported to. + file_type: string of file exporter to use. For example "collada". + processing: assimp postprocessing parameters. Verbose keywords are imported + from postprocessing, and the parameters can be combined bitwise to + generate the final processing value. Note that the default value will + triangulate quad faces. Example of generating other possible values: + processing = (pyassimp.postprocess.aiProcess_Triangulate | + pyassimp.postprocess.aiProcess_OptimizeMeshes) + + ''' + + exportStatus = _assimp_lib.export(ctypes.pointer(scene), file_type.encode("ascii"), filename.encode(sys.getfilesystemencoding()), processing) + + if exportStatus != 0: + raise AssimpError('Could not export scene!') + +def export_blob(scene, + file_type = None, + processing = postprocess.aiProcess_Triangulate): + ''' + Export a scene and return a blob in the correct format. On failure throws AssimpError. + + Arguments + --------- + scene: scene to export. + file_type: string of file exporter to use. For example "collada". + processing: assimp postprocessing parameters. Verbose keywords are imported + from postprocessing, and the parameters can be combined bitwise to + generate the final processing value. Note that the default value will + triangulate quad faces. Example of generating other possible values: + processing = (pyassimp.postprocess.aiProcess_Triangulate | + pyassimp.postprocess.aiProcess_OptimizeMeshes) + Returns + --------- + Pointer to structs.ExportDataBlob + ''' + exportBlobPtr = _assimp_lib.export_blob(ctypes.pointer(scene), file_type.encode("ascii"), processing) + + if exportBlobPtr == 0: + raise AssimpError('Could not export scene to blob!') + return exportBlobPtr + +def _finalize_texture(tex, target): + setattr(target, "achformathint", tex.achFormatHint) + if numpy: + data = numpy.array([make_tuple(getattr(tex, "pcData")[i]) for i in range(tex.mWidth * tex.mHeight)]) + else: + data = [make_tuple(getattr(tex, "pcData")[i]) for i in range(tex.mWidth * tex.mHeight)] + setattr(target, "data", data) + +def _finalize_mesh(mesh, target): + """ Building of meshes is a bit specific. + + We override here the various datasets that can + not be process as regular fields. + + For instance, the length of the normals array is + mNumVertices (no mNumNormals is available) + """ + nb_vertices = getattr(mesh, "mNumVertices") + + def fill(name): + mAttr = getattr(mesh, name) + if numpy: + if mAttr: + data = numpy.array([make_tuple(getattr(mesh, name)[i]) for i in range(nb_vertices)], dtype=numpy.float32) + setattr(target, name[1:].lower(), data) + else: + setattr(target, name[1:].lower(), numpy.array([], dtype="float32")) + else: + if mAttr: + data = [make_tuple(getattr(mesh, name)[i]) for i in range(nb_vertices)] + setattr(target, name[1:].lower(), data) + else: + setattr(target, name[1:].lower(), []) + + def fillarray(name): + mAttr = getattr(mesh, name) + + data = [] + for index, mSubAttr in enumerate(mAttr): + if mSubAttr: + data.append([make_tuple(getattr(mesh, name)[index][i]) for i in range(nb_vertices)]) + + if numpy: + setattr(target, name[1:].lower(), numpy.array(data, dtype=numpy.float32)) + else: + setattr(target, name[1:].lower(), data) + + fill("mNormals") + fill("mTangents") + fill("mBitangents") + + fillarray("mColors") + fillarray("mTextureCoords") + + # prepare faces + if numpy: + faces = numpy.array([f.indices for f in target.faces], dtype=numpy.int32) + else: + faces = [f.indices for f in target.faces] + setattr(target, 'faces', faces) + +def _init_metadata_entry(entry): + entry.type = entry.mType + if entry.type == structs.MetadataEntry.AI_BOOL: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_bool)).contents.value + elif entry.type == structs.MetadataEntry.AI_INT32: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_int32)).contents.value + elif entry.type == structs.MetadataEntry.AI_UINT64: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_uint64)).contents.value + elif entry.type == structs.MetadataEntry.AI_FLOAT: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_float)).contents.value + elif entry.type == structs.MetadataEntry.AI_DOUBLE: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_double)).contents.value + elif entry.type == structs.MetadataEntry.AI_AISTRING: + assimp_string = ctypes.cast(entry.mData, ctypes.POINTER(structs.String)).contents + entry.data = _convert_assimp_string(assimp_string) + elif entry.type == structs.MetadataEntry.AI_AIVECTOR3D: + assimp_vector = ctypes.cast(entry.mData, ctypes.POINTER(structs.Vector3D)).contents + entry.data = make_tuple(assimp_vector) + + return entry + +def _finalize_metadata(metadata, target): + """ Building the metadata object is a bit specific. + + Firstly, there are two separate arrays: one with metadata keys and one + with metadata values, and there are no corresponding mNum* attributes, + so the C arrays are not converted to Python arrays using the generic + code in the _init function. + + Secondly, a metadata entry value has to be cast according to declared + metadata entry type. + """ + length = metadata.mNumProperties + setattr(target, 'keys', [str(_convert_assimp_string(metadata.mKeys[i])) for i in range(length)]) + setattr(target, 'values', [_init_metadata_entry(metadata.mValues[i]) for i in range(length)]) + +class PropertyGetter(dict): + def __getitem__(self, key): + semantic = 0 + if isinstance(key, tuple): + key, semantic = key + + return dict.__getitem__(self, (key, semantic)) + + def keys(self): + for k in dict.keys(self): + yield k[0] + + def __iter__(self): + return self.keys() + + def items(self): + for k, v in dict.items(self): + yield k[0], v + + +def _get_properties(properties, length): + """ + Convenience Function to get the material properties as a dict + and values in a python format. + """ + result = {} + #read all properties + for p in [properties[i] for i in range(length)]: + #the name + p = p.contents + key = str(_convert_assimp_string(p.mKey)) + key = (key.split('.')[1], p.mSemantic) + + #the data + if p.mType == 1: + arr = ctypes.cast(p.mData, + ctypes.POINTER(ctypes.c_float * int(p.mDataLength/ctypes.sizeof(ctypes.c_float))) + ).contents + value = [x for x in arr] + elif p.mType == 3: #string can't be an array + value = _convert_assimp_string(ctypes.cast(p.mData, ctypes.POINTER(structs.MaterialPropertyString)).contents) + + elif p.mType == 4: + arr = ctypes.cast(p.mData, + ctypes.POINTER(ctypes.c_int * int(p.mDataLength/ctypes.sizeof(ctypes.c_int))) + ).contents + value = [x for x in arr] + else: + value = p.mData[:p.mDataLength] + + if len(value) == 1: + [value] = value + + result[key] = value + + return PropertyGetter(result) + +def decompose_matrix(matrix): + if not isinstance(matrix, structs.Matrix4x4): + raise AssimpError("pyassimp.decompose_matrix failed: Not a Matrix4x4!") + + scaling = structs.Vector3D() + rotation = structs.Quaternion() + position = structs.Vector3D() + + _assimp_lib.dll.aiDecomposeMatrix(ctypes.pointer(matrix), + ctypes.byref(scaling), + ctypes.byref(rotation), + ctypes.byref(position)) + return scaling._init(), rotation._init(), position._init() + diff --git a/libs/assimp/port/PyAssimp/pyassimp/errors.py b/libs/assimp/port/PyAssimp/pyassimp/errors.py new file mode 100644 index 0000000..e017b51 --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/errors.py @@ -0,0 +1,11 @@ +#-*- coding: UTF-8 -*- + +""" +All possible errors. +""" + +class AssimpError(BaseException): + """ + If an internal error occurs. + """ + pass diff --git a/libs/assimp/port/PyAssimp/pyassimp/formats.py b/libs/assimp/port/PyAssimp/pyassimp/formats.py new file mode 100644 index 0000000..5d454e5 --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/formats.py @@ -0,0 +1,41 @@ +FORMATS = ["CSM", + "LWS", + "B3D", + "COB", + "PLY", + "IFC", + "OFF", + "SMD", + "IRRMESH", + "3D", + "DAE", + "MDL", + "HMP", + "TER", + "WRL", + "XML", + "NFF", + "AC", + "OBJ", + "3DS", + "STL", + "IRR", + "Q3O", + "Q3D", + "MS3D", + "Q3S", + "ZGL", + "MD2", + "X", + "BLEND", + "XGL", + "MD5MESH", + "MAX", + "LXO", + "DXF", + "BVH", + "LWO", + "NDO"] + +def available_formats(): + return FORMATS diff --git a/libs/assimp/port/PyAssimp/pyassimp/helper.py b/libs/assimp/port/PyAssimp/pyassimp/helper.py new file mode 100644 index 0000000..7c14f60 --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/helper.py @@ -0,0 +1,283 @@ +#-*- coding: UTF-8 -*- + +""" +Some fancy helper functions. +""" + +import os +import ctypes +import operator + +from distutils.sysconfig import get_python_lib +import re +import sys + +try: import numpy +except ImportError: numpy = None + +import logging;logger = logging.getLogger("pyassimp") + +from .errors import AssimpError + +additional_dirs, ext_whitelist = [],[] + +# populate search directories and lists of allowed file extensions +# depending on the platform we're running on. +if os.name=='posix': + additional_dirs.append('./') + additional_dirs.append('/usr/lib/') + additional_dirs.append('/usr/lib/x86_64-linux-gnu/') + additional_dirs.append('/usr/lib/aarch64-linux-gnu/') + additional_dirs.append('/usr/local/lib/') + + if 'LD_LIBRARY_PATH' in os.environ: + additional_dirs.extend([item for item in os.environ['LD_LIBRARY_PATH'].split(':') if item]) + + # check if running from anaconda. + anaconda_keywords = ("conda", "continuum") + if any(k in sys.version.lower() for k in anaconda_keywords): + cur_path = get_python_lib() + pattern = re.compile('.*\/lib\/') + conda_lib = pattern.match(cur_path).group() + logger.info("Adding Anaconda lib path:"+ conda_lib) + additional_dirs.append(conda_lib) + + # note - this won't catch libassimp.so.N.n, but + # currently there's always a symlink called + # libassimp.so in /usr/local/lib. + ext_whitelist.append('.so') + # libassimp.dylib in /usr/local/lib + ext_whitelist.append('.dylib') + +elif os.name=='nt': + ext_whitelist.append('.dll') + path_dirs = os.environ['PATH'].split(';') + additional_dirs.extend(path_dirs) + +def vec2tuple(x): + """ Converts a VECTOR3D to a Tuple """ + return (x.x, x.y, x.z) + +def transform(vector3, matrix4x4): + """ Apply a transformation matrix on a 3D vector. + + :param vector3: array with 3 elements + :param matrix4x4: 4x4 matrix + """ + if numpy: + return numpy.dot(matrix4x4, numpy.append(vector3, 1.)) + else: + m0,m1,m2,m3 = matrix4x4; x,y,z = vector3 + return [ + m0[0]*x + m0[1]*y + m0[2]*z + m0[3], + m1[0]*x + m1[1]*y + m1[2]*z + m1[3], + m2[0]*x + m2[1]*y + m2[2]*z + m2[3], + m3[0]*x + m3[1]*y + m3[2]*z + m3[3] + ] + +def _inv(matrix4x4): + m0,m1,m2,m3 = matrix4x4 + + det = m0[3]*m1[2]*m2[1]*m3[0] - m0[2]*m1[3]*m2[1]*m3[0] - \ + m0[3]*m1[1]*m2[2]*m3[0] + m0[1]*m1[3]*m2[2]*m3[0] + \ + m0[2]*m1[1]*m2[3]*m3[0] - m0[1]*m1[2]*m2[3]*m3[0] - \ + m0[3]*m1[2]*m2[0]*m3[1] + m0[2]*m1[3]*m2[0]*m3[1] + \ + m0[3]*m1[0]*m2[2]*m3[1] - m0[0]*m1[3]*m2[2]*m3[1] - \ + m0[2]*m1[0]*m2[3]*m3[1] + m0[0]*m1[2]*m2[3]*m3[1] + \ + m0[3]*m1[1]*m2[0]*m3[2] - m0[1]*m1[3]*m2[0]*m3[2] - \ + m0[3]*m1[0]*m2[1]*m3[2] + m0[0]*m1[3]*m2[1]*m3[2] + \ + m0[1]*m1[0]*m2[3]*m3[2] - m0[0]*m1[1]*m2[3]*m3[2] - \ + m0[2]*m1[1]*m2[0]*m3[3] + m0[1]*m1[2]*m2[0]*m3[3] + \ + m0[2]*m1[0]*m2[1]*m3[3] - m0[0]*m1[2]*m2[1]*m3[3] - \ + m0[1]*m1[0]*m2[2]*m3[3] + m0[0]*m1[1]*m2[2]*m3[3] + + return[[( m1[2]*m2[3]*m3[1] - m1[3]*m2[2]*m3[1] + m1[3]*m2[1]*m3[2] - m1[1]*m2[3]*m3[2] - m1[2]*m2[1]*m3[3] + m1[1]*m2[2]*m3[3]) /det, + ( m0[3]*m2[2]*m3[1] - m0[2]*m2[3]*m3[1] - m0[3]*m2[1]*m3[2] + m0[1]*m2[3]*m3[2] + m0[2]*m2[1]*m3[3] - m0[1]*m2[2]*m3[3]) /det, + ( m0[2]*m1[3]*m3[1] - m0[3]*m1[2]*m3[1] + m0[3]*m1[1]*m3[2] - m0[1]*m1[3]*m3[2] - m0[2]*m1[1]*m3[3] + m0[1]*m1[2]*m3[3]) /det, + ( m0[3]*m1[2]*m2[1] - m0[2]*m1[3]*m2[1] - m0[3]*m1[1]*m2[2] + m0[1]*m1[3]*m2[2] + m0[2]*m1[1]*m2[3] - m0[1]*m1[2]*m2[3]) /det], + [( m1[3]*m2[2]*m3[0] - m1[2]*m2[3]*m3[0] - m1[3]*m2[0]*m3[2] + m1[0]*m2[3]*m3[2] + m1[2]*m2[0]*m3[3] - m1[0]*m2[2]*m3[3]) /det, + ( m0[2]*m2[3]*m3[0] - m0[3]*m2[2]*m3[0] + m0[3]*m2[0]*m3[2] - m0[0]*m2[3]*m3[2] - m0[2]*m2[0]*m3[3] + m0[0]*m2[2]*m3[3]) /det, + ( m0[3]*m1[2]*m3[0] - m0[2]*m1[3]*m3[0] - m0[3]*m1[0]*m3[2] + m0[0]*m1[3]*m3[2] + m0[2]*m1[0]*m3[3] - m0[0]*m1[2]*m3[3]) /det, + ( m0[2]*m1[3]*m2[0] - m0[3]*m1[2]*m2[0] + m0[3]*m1[0]*m2[2] - m0[0]*m1[3]*m2[2] - m0[2]*m1[0]*m2[3] + m0[0]*m1[2]*m2[3]) /det], + [( m1[1]*m2[3]*m3[0] - m1[3]*m2[1]*m3[0] + m1[3]*m2[0]*m3[1] - m1[0]*m2[3]*m3[1] - m1[1]*m2[0]*m3[3] + m1[0]*m2[1]*m3[3]) /det, + ( m0[3]*m2[1]*m3[0] - m0[1]*m2[3]*m3[0] - m0[3]*m2[0]*m3[1] + m0[0]*m2[3]*m3[1] + m0[1]*m2[0]*m3[3] - m0[0]*m2[1]*m3[3]) /det, + ( m0[1]*m1[3]*m3[0] - m0[3]*m1[1]*m3[0] + m0[3]*m1[0]*m3[1] - m0[0]*m1[3]*m3[1] - m0[1]*m1[0]*m3[3] + m0[0]*m1[1]*m3[3]) /det, + ( m0[3]*m1[1]*m2[0] - m0[1]*m1[3]*m2[0] - m0[3]*m1[0]*m2[1] + m0[0]*m1[3]*m2[1] + m0[1]*m1[0]*m2[3] - m0[0]*m1[1]*m2[3]) /det], + [( m1[2]*m2[1]*m3[0] - m1[1]*m2[2]*m3[0] - m1[2]*m2[0]*m3[1] + m1[0]*m2[2]*m3[1] + m1[1]*m2[0]*m3[2] - m1[0]*m2[1]*m3[2]) /det, + ( m0[1]*m2[2]*m3[0] - m0[2]*m2[1]*m3[0] + m0[2]*m2[0]*m3[1] - m0[0]*m2[2]*m3[1] - m0[1]*m2[0]*m3[2] + m0[0]*m2[1]*m3[2]) /det, + ( m0[2]*m1[1]*m3[0] - m0[1]*m1[2]*m3[0] - m0[2]*m1[0]*m3[1] + m0[0]*m1[2]*m3[1] + m0[1]*m1[0]*m3[2] - m0[0]*m1[1]*m3[2]) /det, + ( m0[1]*m1[2]*m2[0] - m0[2]*m1[1]*m2[0] + m0[2]*m1[0]*m2[1] - m0[0]*m1[2]*m2[1] - m0[1]*m1[0]*m2[2] + m0[0]*m1[1]*m2[2]) /det]] + +def get_bounding_box(scene): + bb_min = [1e10, 1e10, 1e10] # x,y,z + bb_max = [-1e10, -1e10, -1e10] # x,y,z + inv = numpy.linalg.inv if numpy else _inv + return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max, inv(scene.rootnode.transformation)) + +def get_bounding_box_for_node(node, bb_min, bb_max, transformation): + + if numpy: + transformation = numpy.dot(transformation, node.transformation) + else: + t0,t1,t2,t3 = transformation + T0,T1,T2,T3 = node.transformation + transformation = [ [ + t0[0]*T0[0] + t0[1]*T1[0] + t0[2]*T2[0] + t0[3]*T3[0], + t0[0]*T0[1] + t0[1]*T1[1] + t0[2]*T2[1] + t0[3]*T3[1], + t0[0]*T0[2] + t0[1]*T1[2] + t0[2]*T2[2] + t0[3]*T3[2], + t0[0]*T0[3] + t0[1]*T1[3] + t0[2]*T2[3] + t0[3]*T3[3] + ],[ + t1[0]*T0[0] + t1[1]*T1[0] + t1[2]*T2[0] + t1[3]*T3[0], + t1[0]*T0[1] + t1[1]*T1[1] + t1[2]*T2[1] + t1[3]*T3[1], + t1[0]*T0[2] + t1[1]*T1[2] + t1[2]*T2[2] + t1[3]*T3[2], + t1[0]*T0[3] + t1[1]*T1[3] + t1[2]*T2[3] + t1[3]*T3[3] + ],[ + t2[0]*T0[0] + t2[1]*T1[0] + t2[2]*T2[0] + t2[3]*T3[0], + t2[0]*T0[1] + t2[1]*T1[1] + t2[2]*T2[1] + t2[3]*T3[1], + t2[0]*T0[2] + t2[1]*T1[2] + t2[2]*T2[2] + t2[3]*T3[2], + t2[0]*T0[3] + t2[1]*T1[3] + t2[2]*T2[3] + t2[3]*T3[3] + ],[ + t3[0]*T0[0] + t3[1]*T1[0] + t3[2]*T2[0] + t3[3]*T3[0], + t3[0]*T0[1] + t3[1]*T1[1] + t3[2]*T2[1] + t3[3]*T3[1], + t3[0]*T0[2] + t3[1]*T1[2] + t3[2]*T2[2] + t3[3]*T3[2], + t3[0]*T0[3] + t3[1]*T1[3] + t3[2]*T2[3] + t3[3]*T3[3] + ] ] + + for mesh in node.meshes: + for v in mesh.vertices: + v = transform(v, transformation) + bb_min[0] = min(bb_min[0], v[0]) + bb_min[1] = min(bb_min[1], v[1]) + bb_min[2] = min(bb_min[2], v[2]) + bb_max[0] = max(bb_max[0], v[0]) + bb_max[1] = max(bb_max[1], v[1]) + bb_max[2] = max(bb_max[2], v[2]) + + + for child in node.children: + bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max, transformation) + + return bb_min, bb_max + +def try_load_functions(library_path, dll): + ''' + Try to bind to aiImportFile and aiReleaseImport + + Arguments + --------- + library_path: path to current lib + dll: ctypes handle to library + + Returns + --------- + If unsuccessful: + None + If successful: + Tuple containing (library_path, + load from filename function, + load from memory function, + export to filename function, + export to blob function, + release function, + ctypes handle to assimp library) + ''' + + try: + load = dll.aiImportFile + release = dll.aiReleaseImport + load_mem = dll.aiImportFileFromMemory + export = dll.aiExportScene + export2blob = dll.aiExportSceneToBlob + except AttributeError: + #OK, this is a library, but it doesn't have the functions we need + return None + + # library found! + from .structs import Scene, ExportDataBlob + load.restype = ctypes.POINTER(Scene) + load_mem.restype = ctypes.POINTER(Scene) + export2blob.restype = ctypes.POINTER(ExportDataBlob) + return (library_path, load, load_mem, export, export2blob, release, dll) + +def search_library(): + ''' + Loads the assimp library. + Throws exception AssimpError if no library_path is found + + Returns: tuple, (load from filename function, + load from memory function, + export to filename function, + export to blob function, + release function, + dll) + ''' + #this path + folder = os.path.dirname(__file__) + + # silence 'DLL not found' message boxes on win + try: + ctypes.windll.kernel32.SetErrorMode(0x8007) + except AttributeError: + pass + + candidates = [] + # test every file + for curfolder in [folder]+additional_dirs: + if os.path.isdir(curfolder): + for filename in os.listdir(curfolder): + # our minimum requirement for candidates is that + # they should contain 'assimp' somewhere in + # their name + if filename.lower().find('assimp')==-1 : + continue + is_out=1 + for et in ext_whitelist: + if et in filename.lower(): + is_out=0 + break + if is_out: + continue + + library_path = os.path.join(curfolder, filename) + logger.debug('Try ' + library_path) + try: + dll = ctypes.cdll.LoadLibrary(library_path) + except Exception as e: + logger.warning(str(e)) + # OK, this except is evil. But different OSs will throw different + # errors. So just ignore any errors. + continue + # see if the functions we need are in the dll + loaded = try_load_functions(library_path, dll) + if loaded: candidates.append(loaded) + + if not candidates: + # no library found + raise AssimpError("assimp library not found") + else: + # get the newest library_path + candidates = map(lambda x: (os.lstat(x[0])[-2], x), candidates) + res = max(candidates, key=operator.itemgetter(0))[1] + logger.debug('Using assimp library located at ' + res[0]) + + # XXX: if there are 1000 dll/so files containing 'assimp' + # in their name, do we have all of them in our address + # space now until gc kicks in? + + # XXX: take version postfix of the .so on linux? + return res[1:] + +def hasattr_silent(object, name): + """ + Calls hasttr() with the given parameters and preserves the legacy (pre-Python 3.2) + functionality of silently catching exceptions. + + Returns the result of hasatter() or False if an exception was raised. + """ + + try: + if not object: + return False + return hasattr(object, name) + except AttributeError: + return False diff --git a/libs/assimp/port/PyAssimp/pyassimp/material.py b/libs/assimp/port/PyAssimp/pyassimp/material.py new file mode 100644 index 0000000..a36e50a --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/material.py @@ -0,0 +1,89 @@ +# Dummy value. +# +# No texture, but the value to be used as 'texture semantic' +# (#aiMaterialProperty::mSemantic) for all material properties +# # not* related to textures. +# +aiTextureType_NONE = 0x0 + +# The texture is combined with the result of the diffuse +# lighting equation. +# +aiTextureType_DIFFUSE = 0x1 + +# The texture is combined with the result of the specular +# lighting equation. +# +aiTextureType_SPECULAR = 0x2 + +# The texture is combined with the result of the ambient +# lighting equation. +# +aiTextureType_AMBIENT = 0x3 + +# The texture is added to the result of the lighting +# calculation. It isn't influenced by incoming light. +# +aiTextureType_EMISSIVE = 0x4 + +# The texture is a height map. +# +# By convention, higher gray-scale values stand for +# higher elevations from the base height. +# +aiTextureType_HEIGHT = 0x5 + +# The texture is a (tangent space) normal-map. +# +# Again, there are several conventions for tangent-space +# normal maps. Assimp does (intentionally) not +# distinguish here. +# +aiTextureType_NORMALS = 0x6 + +# The texture defines the glossiness of the material. +# +# The glossiness is in fact the exponent of the specular +# (phong) lighting equation. Usually there is a conversion +# function defined to map the linear color values in the +# texture to a suitable exponent. Have fun. +# +aiTextureType_SHININESS = 0x7 + +# The texture defines per-pixel opacity. +# +# Usually 'white' means opaque and 'black' means +# 'transparency'. Or quite the opposite. Have fun. +# +aiTextureType_OPACITY = 0x8 + +# Displacement texture +# +# The exact purpose and format is application-dependent. +# Higher color values stand for higher vertex displacements. +# +aiTextureType_DISPLACEMENT = 0x9 + +# Lightmap texture (aka Ambient Occlusion) +# +# Both 'Lightmaps' and dedicated 'ambient occlusion maps' are +# covered by this material property. The texture contains a +# scaling value for the final color value of a pixel. Its +# intensity is not affected by incoming light. +# +aiTextureType_LIGHTMAP = 0xA + +# Reflection texture +# +# Contains the color of a perfect mirror reflection. +# Rarely used, almost never for real-time applications. +# +aiTextureType_REFLECTION = 0xB + +# Unknown texture +# +# A texture reference that does not match any of the definitions +# above is considered to be 'unknown'. It is still imported +# but is excluded from any further postprocessing. +# +aiTextureType_UNKNOWN = 0xC diff --git a/libs/assimp/port/PyAssimp/pyassimp/postprocess.py b/libs/assimp/port/PyAssimp/pyassimp/postprocess.py new file mode 100644 index 0000000..0c55d67 --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/postprocess.py @@ -0,0 +1,530 @@ +# <hr>Calculates the tangents and bitangents for the imported meshes. +# +# Does nothing if a mesh does not have normals. You might want this post +# processing step to be executed if you plan to use tangent space calculations +# such as normal mapping applied to the meshes. There's a config setting, +# <tt>#AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE<tt>, which allows you to specify +# a maximum smoothing angle for the algorithm. However, usually you'll +# want to leave it at the default value. +# +aiProcess_CalcTangentSpace = 0x1 + +## <hr>Identifies and joins identical vertex data sets within all +# imported meshes. +# +# After this step is run, each mesh contains unique vertices, +# so a vertex may be used by multiple faces. You usually want +# to use this post processing step. If your application deals with +# indexed geometry, this step is compulsory or you'll just waste rendering +# time. <b>If this flag is not specified<b>, no vertices are referenced by +# more than one face and <b>no index buffer is required<b> for rendering. +# +aiProcess_JoinIdenticalVertices = 0x2 + +## <hr>Converts all the imported data to a left-handed coordinate space. +# +# By default the data is returned in a right-handed coordinate space (which +# OpenGL prefers). In this space, +X points to the right, +# +Z points towards the viewer, and +Y points upwards. In the DirectX +# coordinate space +X points to the right, +Y points upwards, and +Z points +# away from the viewer. +# +# You'll probably want to consider this flag if you use Direct3D for +# rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this +# setting and bundles all conversions typically required for D3D-based +# applications. +# +aiProcess_MakeLeftHanded = 0x4 + +## <hr>Triangulates all faces of all meshes. +# +# By default the imported mesh data might contain faces with more than 3 +# indices. For rendering you'll usually want all faces to be triangles. +# This post processing step splits up faces with more than 3 indices into +# triangles. Line and point primitives are #not# modified! If you want +# 'triangles only' with no other kinds of primitives, try the following +# solution: +# <ul> +# <li>Specify both #aiProcess_Triangulate and #aiProcess_SortByPType <li> +# <li>Ignore all point and line meshes when you process assimp's output<li> +# <ul> +# +aiProcess_Triangulate = 0x8 + +## <hr>Removes some parts of the data structure (animations, materials, +# light sources, cameras, textures, vertex components). +# +# The components to be removed are specified in a separate +# configuration option, <tt>#AI_CONFIG_PP_RVC_FLAGS<tt>. This is quite useful +# if you don't need all parts of the output structure. Vertex colors +# are rarely used today for example... Calling this step to remove unneeded +# data from the pipeline as early as possible results in increased +# performance and a more optimized output data structure. +# This step is also useful if you want to force Assimp to recompute +# normals or tangents. The corresponding steps don't recompute them if +# they're already there (loaded from the source asset). By using this +# step you can make sure they are NOT there. +# +# This flag is a poor one, mainly because its purpose is usually +# misunderstood. Consider the following case: a 3D model has been exported +# from a CAD app, and it has per-face vertex colors. Vertex positions can't be +# shared, thus the #aiProcess_JoinIdenticalVertices step fails to +# optimize the data because of these nasty little vertex colors. +# Most apps don't even process them, so it's all for nothing. By using +# this step, unneeded components are excluded as early as possible +# thus opening more room for internal optimizations. +# +aiProcess_RemoveComponent = 0x10 + +## <hr>Generates normals for all faces of all meshes. +# +# This is ignored if normals are already there at the time this flag +# is evaluated. Model importers try to load them from the source file, so +# they're usually already there. Face normals are shared between all points +# of a single face, so a single point can have multiple normals, which +# forces the library to duplicate vertices in some cases. +# #aiProcess_JoinIdenticalVertices is #senseless# then. +# +# This flag may not be specified together with #aiProcess_GenSmoothNormals. +# +aiProcess_GenNormals = 0x20 + +## <hr>Generates smooth normals for all vertices in the mesh. +# +# This is ignored if normals are already there at the time this flag +# is evaluated. Model importers try to load them from the source file, so +# they're usually already there. +# +# This flag may not be specified together with +# #aiProcess_GenNormals. There's a configuration option, +# <tt>#AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE<tt> which allows you to specify +# an angle maximum for the normal smoothing algorithm. Normals exceeding +# this limit are not smoothed, resulting in a 'hard' seam between two faces. +# Using a decent angle here (e.g. 80 degrees) results in very good visual +# appearance. +# +aiProcess_GenSmoothNormals = 0x40 + +## <hr>Splits large meshes into smaller sub-meshes. +# +# This is quite useful for real-time rendering, where the number of triangles +# which can be maximally processed in a single draw-call is limited +# by the video driverhardware. The maximum vertex buffer is usually limited +# too. Both requirements can be met with this step: you may specify both a +# triangle and vertex limit for a single mesh. +# +# The split limits can (and should!) be set through the +# <tt>#AI_CONFIG_PP_SLM_VERTEX_LIMIT<tt> and <tt>#AI_CONFIG_PP_SLM_TRIANGLE_LIMIT<tt> +# settings. The default values are <tt>#AI_SLM_DEFAULT_MAX_VERTICES<tt> and +# <tt>#AI_SLM_DEFAULT_MAX_TRIANGLES<tt>. +# +# Note that splitting is generally a time-consuming task, but only if there's +# something to split. The use of this step is recommended for most users. +# +aiProcess_SplitLargeMeshes = 0x80 + +## <hr>Removes the node graph and pre-transforms all vertices with +# the local transformation matrices of their nodes. +# +# The output scene still contains nodes, however there is only a +# root node with children, each one referencing only one mesh, +# and each mesh referencing one material. For rendering, you can +# simply render all meshes in order - you don't need to pay +# attention to local transformations and the node hierarchy. +# Animations are removed during this step. +# This step is intended for applications without a scenegraph. +# The step CAN cause some problems: if e.g. a mesh of the asset +# contains normals and another, using the same material index, does not, +# they will be brought together, but the first meshes's part of +# the normal list is zeroed. However, these artifacts are rare. +# @note The <tt>#AI_CONFIG_PP_PTV_NORMALIZE<tt> configuration property +# can be set to normalize the scene's spatial dimension to the -1...1 +# range. +# +aiProcess_PreTransformVertices = 0x100 + +## <hr>Limits the number of bones simultaneously affecting a single vertex +# to a maximum value. +# +# If any vertex is affected by more than the maximum number of bones, the least +# important vertex weights are removed and the remaining vertex weights are +# renormalized so that the weights still sum up to 1. +# The default bone weight limit is 4 (defined as <tt>#AI_LMW_MAX_WEIGHTS<tt> in +# config.h), but you can use the <tt>#AI_CONFIG_PP_LBW_MAX_WEIGHTS<tt> setting to +# supply your own limit to the post processing step. +# +# If you intend to perform the skinning in hardware, this post processing +# step might be of interest to you. +# +aiProcess_LimitBoneWeights = 0x200 + +## <hr>Validates the imported scene data structure. +# This makes sure that all indices are valid, all animations and +# bones are linked correctly, all material references are correct .. etc. +# +# It is recommended that you capture Assimp's log output if you use this flag, +# so you can easily find out what's wrong if a file fails the +# validation. The validator is quite strict and will find #all# +# inconsistencies in the data structure... It is recommended that plugin +# developers use it to debug their loaders. There are two types of +# validation failures: +# <ul> +# <li>Error: There's something wrong with the imported data. Further +# postprocessing is not possible and the data is not usable at all. +# The import fails. #Importer::GetErrorString() or #aiGetErrorString() +# carry the error message around.<li> +# <li>Warning: There are some minor issues (e.g. 1000000 animation +# keyframes with the same time), but further postprocessing and use +# of the data structure is still safe. Warning details are written +# to the log file, <tt>#AI_SCENE_FLAGS_VALIDATION_WARNING<tt> is set +# in #aiScene::mFlags<li> +# <ul> +# +# This post-processing step is not time-consuming. Its use is not +# compulsory, but recommended. +# +aiProcess_ValidateDataStructure = 0x400 + +## <hr>Reorders triangles for better vertex cache locality. +# +# The step tries to improve the ACMR (average post-transform vertex cache +# miss ratio) for all meshes. The implementation runs in O(n) and is +# roughly based on the 'tipsify' algorithm (see <a href=" +# http:www.cs.princeton.edugfxpubsSander_2007_%3ETRtipsy.pdf">this +# paper<a>). +# +# If you intend to render huge models in hardware, this step might +# be of interest to you. The <tt>#AI_CONFIG_PP_ICL_PTCACHE_SIZE<tt>config +# setting can be used to fine-tune the cache optimization. +# +aiProcess_ImproveCacheLocality = 0x800 + +## <hr>Searches for redundantunreferenced materials and removes them. +# +# This is especially useful in combination with the +# #aiProcess_PretransformVertices and #aiProcess_OptimizeMeshes flags. +# Both join small meshes with equal characteristics, but they can't do +# their work if two meshes have different materials. Because several +# material settings are lost during Assimp's import filters, +# (and because many exporters don't check for redundant materials), huge +# models often have materials which are are defined several times with +# exactly the same settings. +# +# Several material settings not contributing to the final appearance of +# a surface are ignored in all comparisons (e.g. the material name). +# So, if you're passing additional information through the +# content pipeline (probably using #magic# material names), don't +# specify this flag. Alternatively take a look at the +# <tt>#AI_CONFIG_PP_RRM_EXCLUDE_LIST<tt> setting. +# +aiProcess_RemoveRedundantMaterials = 0x1000 + +## <hr>This step tries to determine which meshes have normal vectors +# that are facing inwards and inverts them. +# +# The algorithm is simple but effective: +# the bounding box of all vertices + their normals is compared against +# the volume of the bounding box of all vertices without their normals. +# This works well for most objects, problems might occur with planar +# surfaces. However, the step tries to filter such cases. +# The step inverts all in-facing normals. Generally it is recommended +# to enable this step, although the result is not always correct. +# +aiProcess_FixInfacingNormals = 0x2000 + +## <hr>This step splits meshes with more than one primitive type in +# homogeneous sub-meshes. +# +# The step is executed after the triangulation step. After the step +# returns, just one bit is set in aiMesh::mPrimitiveTypes. This is +# especially useful for real-time rendering where point and line +# primitives are often ignored or rendered separately. +# You can use the <tt>#AI_CONFIG_PP_SBP_REMOVE<tt> option to specify which +# primitive types you need. This can be used to easily exclude +# lines and points, which are rarely used, from the import. +# +aiProcess_SortByPType = 0x8000 + +## <hr>This step searches all meshes for degenerate primitives and +# converts them to proper lines or points. +# +# A face is 'degenerate' if one or more of its points are identical. +# To have the degenerate stuff not only detected and collapsed but +# removed, try one of the following procedures: +# <br><b>1.<b> (if you support lines and points for rendering but don't +# want the degenerates)<br> +# <ul> +# <li>Specify the #aiProcess_FindDegenerates flag. +# <li> +# <li>Set the <tt>AI_CONFIG_PP_FD_REMOVE<tt> option to 1. This will +# cause the step to remove degenerate triangles from the import +# as soon as they're detected. They won't pass any further +# pipeline steps. +# <li> +# <ul> +# <br><b>2.<b>(if you don't support lines and points at all)<br> +# <ul> +# <li>Specify the #aiProcess_FindDegenerates flag. +# <li> +# <li>Specify the #aiProcess_SortByPType flag. This moves line and +# point primitives to separate meshes. +# <li> +# <li>Set the <tt>AI_CONFIG_PP_SBP_REMOVE<tt> option to +# @code aiPrimitiveType_POINTS | aiPrimitiveType_LINES +# @endcode to cause SortByPType to reject point +# and line meshes from the scene. +# <li> +# <ul> +# @note Degenerate polygons are not necessarily evil and that's why +# they're not removed by default. There are several file formats which +# don't support lines or points, and some exporters bypass the +# format specification and write them as degenerate triangles instead. +# +aiProcess_FindDegenerates = 0x10000 + +## <hr>This step searches all meshes for invalid data, such as zeroed +# normal vectors or invalid UV coords and removesfixes them. This is +# intended to get rid of some common exporter errors. +# +# This is especially useful for normals. If they are invalid, and +# the step recognizes this, they will be removed and can later +# be recomputed, i.e. by the #aiProcess_GenSmoothNormals flag.<br> +# The step will also remove meshes that are infinitely small and reduce +# animation tracks consisting of hundreds if redundant keys to a single +# key. The <tt>AI_CONFIG_PP_FID_ANIM_ACCURACY<tt> config property decides +# the accuracy of the check for duplicate animation tracks. +# +aiProcess_FindInvalidData = 0x20000 + +## <hr>This step converts non-UV mappings (such as spherical or +# cylindrical mapping) to proper texture coordinate channels. +# +# Most applications will support UV mapping only, so you will +# probably want to specify this step in every case. Note that Assimp is not +# always able to match the original mapping implementation of the +# 3D app which produced a model perfectly. It's always better to let the +# modelling app compute the UV channels - 3ds max, Maya, Blender, +# LightWave, and Modo do this for example. +# +# @note If this step is not requested, you'll need to process the +# <tt>#AI_MATKEY_MAPPING<tt> material property in order to display all assets +# properly. +# +aiProcess_GenUVCoords = 0x40000 + +## <hr>This step applies per-texture UV transformations and bakes +# them into stand-alone vtexture coordinate channels. +# +# UV transformations are specified per-texture - see the +# <tt>#AI_MATKEY_UVTRANSFORM<tt> material key for more information. +# This step processes all textures with +# transformed input UV coordinates and generates a new (pre-transformed) UV channel +# which replaces the old channel. Most applications won't support UV +# transformations, so you will probably want to specify this step. +# +# @note UV transformations are usually implemented in real-time apps by +# transforming texture coordinates at vertex shader stage with a 3x3 +# (homogenous) transformation matrix. +# +aiProcess_TransformUVCoords = 0x80000 + +## <hr>This step searches for duplicate meshes and replaces them +# with references to the first mesh. +# +# This step takes a while, so don't use it if speed is a concern. +# Its main purpose is to workaround the fact that many export +# file formats don't support instanced meshes, so exporters need to +# duplicate meshes. This step removes the duplicates again. Please +# note that Assimp does not currently support per-node material +# assignment to meshes, which means that identical meshes with +# different materials are currently #not# joined, although this is +# planned for future versions. +# +aiProcess_FindInstances = 0x100000 + +## <hr>A postprocessing step to reduce the number of meshes. +# +# This will, in fact, reduce the number of draw calls. +# +# This is a very effective optimization and is recommended to be used +# together with #aiProcess_OptimizeGraph, if possible. The flag is fully +# compatible with both #aiProcess_SplitLargeMeshes and #aiProcess_SortByPType. +# +aiProcess_OptimizeMeshes = 0x200000 + + +## <hr>A postprocessing step to optimize the scene hierarchy. +# +# Nodes without animations, bones, lights or cameras assigned are +# collapsed and joined. +# +# Node names can be lost during this step. If you use special 'tag nodes' +# to pass additional information through your content pipeline, use the +# <tt>#AI_CONFIG_PP_OG_EXCLUDE_LIST<tt> setting to specify a list of node +# names you want to be kept. Nodes matching one of the names in this list won't +# be touched or modified. +# +# Use this flag with caution. Most simple files will be collapsed to a +# single node, so complex hierarchies are usually completely lost. This is not +# useful for editor environments, but probably a very effective +# optimization if you just want to get the model data, convert it to your +# own format, and render it as fast as possible. +# +# This flag is designed to be used with #aiProcess_OptimizeMeshes for best +# results. +# +# @note 'Crappy' scenes with thousands of extremely small meshes packed +# in deeply nested nodes exist for almost all file formats. +# #aiProcess_OptimizeMeshes in combination with #aiProcess_OptimizeGraph +# usually fixes them all and makes them renderable. +# +aiProcess_OptimizeGraph = 0x400000 + +## <hr>This step flips all UV coordinates along the y-axis and adjusts +# material settings and bitangents accordingly. +# +# <b>Output UV coordinate system:<b> +# @code +# 0y|0y ---------- 1x|0y +# | | +# | | +# | | +# 0x|1y ---------- 1x|1y +# @endcode +# +# You'll probably want to consider this flag if you use Direct3D for +# rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this +# setting and bundles all conversions typically required for D3D-based +# applications. +# +aiProcess_FlipUVs = 0x800000 + +## <hr>This step adjusts the output face winding order to be CW. +# +# The default face winding order is counter clockwise (CCW). +# +# <b>Output face order:<b> +# @code +# x2 +# +# x0 +# x1 +# @endcode +# +aiProcess_FlipWindingOrder = 0x1000000 + +## <hr>This step splits meshes with many bones into sub-meshes so that each +# su-bmesh has fewer or as many bones as a given limit. +# +aiProcess_SplitByBoneCount = 0x2000000 + +## <hr>This step removes bones losslessly or according to some threshold. +# +# In some cases (i.e. formats that require it) exporters are forced to +# assign dummy bone weights to otherwise static meshes assigned to +# animated meshes. Full, weight-based skinning is expensive while +# animating nodes is extremely cheap, so this step is offered to clean up +# the data in that regard. +# +# Use <tt>#AI_CONFIG_PP_DB_THRESHOLD<tt> to control this. +# Use <tt>#AI_CONFIG_PP_DB_ALL_OR_NONE<tt> if you want bones removed if and +# only if all bones within the scene qualify for removal. +# +aiProcess_Debone = 0x4000000 + +aiProcess_GenEntityMeshes = 0x100000 +aiProcess_OptimizeAnimations = 0x200000 +aiProcess_FixTexturePaths = 0x200000 +aiProcess_EmbedTextures = 0x10000000, + +## @def aiProcess_ConvertToLeftHanded + # @brief Shortcut flag for Direct3D-based applications. + # + # Supersedes the #aiProcess_MakeLeftHanded and #aiProcess_FlipUVs and + # #aiProcess_FlipWindingOrder flags. + # The output data matches Direct3D's conventions: left-handed geometry, upper-left + # origin for UV coordinates and finally clockwise face order, suitable for CCW culling. + # + # @deprecated + # +aiProcess_ConvertToLeftHanded = ( \ + aiProcess_MakeLeftHanded | \ + aiProcess_FlipUVs | \ + aiProcess_FlipWindingOrder | \ + 0 ) + + +## @def aiProcessPreset_TargetRealtimeUse_Fast + # @brief Default postprocess configuration optimizing the data for real-time rendering. + # + # Applications would want to use this preset to load models on end-user PCs, + # maybe for direct use in game. + # + # If you're using DirectX, don't forget to combine this value with + # the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + # in your application apply the #aiProcess_TransformUVCoords step, too. + # @note Please take the time to read the docs for the steps enabled by this preset. + # Some of them offer further configurable properties, while some of them might not be of + # use for you so it might be better to not specify them. + # +aiProcessPreset_TargetRealtime_Fast = ( \ + aiProcess_CalcTangentSpace | \ + aiProcess_GenNormals | \ + aiProcess_JoinIdenticalVertices | \ + aiProcess_Triangulate | \ + aiProcess_GenUVCoords | \ + aiProcess_SortByPType | \ + 0 ) + + ## @def aiProcessPreset_TargetRealtime_Quality + # @brief Default postprocess configuration optimizing the data for real-time rendering. + # + # Unlike #aiProcessPreset_TargetRealtime_Fast, this configuration + # performs some extra optimizations to improve rendering speed and + # to minimize memory usage. It could be a good choice for a level editor + # environment where import speed is not so important. + # + # If you're using DirectX, don't forget to combine this value with + # the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + # in your application apply the #aiProcess_TransformUVCoords step, too. + # @note Please take the time to read the docs for the steps enabled by this preset. + # Some of them offer further configurable properties, while some of them might not be + # of use for you so it might be better to not specify them. + # +aiProcessPreset_TargetRealtime_Quality = ( \ + aiProcess_CalcTangentSpace | \ + aiProcess_GenSmoothNormals | \ + aiProcess_JoinIdenticalVertices | \ + aiProcess_ImproveCacheLocality | \ + aiProcess_LimitBoneWeights | \ + aiProcess_RemoveRedundantMaterials | \ + aiProcess_SplitLargeMeshes | \ + aiProcess_Triangulate | \ + aiProcess_GenUVCoords | \ + aiProcess_SortByPType | \ + aiProcess_FindDegenerates | \ + aiProcess_FindInvalidData | \ + 0 ) + + ## @def aiProcessPreset_TargetRealtime_MaxQuality + # @brief Default postprocess configuration optimizing the data for real-time rendering. + # + # This preset enables almost every optimization step to achieve perfectly + # optimized data. It's your choice for level editor environments where import speed + # is not important. + # + # If you're using DirectX, don't forget to combine this value with + # the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + # in your application, apply the #aiProcess_TransformUVCoords step, too. + # @note Please take the time to read the docs for the steps enabled by this preset. + # Some of them offer further configurable properties, while some of them might not be + # of use for you so it might be better to not specify them. + # +aiProcessPreset_TargetRealtime_MaxQuality = ( \ + aiProcessPreset_TargetRealtime_Quality | \ + aiProcess_FindInstances | \ + aiProcess_ValidateDataStructure | \ + aiProcess_OptimizeMeshes | \ + 0 ) + + diff --git a/libs/assimp/port/PyAssimp/pyassimp/structs.py b/libs/assimp/port/PyAssimp/pyassimp/structs.py new file mode 100644 index 0000000..e1fba19 --- /dev/null +++ b/libs/assimp/port/PyAssimp/pyassimp/structs.py @@ -0,0 +1,1135 @@ +#-*- coding: utf-8 -*- + +from ctypes import POINTER, c_void_p, c_uint, c_char, c_float, Structure, c_double, c_ubyte, c_size_t, c_uint32 + + +class Vector2D(Structure): + """ + See 'vector2.h' for details. + """ + + + _fields_ = [ + ("x", c_float),("y", c_float), + ] + +class Matrix3x3(Structure): + """ + See 'matrix3x3.h' for details. + """ + + + _fields_ = [ + ("a1", c_float),("a2", c_float),("a3", c_float), + ("b1", c_float),("b2", c_float),("b3", c_float), + ("c1", c_float),("c2", c_float),("c3", c_float), + ] + +class Texel(Structure): + """ + See 'texture.h' for details. + """ + + _fields_ = [ + ("b", c_ubyte),("g", c_ubyte),("r", c_ubyte),("a", c_ubyte), + ] + +class Color4D(Structure): + """ + See 'color4.h' for details. + """ + + + _fields_ = [ + # Red, green, blue and alpha color values + ("r", c_float),("g", c_float),("b", c_float),("a", c_float), + ] + +class Plane(Structure): + """ + See 'types.h' for details. + """ + + _fields_ = [ + # Plane equation + ("a", c_float),("b", c_float),("c", c_float),("d", c_float), + ] + +class Color3D(Structure): + """ + See 'types.h' for details. + """ + + _fields_ = [ + # Red, green and blue color values + ("r", c_float),("g", c_float),("b", c_float), + ] + +class String(Structure): + """ + See 'types.h' for details. + """ + + MAXLEN = 1024 + + _fields_ = [ + # Binary length of the string excluding the terminal 0. This is NOT the + # logical length of strings containing UTF-8 multibyte sequences! It's + # the number of bytes from the beginning of the string to its end. + ("length", c_uint32), + + # String buffer. Size limit is MAXLEN + ("data", c_char*MAXLEN), + ] + +class MaterialPropertyString(Structure): + """ + See 'MaterialSystem.cpp' for details. + + The size of length is truncated to 4 bytes on 64-bit platforms when used as a + material property (see MaterialSystem.cpp aiMaterial::AddProperty() for details). + """ + + MAXLEN = 1024 + + _fields_ = [ + # Binary length of the string excluding the terminal 0. This is NOT the + # logical length of strings containing UTF-8 multibyte sequences! It's + # the number of bytes from the beginning of the string to its end. + ("length", c_uint32), + + # String buffer. Size limit is MAXLEN + ("data", c_char*MAXLEN), + ] + +class MemoryInfo(Structure): + """ + See 'types.h' for details. + """ + + _fields_ = [ + # Storage allocated for texture data + ("textures", c_uint), + + # Storage allocated for material data + ("materials", c_uint), + + # Storage allocated for mesh data + ("meshes", c_uint), + + # Storage allocated for node data + ("nodes", c_uint), + + # Storage allocated for animation data + ("animations", c_uint), + + # Storage allocated for camera data + ("cameras", c_uint), + + # Storage allocated for light data + ("lights", c_uint), + + # Total storage allocated for the full import. + ("total", c_uint), + ] + +class Quaternion(Structure): + """ + See 'quaternion.h' for details. + """ + + + _fields_ = [ + # w,x,y,z components of the quaternion + ("w", c_float),("x", c_float),("y", c_float),("z", c_float), + ] + +class Face(Structure): + """ + See 'mesh.h' for details. + """ + + _fields_ = [ + # Number of indices defining this face. + # The maximum value for this member is + #AI_MAX_FACE_INDICES. + ("mNumIndices", c_uint), + + # Pointer to the indices array. Size of the array is given in numIndices. + ("mIndices", POINTER(c_uint)), + ] + +class VertexWeight(Structure): + """ + See 'mesh.h' for details. + """ + + _fields_ = [ + # Index of the vertex which is influenced by the bone. + ("mVertexId", c_uint), + + # The strength of the influence in the range (0...1). + # The influence from all bones at one vertex amounts to 1. + ("mWeight", c_float), + ] + +class Matrix4x4(Structure): + """ + See 'matrix4x4.h' for details. + """ + + + _fields_ = [ + ("a1", c_float),("a2", c_float),("a3", c_float),("a4", c_float), + ("b1", c_float),("b2", c_float),("b3", c_float),("b4", c_float), + ("c1", c_float),("c2", c_float),("c3", c_float),("c4", c_float), + ("d1", c_float),("d2", c_float),("d3", c_float),("d4", c_float), + ] + +class Vector3D(Structure): + """ + See 'vector3.h' for details. + """ + + + _fields_ = [ + ("x", c_float),("y", c_float),("z", c_float), + ] + +class MeshKey(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # The time of this key + ("mTime", c_double), + + # Index into the aiMesh::mAnimMeshes array of the + # mesh corresponding to the + #aiMeshAnim hosting this + # key frame. The referenced anim mesh is evaluated + # according to the rules defined in the docs for + #aiAnimMesh. + ("mValue", c_uint), + ] + +class MetadataEntry(Structure): + """ + See 'metadata.h' for details + """ + AI_BOOL = 0 + AI_INT32 = 1 + AI_UINT64 = 2 + AI_FLOAT = 3 + AI_DOUBLE = 4 + AI_AISTRING = 5 + AI_AIVECTOR3D = 6 + AI_META_MAX = 7 + _fields_ = [ + # The type field uniquely identifies the underlying type of the data field + ("mType", c_uint), + ("mData", c_void_p), + ] + +class Metadata(Structure): + """ + See 'metadata.h' for details + """ + _fields_ = [ + # Length of the mKeys and mValues arrays, respectively + ("mNumProperties", c_uint), + + # Arrays of keys, may not be NULL. Entries in this array may not be NULL + # as well. + ("mKeys", POINTER(String)), + + # Arrays of values, may not be NULL. Entries in this array may be NULL + # if the corresponding property key has no assigned value. + ("mValues", POINTER(MetadataEntry)), + ] + +class Node(Structure): + """ + See 'scene.h' for details. + """ + + +Node._fields_ = [ + # The name of the node. + # The name might be empty (length of zero) but all nodes which + # need to be accessed afterwards by bones or anims are usually named. + # Multiple nodes may have the same name, but nodes which are accessed + # by bones (see + #aiBone and + #aiMesh::mBones) *must* be unique. + # Cameras and lights are assigned to a specific node name - if there + # are multiple nodes with this name, they're assigned to each of them. + # <br> + # There are no limitations regarding the characters contained in + # this text. You should be able to handle stuff like whitespace, tabs, + # linefeeds, quotation marks, ampersands, ... . + ("mName", String), + + # The transformation relative to the node's parent. + ("mTransformation", Matrix4x4), + + # Parent node. NULL if this node is the root node. + ("mParent", POINTER(Node)), + + # The number of child nodes of this node. + ("mNumChildren", c_uint), + + # The child nodes of this node. NULL if mNumChildren is 0. + ("mChildren", POINTER(POINTER(Node))), + + # The number of meshes of this node. + ("mNumMeshes", c_uint), + + # The meshes of this node. Each entry is an index into the mesh + ("mMeshes", POINTER(c_uint)), + + # Metadata associated with this node or NULL if there is no metadata. + # Whether any metadata is generated depends on the source file format. + ("mMetadata", POINTER(Metadata)), + ] + +class Light(Structure): + """ + See 'light.h' for details. + """ + + + _fields_ = [ + # The name of the light source. + # There must be a node in the scenegraph with the same name. + # This node specifies the position of the light in the scene + # hierarchy and can be animated. + ("mName", String), + + # The type of the light source. + # aiLightSource_UNDEFINED is not a valid value for this member. + ("mType", c_uint), + + # Position of the light source in space. Relative to the + # transformation of the node corresponding to the light. + # The position is undefined for directional lights. + ("mPosition", Vector3D), + + # Direction of the light source in space. Relative to the + # transformation of the node corresponding to the light. + # The direction is undefined for point lights. The vector + # may be normalized, but it needn't. + ("mDirection", Vector3D), + + # Up direction of the light source in space. Relative to the + # transformation of the node corresponding to the light. + # + # The direction is undefined for point lights. The vector + # may be normalized, but it needn't. + ("mUp", Vector3D), + + # Constant light attenuation factor. + # The intensity of the light source at a given distance 'd' from + # the light's position is + # @code + # Atten = 1/( att0 + att1 + # d + att2 + # d*d) + # @endcode + # This member corresponds to the att0 variable in the equation. + # Naturally undefined for directional lights. + ("mAttenuationConstant", c_float), + + # Linear light attenuation factor. + # The intensity of the light source at a given distance 'd' from + # the light's position is + # @code + # Atten = 1/( att0 + att1 + # d + att2 + # d*d) + # @endcode + # This member corresponds to the att1 variable in the equation. + # Naturally undefined for directional lights. + ("mAttenuationLinear", c_float), + + # Quadratic light attenuation factor. + # The intensity of the light source at a given distance 'd' from + # the light's position is + # @code + # Atten = 1/( att0 + att1 + # d + att2 + # d*d) + # @endcode + # This member corresponds to the att2 variable in the equation. + # Naturally undefined for directional lights. + ("mAttenuationQuadratic", c_float), + + # Diffuse color of the light source + # The diffuse light color is multiplied with the diffuse + # material color to obtain the final color that contributes + # to the diffuse shading term. + ("mColorDiffuse", Color3D), + + # Specular color of the light source + # The specular light color is multiplied with the specular + # material color to obtain the final color that contributes + # to the specular shading term. + ("mColorSpecular", Color3D), + + # Ambient color of the light source + # The ambient light color is multiplied with the ambient + # material color to obtain the final color that contributes + # to the ambient shading term. Most renderers will ignore + # this value it, is just a remaining of the fixed-function pipeline + # that is still supported by quite many file formats. + ("mColorAmbient", Color3D), + + # Inner angle of a spot light's light cone. + # The spot light has maximum influence on objects inside this + # angle. The angle is given in radians. It is 2PI for point + # lights and undefined for directional lights. + ("mAngleInnerCone", c_float), + + # Outer angle of a spot light's light cone. + # The spot light does not affect objects outside this angle. + # The angle is given in radians. It is 2PI for point lights and + # undefined for directional lights. The outer angle must be + # greater than or equal to the inner angle. + # It is assumed that the application uses a smooth + # interpolation between the inner and the outer cone of the + # spot light. + ("mAngleOuterCone", c_float), + + # Size of area light source. + ("mSize", Vector2D), + ] + +class Texture(Structure): + """ + See 'texture.h' for details. + """ + + + _fields_ = [ + # Width of the texture, in pixels + # If mHeight is zero the texture is compressed in a format + # like JPEG. In this case mWidth specifies the size of the + # memory area pcData is pointing to, in bytes. + ("mWidth", c_uint), + + # Height of the texture, in pixels + # If this value is zero, pcData points to an compressed texture + # in any format (e.g. JPEG). + ("mHeight", c_uint), + + # A hint from the loader to make it easier for applications + # to determine the type of embedded textures. + # + # If mHeight != 0 this member is show how data is packed. Hint will consist of + # two parts: channel order and channel bitness (count of the bits for every + # color channel). For simple parsing by the viewer it's better to not omit + # absent color channel and just use 0 for bitness. For example: + # 1. Image contain RGBA and 8 bit per channel, achFormatHint == "rgba8888"; + # 2. Image contain ARGB and 8 bit per channel, achFormatHint == "argb8888"; + # 3. Image contain RGB and 5 bit for R and B channels and 6 bit for G channel, + # achFormatHint == "rgba5650"; + # 4. One color image with B channel and 1 bit for it, achFormatHint == "rgba0010"; + # If mHeight == 0 then achFormatHint is set set to '\\0\\0\\0\\0' if the loader has no additional + # information about the texture file format used OR the + # file extension of the format without a trailing dot. If there + # are multiple file extensions for a format, the shortest + # extension is chosen (JPEG maps to 'jpg', not to 'jpeg'). + # E.g. 'dds\\0', 'pcx\\0', 'jpg\\0'. All characters are lower-case. + # The fourth character will always be '\\0'. + ("achFormatHint", c_char*9), + + # Data of the texture. + # Points to an array of mWidth + # mHeight aiTexel's. + # The format of the texture data is always ARGB8888 to + # make the implementation for user of the library as easy + # as possible. If mHeight = 0 this is a pointer to a memory + # buffer of size mWidth containing the compressed texture + # data. Good luck, have fun! + ("pcData", POINTER(Texel)), + + # Texture original filename + # Used to get the texture reference + ("mFilename", String), + ] + +class Ray(Structure): + """ + See 'types.h' for details. + """ + + _fields_ = [ + # Position and direction of the ray + ("pos", Vector3D),("dir", Vector3D), + ] + +class UVTransform(Structure): + """ + See 'material.h' for details. + """ + + _fields_ = [ + # Translation on the u and v axes. + # The default value is (0|0). + ("mTranslation", Vector2D), + + # Scaling on the u and v axes. + # The default value is (1|1). + ("mScaling", Vector2D), + + # Rotation - in counter-clockwise direction. + # The rotation angle is specified in radians. The + # rotation center is 0.5f|0.5f. The default value + # 0.f. + ("mRotation", c_float), + ] + +class MaterialProperty(Structure): + """ + See 'material.h' for details. + """ + + _fields_ = [ + # Specifies the name of the property (key) + # Keys are generally case insensitive. + ("mKey", String), + + # Textures: Specifies their exact usage semantic. + # For non-texture properties, this member is always 0 + # (or, better-said, + #aiTextureType_NONE). + ("mSemantic", c_uint), + + # Textures: Specifies the index of the texture. + # For non-texture properties, this member is always 0. + ("mIndex", c_uint), + + # Size of the buffer mData is pointing to, in bytes. + # This value may not be 0. + ("mDataLength", c_uint), + + # Type information for the property. + # Defines the data layout inside the data buffer. This is used + # by the library internally to perform debug checks and to + # utilize proper type conversions. + # (It's probably a hacky solution, but it works.) + ("mType", c_uint), + + # Binary buffer to hold the property's value. + # The size of the buffer is always mDataLength. + ("mData", POINTER(c_char)), + ] + +class Material(Structure): + """ + See 'material.h' for details. + """ + + _fields_ = [ + # List of all material properties loaded. + ("mProperties", POINTER(POINTER(MaterialProperty))), + + # Number of properties in the data base + ("mNumProperties", c_uint), + + # Storage allocated + ("mNumAllocated", c_uint), + ] + +class Bone(Structure): + """ + See 'mesh.h' for details. + """ + + _fields_ = [ + # The name of the bone. + ("mName", String), + + # The number of vertices affected by this bone + # The maximum value for this member is + #AI_MAX_BONE_WEIGHTS. + ("mNumWeights", c_uint), + + # The vertices affected by this bone + ("mWeights", POINTER(VertexWeight)), + + # Matrix that transforms from mesh space to bone space in bind pose + ("mOffsetMatrix", Matrix4x4), + ] + + +class AnimMesh(Structure): + """ + See 'mesh.h' for details. + """ + + AI_MAX_NUMBER_OF_TEXTURECOORDS = 0x8 + AI_MAX_NUMBER_OF_COLOR_SETS = 0x8 + + _fields_ = [ + # Anim Mesh name + ("mName", String), + + # Replacement for aiMesh::mVertices. If this array is non-NULL, + # it *must* contain mNumVertices entries. The corresponding + # array in the host mesh must be non-NULL as well - animation + # meshes may neither add or nor remove vertex components (if + # a replacement array is NULL and the corresponding source + # array is not, the source data is taken instead) + ("mVertices", POINTER(Vector3D)), + + # Replacement for aiMesh::mNormals. + ("mNormals", POINTER(Vector3D)), + + # Replacement for aiMesh::mTangents. + ("mTangents", POINTER(Vector3D)), + + # Replacement for aiMesh::mBitangents. + ("mBitangents", POINTER(Vector3D)), + + # Replacement for aiMesh::mColors + ("mColors", POINTER(Color4D) * AI_MAX_NUMBER_OF_COLOR_SETS), + + # Replacement for aiMesh::mTextureCoords + ("mTextureCoords", POINTER(Vector3D) * AI_MAX_NUMBER_OF_TEXTURECOORDS), + + # The number of vertices in the aiAnimMesh, and thus the length of all + # the member arrays. + # + # This has always the same value as the mNumVertices property in the + # corresponding aiMesh. It is duplicated here merely to make the length + # of the member arrays accessible even if the aiMesh is not known, e.g. + # from language bindings. + ("mNumVertices", c_uint), + + # Weight of the AnimMesh. + ("mWeight", c_float), + ] + + +class Mesh(Structure): + """ + See 'mesh.h' for details. + """ + + AI_MAX_FACE_INDICES = 0x7fff + AI_MAX_BONE_WEIGHTS = 0x7fffffff + AI_MAX_VERTICES = 0x7fffffff + AI_MAX_FACES = 0x7fffffff + AI_MAX_NUMBER_OF_COLOR_SETS = 0x8 + AI_MAX_NUMBER_OF_TEXTURECOORDS = 0x8 + + _fields_ = [ # Bitwise combination of the members of the + #aiPrimitiveType enum. + # This specifies which types of primitives are present in the mesh. + # The "SortByPrimitiveType"-Step can be used to make sure the + # output meshes consist of one primitive type each. + ("mPrimitiveTypes", c_uint), + + # The number of vertices in this mesh. + # This is also the size of all of the per-vertex data arrays. + # The maximum value for this member is + #AI_MAX_VERTICES. + ("mNumVertices", c_uint), + + # The number of primitives (triangles, polygons, lines) in this mesh. + # This is also the size of the mFaces array. + # The maximum value for this member is + #AI_MAX_FACES. + ("mNumFaces", c_uint), + + # Vertex positions. + # This array is always present in a mesh. The array is + # mNumVertices in size. + ("mVertices", POINTER(Vector3D)), + + # Vertex normals. + # The array contains normalized vectors, NULL if not present. + # The array is mNumVertices in size. Normals are undefined for + # point and line primitives. A mesh consisting of points and + # lines only may not have normal vectors. Meshes with mixed + # primitive types (i.e. lines and triangles) may have normals, + # but the normals for vertices that are only referenced by + # point or line primitives are undefined and set to QNaN (WARN: + # qNaN compares to inequal to *everything*, even to qNaN itself. + # Using code like this to check whether a field is qnan is: + # @code + #define IS_QNAN(f) (f != f) + # @endcode + # still dangerous because even 1.f == 1.f could evaluate to false! ( + # remember the subtleties of IEEE754 artithmetics). Use stuff like + # @c fpclassify instead. + # @note Normal vectors computed by Assimp are always unit-length. + # However, this needn't apply for normals that have been taken + # directly from the model file. + ("mNormals", POINTER(Vector3D)), + + # Vertex tangents. + # The tangent of a vertex points in the direction of the positive + # X texture axis. The array contains normalized vectors, NULL if + # not present. The array is mNumVertices in size. A mesh consisting + # of points and lines only may not have normal vectors. Meshes with + # mixed primitive types (i.e. lines and triangles) may have + # normals, but the normals for vertices that are only referenced by + # point or line primitives are undefined and set to qNaN. See + # the + #mNormals member for a detailed discussion of qNaNs. + # @note If the mesh contains tangents, it automatically also + # contains bitangents (the bitangent is just the cross product of + # tangent and normal vectors). + ("mTangents", POINTER(Vector3D)), + + # Vertex bitangents. + # The bitangent of a vertex points in the direction of the positive + # Y texture axis. The array contains normalized vectors, NULL if not + # present. The array is mNumVertices in size. + # @note If the mesh contains tangents, it automatically also contains + # bitangents. + ("mBitangents", POINTER(Vector3D)), + + # Vertex color sets. + # A mesh may contain 0 to + #AI_MAX_NUMBER_OF_COLOR_SETS vertex + # colors per vertex. NULL if not present. Each array is + # mNumVertices in size if present. + ("mColors", POINTER(Color4D)*AI_MAX_NUMBER_OF_COLOR_SETS), + + # Vertex texture coords, also known as UV channels. + # A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS per + # vertex. NULL if not present. The array is mNumVertices in size. + ("mTextureCoords", POINTER(Vector3D)*AI_MAX_NUMBER_OF_TEXTURECOORDS), + + # Specifies the number of components for a given UV channel. + # Up to three channels are supported (UVW, for accessing volume + # or cube maps). If the value is 2 for a given channel n, the + # component p.z of mTextureCoords[n][p] is set to 0.0f. + # If the value is 1 for a given channel, p.y is set to 0.0f, too. + # @note 4D coords are not supported + ("mNumUVComponents", c_uint*AI_MAX_NUMBER_OF_TEXTURECOORDS), + + # The faces the mesh is constructed from. + # Each face refers to a number of vertices by their indices. + # This array is always present in a mesh, its size is given + # in mNumFaces. If the + #AI_SCENE_FLAGS_NON_VERBOSE_FORMAT + # is NOT set each face references an unique set of vertices. + ("mFaces", POINTER(Face)), + + # The number of bones this mesh contains. + # Can be 0, in which case the mBones array is NULL. + ("mNumBones", c_uint), + + # The bones of this mesh. + # A bone consists of a name by which it can be found in the + # frame hierarchy and a set of vertex weights. + ("mBones", POINTER(POINTER(Bone))), + + # The material used by this mesh. + # A mesh does use only a single material. If an imported model uses + # multiple materials, the import splits up the mesh. Use this value + # as index into the scene's material list. + ("mMaterialIndex", c_uint), + + # Name of the mesh. Meshes can be named, but this is not a + # requirement and leaving this field empty is totally fine. + # There are mainly three uses for mesh names: + # - some formats name nodes and meshes independently. + # - importers tend to split meshes up to meet the + # one-material-per-mesh requirement. Assigning + # the same (dummy) name to each of the result meshes + # aids the caller at recovering the original mesh + # partitioning. + # - Vertex animations refer to meshes by their names. + ("mName", String), + + # The number of attachment meshes. Note! Currently only works with Collada loader. + ("mNumAnimMeshes", c_uint), + + # Attachment meshes for this mesh, for vertex-based animation. + # Attachment meshes carry replacement data for some of the + # mesh'es vertex components (usually positions, normals). + # Note! Currently only works with Collada loader. + ("mAnimMeshes", POINTER(POINTER(AnimMesh))), + + # Method of morphing when animeshes are specified. + ("mMethod", c_uint), + + ] + +class Camera(Structure): + """ + See 'camera.h' for details. + """ + + + _fields_ = [ + # The name of the camera. + # There must be a node in the scenegraph with the same name. + # This node specifies the position of the camera in the scene + # hierarchy and can be animated. + ("mName", String), + + # Position of the camera relative to the coordinate space + # defined by the corresponding node. + # The default value is 0|0|0. + ("mPosition", Vector3D), + + # 'Up' - vector of the camera coordinate system relative to + # the coordinate space defined by the corresponding node. + # The 'right' vector of the camera coordinate system is + # the cross product of the up and lookAt vectors. + # The default value is 0|1|0. The vector + # may be normalized, but it needn't. + ("mUp", Vector3D), + + # 'LookAt' - vector of the camera coordinate system relative to + # the coordinate space defined by the corresponding node. + # This is the viewing direction of the user. + # The default value is 0|0|1. The vector + # may be normalized, but it needn't. + ("mLookAt", Vector3D), + + # Half horizontal field of view angle, in radians. + # The field of view angle is the angle between the center + # line of the screen and the left or right border. + # The default value is 1/4PI. + ("mHorizontalFOV", c_float), + + # Distance of the near clipping plane from the camera. + # The value may not be 0.f (for arithmetic reasons to prevent + # a division through zero). The default value is 0.1f. + ("mClipPlaneNear", c_float), + + # Distance of the far clipping plane from the camera. + # The far clipping plane must, of course, be further away than the + # near clipping plane. The default value is 1000.f. The ratio + # between the near and the far plane should not be too + # large (between 1000-10000 should be ok) to avoid floating-point + # inaccuracies which could lead to z-fighting. + ("mClipPlaneFar", c_float), + + # Screen aspect ratio. + # This is the ration between the width and the height of the + # screen. Typical values are 4/3, 1/2 or 1/1. This value is + # 0 if the aspect ratio is not defined in the source file. + # 0 is also the default value. + ("mAspect", c_float), + ] + +class VectorKey(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # The time of this key + ("mTime", c_double), + + # The value of this key + ("mValue", Vector3D), + ] + +class QuatKey(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # The time of this key + ("mTime", c_double), + + # The value of this key + ("mValue", Quaternion), + ] + +class MeshMorphKey(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # The time of this key + ("mTime", c_double), + + # The values and weights at the time of this key + ("mValues", POINTER(c_uint)), + ("mWeights", POINTER(c_double)), + + # The number of values and weights + ("mNumValuesAndWeights", c_uint), + + ] + +class NodeAnim(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # The name of the node affected by this animation. The node + # must exist and it must be unique. + ("mNodeName", String), + + # The number of position keys + ("mNumPositionKeys", c_uint), + + # The position keys of this animation channel. Positions are + # specified as 3D vector. The array is mNumPositionKeys in size. + # If there are position keys, there will also be at least one + # scaling and one rotation key. + ("mPositionKeys", POINTER(VectorKey)), + + # The number of rotation keys + ("mNumRotationKeys", c_uint), + + # The rotation keys of this animation channel. Rotations are + # given as quaternions, which are 4D vectors. The array is + # mNumRotationKeys in size. + # If there are rotation keys, there will also be at least one + # scaling and one position key. + ("mRotationKeys", POINTER(QuatKey)), + + # The number of scaling keys + ("mNumScalingKeys", c_uint), + + # The scaling keys of this animation channel. Scalings are + # specified as 3D vector. The array is mNumScalingKeys in size. + # If there are scaling keys, there will also be at least one + # position and one rotation key. + ("mScalingKeys", POINTER(VectorKey)), + + # Defines how the animation behaves before the first + # key is encountered. + # The default value is aiAnimBehaviour_DEFAULT (the original + # transformation matrix of the affected node is used). + ("mPreState", c_uint), + + # Defines how the animation behaves after the last + # key was processed. + # The default value is aiAnimBehaviour_DEFAULT (the original + # transformation matrix of the affected node is taken). + ("mPostState", c_uint), + ] + +class MeshAnim(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # Name of the mesh to be animated. An empty string is not allowed, + # animated meshes need to be named (not necessarily uniquely, + # the name can basically serve as wild-card to select a group + # of meshes with similar animation setup) + ("mName", String), + + # Size of the #mKeys array. Must be 1, at least. + ("mNumKeys", c_uint), + + # Key frames of the animation. May not be NULL. + ("mKeys", POINTER(MeshKey)), + ] + +class MeshMorphAnim(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # Name of the mesh to be animated. An empty string is not allowed, + # animated meshes need to be named (not necessarily uniquely, + # the name can basically serve as wildcard to select a group + # of meshes with similar animation setup) + ("mName", String), + + # Size of the #mKeys array. Must be 1, at least. + ("mNumKeys", c_uint), + + # Key frames of the animation. May not be NULL. + ("mKeys", POINTER(MeshMorphKey)), + ] + + +class Animation(Structure): + """ + See 'anim.h' for details. + """ + + _fields_ = [ + # The name of the animation. If the modeling package this data was + # exported from does support only a single animation channel, this + # name is usually empty (length is zero). + ("mName", String), + + # Duration of the animation in ticks. + ("mDuration", c_double), + + # Ticks per second. 0 if not specified in the imported file + ("mTicksPerSecond", c_double), + + # The number of bone animation channels. Each channel affects + # a single node. + ("mNumChannels", c_uint), + + # The node animation channels. Each channel affects a single node. + # The array is mNumChannels in size. + ("mChannels", POINTER(POINTER(NodeAnim))), + + # The number of mesh animation channels. Each channel affects + # a single mesh and defines vertex-based animation. + ("mNumMeshChannels", c_uint), + + # The mesh animation channels. Each channel affects a single mesh. + # The array is mNumMeshChannels in size. + ("mMeshChannels", POINTER(POINTER(MeshAnim))), + + # The number of mesh animation channels. Each channel affects + # a single mesh and defines morphing animation. + ("mNumMorphMeshChannels", c_uint), + + # The morph mesh animation channels. Each channel affects a single mesh. + # The array is mNumMorphMeshChannels in size. + ("mMorphMeshChannels", POINTER(POINTER(MeshMorphAnim))), + + ] + +class ExportDataBlob(Structure): + """ + See 'cexport.h' for details. + + Note that the '_fields_' definition is outside the class to allow the 'next' field to be recursive + """ + pass + +ExportDataBlob._fields_ = [ + # Size of the data in bytes + ("size", c_size_t), + + # The data. + ("data", c_void_p), + + # Name of the blob. An empty string always + # indicates the first (and primary) blob, + # which contains the actual file data. + # Any other blobs are auxiliary files produced + # by exporters (i.e. material files). Existence + # of such files depends on the file format. Most + # formats don't split assets across multiple files. + # + # If used, blob names usually contain the file + # extension that should be used when writing + # the data to disc. + ("name", String), + + # Pointer to the next blob in the chain or NULL if there is none. + ("next", POINTER(ExportDataBlob)), + ] + + +class Scene(Structure): + """ + See 'aiScene.h' for details. + """ + + AI_SCENE_FLAGS_INCOMPLETE = 0x1 + AI_SCENE_FLAGS_VALIDATED = 0x2 + AI_SCENE_FLAGS_VALIDATION_WARNING = 0x4 + AI_SCENE_FLAGS_NON_VERBOSE_FORMAT = 0x8 + AI_SCENE_FLAGS_TERRAIN = 0x10 + AI_SCENE_FLAGS_ALLOW_SHARED = 0x20 + + _fields_ = [ + # Any combination of the AI_SCENE_FLAGS_XXX flags. By default + # this value is 0, no flags are set. Most applications will + # want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE + # bit set. + ("mFlags", c_uint), + + # The root node of the hierarchy. + # There will always be at least the root node if the import + # was successful (and no special flags have been set). + # Presence of further nodes depends on the format and content + # of the imported file. + ("mRootNode", POINTER(Node)), + + # The number of meshes in the scene. + ("mNumMeshes", c_uint), + + # The array of meshes. + # Use the indices given in the aiNode structure to access + # this array. The array is mNumMeshes in size. If the + # AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always + # be at least ONE material. + ("mMeshes", POINTER(POINTER(Mesh))), + + # The number of materials in the scene. + ("mNumMaterials", c_uint), + + # The array of materials. + # Use the index given in each aiMesh structure to access this + # array. The array is mNumMaterials in size. If the + # AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always + # be at least ONE material. + ("mMaterials", POINTER(POINTER(Material))), + + # The number of animations in the scene. + ("mNumAnimations", c_uint), + + # The array of animations. + # All animations imported from the given file are listed here. + # The array is mNumAnimations in size. + ("mAnimations", POINTER(POINTER(Animation))), + + # The number of textures embedded into the file + ("mNumTextures", c_uint), + + # The array of embedded textures. + # Not many file formats embed their textures into the file. + # An example is Quake's MDL format (which is also used by + # some GameStudio versions) + ("mTextures", POINTER(POINTER(Texture))), + + # The number of light sources in the scene. Light sources + # are fully optional, in most cases this attribute will be 0 + ("mNumLights", c_uint), + + # The array of light sources. + # All light sources imported from the given file are + # listed here. The array is mNumLights in size. + ("mLights", POINTER(POINTER(Light))), + + # The number of cameras in the scene. Cameras + # are fully optional, in most cases this attribute will be 0 + ("mNumCameras", c_uint), + + # The array of cameras. + # All cameras imported from the given file are listed here. + # The array is mNumCameras in size. The first camera in the + # array (if existing) is the default camera view into + # the scene. + ("mCameras", POINTER(POINTER(Camera))), + + # This data contains global metadata which belongs to the scene like + # unit-conversions, versions, vendors or other model-specific data. This + # can be used to store format-specific metadata as well. + ("mMetadata", POINTER(Metadata)), + + # Internal data, do not touch + ("mPrivate", POINTER(c_char)), + ] + +assimp_structs_as_tuple = (Matrix4x4, + Matrix3x3, + Vector2D, + Vector3D, + Color3D, + Color4D, + Quaternion, + Plane, + Texel) diff --git a/libs/assimp/port/PyAssimp/scripts/3d_viewer.py b/libs/assimp/port/PyAssimp/scripts/3d_viewer.py new file mode 100755 index 0000000..08a6266 --- /dev/null +++ b/libs/assimp/port/PyAssimp/scripts/3d_viewer.py @@ -0,0 +1,1318 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +""" This program loads a model with PyASSIMP, and display it. + +Based on: +- pygame code from http://3dengine.org/Spectator_%28PyOpenGL%29 +- http://www.lighthouse3d.com/tutorials +- http://www.songho.ca/opengl/gl_transform.html +- http://code.activestate.com/recipes/325391/ +- ASSIMP's C++ SimpleOpenGL viewer + +Authors: Séverin Lemaignan, 2012-2016 +""" +import sys +import logging + +logger = logging.getLogger("pyassimp") +gllogger = logging.getLogger("OpenGL") +gllogger.setLevel(logging.WARNING) +logging.basicConfig(level=logging.INFO) + +import OpenGL + +OpenGL.ERROR_CHECKING = False +OpenGL.ERROR_LOGGING = False +# OpenGL.ERROR_ON_COPY = True +# OpenGL.FULL_LOGGING = True +from OpenGL.GL import * +from OpenGL.arrays import vbo +from OpenGL.GL import shaders + +import pygame +import pygame.font +import pygame.image + +import math, random +from numpy import linalg + +import pyassimp +from pyassimp.postprocess import * +from pyassimp.helper import * +import transformations + +ROTATION_180_X = numpy.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], dtype=numpy.float32) + +# rendering mode +BASE = "BASE" +COLORS = "COLORS" +SILHOUETTE = "SILHOUETTE" +HELPERS = "HELPERS" + +# Entities type +ENTITY = "entity" +CAMERA = "camera" +MESH = "mesh" + +FLAT_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; + +varying vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +FLAT_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; + +out vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; +attribute vec3 a_normal; + +varying vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; +in vec3 a_normal; + +out vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_FRAGMENT_SHADER_120 = """ +#version 120 + +varying vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +BASIC_FRAGMENT_SHADER_130 = """ +#version 130 + +in vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +GOOCH_VERTEX_SHADER_120 = """ +#version 120 + +// attributes +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_VERTEX_SHADER_130 = """ +#version 130 + +// attributes +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +out vec3 o_normal; +out vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_FRAGMENT_SHADER_120 = """ +#version 120 + +// data from vertex shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + gl_FragColor.rgb = colorOut; + gl_FragColor.a = 1; +} +""" + +GOOCH_FRAGMENT_SHADER_130 = """ +#version 130 + +// data from vertex shader +in vec3 o_normal; +in vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +// output to framebuffer +out vec4 resultingColor; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + resultingColor.rgb = colorOut; + resultingColor.a = 1; +} +""" + +SILHOUETTE_VERTEX_SHADER_120 = """ +#version 120 + +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +varying vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" + +SILHOUETTE_VERTEX_SHADER_130 = """ +#version 130 + +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +out vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" +DEFAULT_CLIP_PLANE_NEAR = 0.001 +DEFAULT_CLIP_PLANE_FAR = 1000.0 + + +def get_world_transform(scene, node): + if node == scene.rootnode: + return numpy.identity(4, dtype=numpy.float32) + + parents = reversed(_get_parent_chain(scene, node, [])) + parent_transform = reduce(numpy.dot, [p.transformation for p in parents]) + return numpy.dot(parent_transform, node.transformation) + + +def _get_parent_chain(scene, node, parents): + parent = node.parent + + parents.append(parent) + + if parent == scene.rootnode: + return parents + + return _get_parent_chain(scene, parent, parents) + + +class DefaultCamera: + def __init__(self, w, h, fov): + self.name = "default camera" + self.type = CAMERA + self.clipplanenear = DEFAULT_CLIP_PLANE_NEAR + self.clipplanefar = DEFAULT_CLIP_PLANE_FAR + self.aspect = w / h + self.horizontalfov = fov * math.pi / 180 + self.transformation = numpy.array([[0.68, -0.32, 0.65, 7.48], + [0.73, 0.31, -0.61, -6.51], + [-0.01, 0.89, 0.44, 5.34], + [0., 0., 0., 1.]], dtype=numpy.float32) + + self.transformation = numpy.dot(self.transformation, ROTATION_180_X) + + def __str__(self): + return self.name + + +class PyAssimp3DViewer: + base_name = "PyASSIMP 3D viewer" + + def __init__(self, model, w=1024, h=768): + + self.w = w + self.h = h + + pygame.init() + pygame.display.set_caption(self.base_name) + pygame.display.set_mode((w, h), pygame.OPENGL | pygame.DOUBLEBUF) + + glClearColor(0.18, 0.18, 0.18, 1.0) + + shader_compilation_succeeded = False + try: + self.set_shaders_v130() + self.prepare_shaders() + except RuntimeError, message: + sys.stderr.write("%s\n" % message) + sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") + + if not shader_compilation_succeeded: + self.set_shaders_v120() + self.prepare_shaders() + + self.scene = None + self.meshes = {} # stores the OpenGL vertex/faces/normals buffers pointers + + self.node2colorid = {} # stores a color ID for each node. Useful for mouse picking and visibility checking + self.colorid2node = {} # reverse dict of node2colorid + + self.currently_selected = None + self.moving = False + self.moving_situation = None + + self.default_camera = DefaultCamera(self.w, self.h, fov=70) + self.cameras = [self.default_camera] + + self.current_cam_index = 0 + self.current_cam = self.default_camera + self.set_camera_projection() + + self.load_model(model) + + # user interactions + self.focal_point = [0, 0, 0] + self.is_rotating = False + self.is_panning = False + self.is_zooming = False + + def set_shaders_v120(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_120 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_120 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_120 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_120 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_120 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_120 + + def set_shaders_v130(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_130 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_130 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_130 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_130 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_130 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_130 + + def prepare_shaders(self): + + ### Base shader + vertex = shaders.compileShader(self.BASIC_VERTEX_SHADER, GL_VERTEX_SHADER) + fragment = shaders.compileShader(self.BASIC_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + + self.shader = shaders.compileProgram(vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse'), + ('a_vertex', + 'a_normal'), self.shader) + + ### Flat shader + flatvertex = shaders.compileShader(self.FLAT_VERTEX_SHADER, GL_VERTEX_SHADER) + self.flatshader = shaders.compileProgram(flatvertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_materialDiffuse',), + ('a_vertex',), self.flatshader) + + ### Silhouette shader + silh_vertex = shaders.compileShader(self.SILHOUETTE_VERTEX_SHADER, GL_VERTEX_SHADER) + self.silhouette_shader = shaders.compileProgram(silh_vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_modelViewMatrix', + 'u_materialDiffuse', + 'u_bordersize' # width of the silhouette + ), + ('a_vertex', + 'a_normal'), self.silhouette_shader) + + ### Gooch shader + gooch_vertex = shaders.compileShader(self.GOOCH_VERTEX_SHADER, GL_VERTEX_SHADER) + gooch_fragment = shaders.compileShader(self.GOOCH_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + self.gooch_shader = shaders.compileProgram(gooch_vertex, gooch_fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse', + 'u_coolColor', + 'u_warmColor', + 'u_alpha', + 'u_beta' + ), + ('a_vertex', + 'a_normal'), self.gooch_shader) + + @staticmethod + def set_shader_accessors(uniforms, attributes, shader): + # add accessors to the shaders uniforms and attributes + for uniform in uniforms: + location = glGetUniformLocation(shader, uniform) + if location in (None, -1): + raise RuntimeError('No uniform: %s (maybe it is not used ' + 'anymore and has been optimized out by' + ' the shader compiler)' % uniform) + setattr(shader, uniform, location) + + for attribute in attributes: + location = glGetAttribLocation(shader, attribute) + if location in (None, -1): + raise RuntimeError('No attribute: %s' % attribute) + setattr(shader, attribute, location) + + @staticmethod + def prepare_gl_buffers(mesh): + + mesh.gl = {} + + # Fill the buffer for vertex and normals positions + v = numpy.array(mesh.vertices, 'f') + n = numpy.array(mesh.normals, 'f') + + mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v, n))) + + # Fill the buffer for vertex positions + mesh.gl["faces"] = glGenBuffers(1) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + numpy.array(mesh.faces, dtype=numpy.int32), + GL_STATIC_DRAW) + + mesh.gl["nbfaces"] = len(mesh.faces) + + # Unbind buffers + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + @staticmethod + def get_rgb_from_colorid(colorid): + r = (colorid >> 0) & 0xff + g = (colorid >> 8) & 0xff + b = (colorid >> 16) & 0xff + + return r, g, b + + def get_color_id(self): + id = random.randint(0, 256 * 256 * 256) + if id not in self.colorid2node: + return id + else: + return self.get_color_id() + + def glize(self, scene, node): + + logger.info("Loading node <%s>" % node) + node.selected = True if self.currently_selected and self.currently_selected == node else False + + node.transformation = node.transformation.astype(numpy.float32) + + if node.meshes: + node.type = MESH + colorid = self.get_color_id() + self.colorid2node[colorid] = node + self.node2colorid[node.name] = colorid + + elif node.name in [c.name for c in scene.cameras]: + + # retrieve the ASSIMP camera object + [cam] = [c for c in scene.cameras if c.name == node.name] + node.type = CAMERA + logger.info("Added camera <%s>" % node.name) + logger.info("Camera position: %.3f, %.3f, %.3f" % tuple(node.transformation[:, 3][:3].tolist())) + self.cameras.append(node) + node.clipplanenear = cam.clipplanenear + node.clipplanefar = cam.clipplanefar + + if numpy.allclose(cam.lookat, [0, 0, -1]) and numpy.allclose(cam.up, [0, 1, 0]): # Cameras in .blend files + + # Rotate by 180deg around X to have Z pointing forward + node.transformation = numpy.dot(node.transformation, ROTATION_180_X) + else: + raise RuntimeError( + "I do not know how to normalize this camera orientation: lookat=%s, up=%s" % (cam.lookat, cam.up)) + + if cam.aspect == 0.0: + logger.warning("Camera aspect not set. Setting to default 4:3") + node.aspect = 1.333 + else: + node.aspect = cam.aspect + + node.horizontalfov = cam.horizontalfov + + else: + node.type = ENTITY + + for child in node.children: + self.glize(scene, child) + + def load_model(self, path, postprocess=aiProcessPreset_TargetRealtime_MaxQuality): + logger.info("Loading model:" + path + "...") + + if postprocess: + self.scene = pyassimp.load(path, processing=postprocess) + else: + self.scene = pyassimp.load(path) + logger.info("Done.") + + scene = self.scene + # log some statistics + logger.info(" meshes: %d" % len(scene.meshes)) + logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) + logger.info(" materials: %d" % len(scene.materials)) + self.bb_min, self.bb_max = get_bounding_box(self.scene) + logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) + + self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] + + for index, mesh in enumerate(scene.meshes): + self.prepare_gl_buffers(mesh) + + self.glize(scene, scene.rootnode) + + # Finally release the model + pyassimp.release(scene) + logger.info("Ready for 3D rendering!") + + def cycle_cameras(self): + + self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras) + self.current_cam = self.cameras[self.current_cam_index] + self.set_camera_projection(self.current_cam) + logger.info("Switched to camera <%s>" % self.current_cam) + + def set_overlay_projection(self): + glViewport(0, 0, self.w, self.h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(0.0, self.w - 1.0, 0.0, self.h - 1.0, -1.0, 1.0) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def set_camera_projection(self, camera=None): + + if not camera: + camera = self.current_cam + + znear = camera.clipplanenear or DEFAULT_CLIP_PLANE_NEAR + zfar = camera.clipplanefar or DEFAULT_CLIP_PLANE_FAR + aspect = camera.aspect + fov = camera.horizontalfov + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + + # Compute gl frustrum + tangent = math.tan(fov / 2.) + h = znear * tangent + w = h * aspect + + # params: left, right, bottom, top, near, far + glFrustum(-w, w, -h, h, znear, zfar) + # equivalent to: + # gluPerspective(fov * 180/math.pi, aspect, znear, zfar) + + self.projection_matrix = glGetFloatv(GL_PROJECTION_MATRIX).transpose() + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def render_colors(self): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + glEnable(GL_CULL_FACE) + + glUseProgram(self.flatshader) + + glUniformMatrix4fv(self.flatshader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, self.flatshader, mode=COLORS) + + glUseProgram(0) + + def get_hovered_node(self, mousex, mousey): + """ + Attention: The performances of this method relies heavily on the size of the display! + """ + + # mouse out of the window? + if mousex < 0 or mousex >= self.w or mousey < 0 or mousey >= self.h: + return None + + self.render_colors() + # Capture image from the OpenGL buffer + buf = (GLubyte * (3 * self.w * self.h))(0) + glReadPixels(0, 0, self.w, self.h, GL_RGB, GL_UNSIGNED_BYTE, buf) + + # Reinterpret the RGB pixel buffer as a 1-D array of 24bits colors + a = numpy.ndarray(len(buf), numpy.dtype('>u1'), buf) + colors = numpy.zeros(len(buf) / 3, numpy.dtype('<u4')) + for i in range(3): + colors.view(dtype='>u1')[i::4] = a.view(dtype='>u1')[i::3] + + colorid = colors[mousex + mousey * self.w] + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + if colorid in self.colorid2node: + return self.colorid2node[colorid] + + def render(self, wireframe=False, twosided=False): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) + glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) + + self.render_grid() + + self.recursive_render(self.scene.rootnode, None, mode=HELPERS) + + ### First, the silhouette + + if False: + shader = self.silhouette_shader + + # glDepthMask(GL_FALSE) + glCullFace(GL_FRONT) # cull front faces + + glUseProgram(shader) + glUniform1f(shader.u_bordersize, 0.01) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader, mode=SILHOUETTE) + + glUseProgram(0) + + ### Then, inner shading + # glDepthMask(GL_TRUE) + glCullFace(GL_BACK) + + use_gooch = False + if use_gooch: + shader = self.gooch_shader + + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + ##### GOOCH specific + glUniform3f(shader.u_coolColor, 159.0 / 255, 148.0 / 255, 255.0 / 255) + glUniform3f(shader.u_warmColor, 255.0 / 255, 75.0 / 255, 75.0 / 255) + glUniform1f(shader.u_alpha, .25) + glUniform1f(shader.u_beta, .25) + ######### + else: + shader = self.shader + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader) + + glUseProgram(0) + + def render_axis(self, + transformation=numpy.identity(4, dtype=numpy.float32), + label=None, + size=0.2, + selected=False): + m = transformation.transpose() # OpenGL row major + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(3 if selected else 1) + + size = 2 * size if selected else size + + glBegin(GL_LINES) + + # draw line for x axis + glColor3f(1.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(size, 0.0, 0.0) + + # draw line for y axis + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, size, 0.0) + + # draw line for Z axis + glColor3f(0.0, 0.0, 1.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, size) + + glEnd() + + if label: + self.showtext(label) + + glPopMatrix() + + @staticmethod + def render_camera(camera, transformation): + + m = transformation.transpose() # OpenGL row major + + aspect = camera.aspect + + u = 0.1 # unit size (in m) + l = 3 * u # length of the camera cone + f = 3 * u # aperture of the camera cone + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(2) + glBegin(GL_LINE_STRIP) + + glColor3f(.2, .2, .2) + + glVertex3f(u, u, -u) + glVertex3f(u, -u, -u) + glVertex3f(-u, -u, -u) + glVertex3f(-u, u, -u) + glVertex3f(u, u, -u) + + glVertex3f(u, u, 0.0) + glVertex3f(u, -u, 0.0) + glVertex3f(-u, -u, 0.0) + glVertex3f(-u, u, 0.0) + glVertex3f(u, u, 0.0) + + glVertex3f(f * aspect, f, l) + glVertex3f(f * aspect, -f, l) + glVertex3f(-f * aspect, -f, l) + glVertex3f(-f * aspect, f, l) + glVertex3f(f * aspect, f, l) + + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(u, -u, -u) + glVertex3f(u, -u, 0.0) + glVertex3f(f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, -u, -u) + glVertex3f(-u, -u, 0.0) + glVertex3f(-f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, u, -u) + glVertex3f(-u, u, 0.0) + glVertex3f(-f * aspect, f, l) + glEnd() + + glPopMatrix() + + @staticmethod + def render_grid(): + + glLineWidth(1) + glColor3f(0.5, 0.5, 0.5) + glBegin(GL_LINES) + for i in range(-10, 11): + glVertex3f(i, -10.0, 0.0) + glVertex3f(i, 10.0, 0.0) + + for i in range(-10, 11): + glVertex3f(-10.0, i, 0.0) + glVertex3f(10.0, i, 0.0) + glEnd() + + def recursive_render(self, node, shader, mode=BASE, with_normals=True): + """ Main recursive rendering method. + """ + + normals = with_normals + + if mode == COLORS: + normals = False + + + if not hasattr(node, "selected"): + node.selected = False + + m = get_world_transform(self.scene, node) + + # HELPERS mode + ### + if mode == HELPERS: + # if node.type == ENTITY: + self.render_axis(m, + label=node.name if node != self.scene.rootnode else None, + selected=node.selected if hasattr(node, "selected") else False) + + if node.type == CAMERA: + self.render_camera(node, m) + + for child in node.children: + self.recursive_render(child, shader, mode) + + return + + # Mesh rendering modes + ### + if node.type == MESH: + + for mesh in node.meshes: + + stride = 24 # 6 * 4 bytes + + if node.selected and mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, 1.0, 0.0, 0.0, 1.0) + glUniformMatrix4fv(shader.u_modelViewMatrix, 1, GL_TRUE, + numpy.dot(self.view_matrix, m)) + + else: + if mode == COLORS: + colorid = self.node2colorid[node.name] + r, g, b = self.get_rgb_from_colorid(colorid) + glUniform4f(shader.u_materialDiffuse, r / 255.0, g / 255.0, b / 255.0, 1.0) + elif mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, .0, .0, .0, 1.0) + else: + if node.selected: + diffuse = (1.0, 0.0, 0.0, 1.0) # selected nodes in red + else: + diffuse = mesh.material.properties["diffuse"] + if len(diffuse) == 3: # RGB instead of expected RGBA + diffuse.append(1.0) + glUniform4f(shader.u_materialDiffuse, *diffuse) + # if ambient: + # glUniform4f( shader.Material_ambient, *mat["ambient"] ) + + if mode == BASE: # not in COLORS or SILHOUETTE + normal_matrix = linalg.inv(numpy.dot(self.view_matrix, m)[0:3, 0:3]).transpose() + glUniformMatrix3fv(shader.u_normalMatrix, 1, GL_TRUE, normal_matrix) + + glUniformMatrix4fv(shader.u_modelMatrix, 1, GL_TRUE, m) + + vbo = mesh.gl["vbo"] + vbo.bind() + + glEnableVertexAttribArray(shader.a_vertex) + if normals: + glEnableVertexAttribArray(shader.a_normal) + + glVertexAttribPointer( + shader.a_vertex, + 3, GL_FLOAT, False, stride, vbo + ) + + if normals: + glVertexAttribPointer( + shader.a_normal, + 3, GL_FLOAT, False, stride, vbo + 12 + ) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glDrawElements(GL_TRIANGLES, mesh.gl["nbfaces"] * 3, GL_UNSIGNED_INT, None) + + vbo.unbind() + glDisableVertexAttribArray(shader.a_vertex) + + if normals: + glDisableVertexAttribArray(shader.a_normal) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + for child in node.children: + self.recursive_render(child, shader, mode) + + + def switch_to_overlay(self): + glPushMatrix() + self.set_overlay_projection() + + def switch_from_overlay(self): + self.set_camera_projection() + glPopMatrix() + + def select_node(self, node): + self.currently_selected = node + self.update_node_select(self.scene.rootnode) + + def update_node_select(self, node): + if node is self.currently_selected: + node.selected = True + else: + node.selected = False + + for child in node.children: + self.update_node_select(child) + + def loop(self): + + pygame.display.flip() + + if not self.process_events(): + return False # ESC has been pressed + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + return True + + def process_events(self): + + LEFT_BUTTON = 1 + MIDDLE_BUTTON = 2 + RIGHT_BUTTON = 3 + WHEEL_UP = 4 + WHEEL_DOWN = 5 + + dx, dy = pygame.mouse.get_rel() + mousex, mousey = pygame.mouse.get_pos() + + zooming_one_shot = False + + ok = True + + for evt in pygame.event.get(): + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == LEFT_BUTTON: + hovered = self.get_hovered_node(mousex, self.h - mousey) + if hovered: + if self.currently_selected and self.currently_selected == hovered: + self.select_node(None) + else: + logger.info("Node %s selected" % hovered) + self.select_node(hovered) + else: + self.is_rotating = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == LEFT_BUTTON: + self.is_rotating = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == MIDDLE_BUTTON: + self.is_panning = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == MIDDLE_BUTTON: + self.is_panning = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == RIGHT_BUTTON: + self.is_zooming = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == RIGHT_BUTTON: + self.is_zooming = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button in [WHEEL_UP, WHEEL_DOWN]: + zooming_one_shot = True + self.is_zooming = True + dy = -10 if evt.button == WHEEL_UP else 10 + + if evt.type == pygame.KEYDOWN: + ok = (ok and self.process_keystroke(evt.key, evt.mod)) + + self.controls_3d(dx, dy, zooming_one_shot) + + return ok + + def process_keystroke(self, key, mod): + + # process arrow keys if an object is selected + if self.currently_selected: + up = 0 + strafe = 0 + + if key == pygame.K_UP: + up = 1 + if key == pygame.K_DOWN: + up = -1 + if key == pygame.K_LEFT: + strafe = -1 + if key == pygame.K_RIGHT: + strafe = 1 + + self.move_selected_node(up, strafe) + + if key == pygame.K_f: + pygame.display.toggle_fullscreen() + + if key == pygame.K_TAB: + self.cycle_cameras() + + if key in [pygame.K_ESCAPE, pygame.K_q]: + return False + + return True + + def controls_3d(self, dx, dy, zooming_one_shot=False): + + CAMERA_TRANSLATION_FACTOR = 0.01 + CAMERA_ROTATION_FACTOR = 0.01 + + if not (self.is_rotating or self.is_panning or self.is_zooming): + return + + current_pos = self.current_cam.transformation[:3, 3].copy() + distance = numpy.linalg.norm(self.focal_point - current_pos) + + if self.is_rotating: + """ Orbiting the camera is implemented the following way: + + - the rotation is split into a rotation around the *world* Z axis + (controlled by the horizontal mouse motion along X) and a + rotation around the *X* axis of the camera (pitch) *shifted to + the focal origin* (the world origin for now). This is controlled + by the vertical motion of the mouse (Y axis). + + - as a result, the resulting transformation of the camera in the + world frame C' is: + C' = (T · Rx · T⁻¹ · (Rz · C)⁻¹)⁻¹ + + where: + - C is the original camera transformation in the world frame, + - Rz is the rotation along the Z axis (in the world frame) + - T is the translation camera -> world (ie, the inverse of the + translation part of C + - Rx is the rotation around X in the (translated) camera frame + """ + + rotation_camera_x = dy * CAMERA_ROTATION_FACTOR + rotation_world_z = dx * CAMERA_ROTATION_FACTOR + world_z_rotation = transformations.euler_matrix(0, 0, rotation_world_z) + cam_x_rotation = transformations.euler_matrix(rotation_camera_x, 0, 0) + + after_world_z_rotation = numpy.dot(world_z_rotation, self.current_cam.transformation) + + inverse_transformation = transformations.inverse_matrix(after_world_z_rotation) + + translation = transformations.translation_matrix( + transformations.decompose_matrix(inverse_transformation)[3]) + inverse_translation = transformations.inverse_matrix(translation) + + new_inverse = numpy.dot(inverse_translation, inverse_transformation) + new_inverse = numpy.dot(cam_x_rotation, new_inverse) + new_inverse = numpy.dot(translation, new_inverse) + + self.current_cam.transformation = transformations.inverse_matrix(new_inverse).astype(numpy.float32) + + if self.is_panning: + tx = -dx * CAMERA_TRANSLATION_FACTOR * distance + ty = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((tx, ty, 0)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if self.is_zooming: + tz = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((0, 0, tz)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if zooming_one_shot: + self.is_zooming = False + + self.update_view_camera() + + def update_view_camera(self): + + self.view_matrix = linalg.inv(self.current_cam.transformation) + + # Rotate by 180deg around X to have Z pointing backward (OpenGL convention) + self.view_matrix = numpy.dot(ROTATION_180_X, self.view_matrix) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + glMultMatrixf(self.view_matrix.transpose()) + + def move_selected_node(self, up, strafe): + self.currently_selected.transformation[0][3] += strafe + self.currently_selected.transformation[2][3] += up + + @staticmethod + def showtext(text, x=0, y=0, z=0, size=20): + + # TODO: alpha blending does not work... + # glEnable(GL_BLEND) + # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + font = pygame.font.Font(None, size) + text_surface = font.render(text, True, (10, 10, 10, 255), + (255 * 0.18, 255 * 0.18, 255 * 0.18, 0)) + text_data = pygame.image.tostring(text_surface, "RGBA", True) + glRasterPos3d(x, y, z) + glDrawPixels(text_surface.get_width(), + text_surface.get_height(), + GL_RGBA, GL_UNSIGNED_BYTE, + text_data) + + # glDisable(GL_BLEND) + + +def main(model, width, height): + app = PyAssimp3DViewer(model, w=width, h=height) + + clock = pygame.time.Clock() + + while app.loop(): + + app.update_view_camera() + + ## Main rendering + app.render() + + ## GUI text display + app.switch_to_overlay() + app.showtext("Active camera: %s" % str(app.current_cam), 10, app.h - 30) + if app.currently_selected: + app.showtext("Selected node: %s" % app.currently_selected, 10, app.h - 50) + pos = app.h - 70 + + app.showtext("(%sm, %sm, %sm)" % (app.currently_selected.transformation[0, 3], + app.currently_selected.transformation[1, 3], + app.currently_selected.transformation[2, 3]), 30, pos) + + app.switch_from_overlay() + + # Make sure we do not go over 30fps + clock.tick(30) + + logger.info("Quitting! Bye bye!") + + +######################################################################### +######################################################################### + +if __name__ == '__main__': + if not len(sys.argv) > 1: + print("Usage: " + __file__ + " <model>") + sys.exit(2) + + main(model=sys.argv[1], width=1024, height=768) diff --git a/libs/assimp/port/PyAssimp/scripts/3d_viewer_py3.py b/libs/assimp/port/PyAssimp/scripts/3d_viewer_py3.py new file mode 100755 index 0000000..fcee637 --- /dev/null +++ b/libs/assimp/port/PyAssimp/scripts/3d_viewer_py3.py @@ -0,0 +1,1316 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +""" This program loads a model with PyASSIMP, and display it. + +Based on: +- pygame code from http://3dengine.org/Spectator_%28PyOpenGL%29 +- http://www.lighthouse3d.com/tutorials +- http://www.songho.ca/opengl/gl_transform.html +- http://code.activestate.com/recipes/325391/ +- ASSIMP's C++ SimpleOpenGL viewer + +Authors: Séverin Lemaignan, 2012-2016 +""" +import sys +import logging + +from functools import reduce + +logger = logging.getLogger("pyassimp") +gllogger = logging.getLogger("OpenGL") +gllogger.setLevel(logging.WARNING) +logging.basicConfig(level=logging.INFO) + +import OpenGL + +OpenGL.ERROR_CHECKING = False +OpenGL.ERROR_LOGGING = False +# OpenGL.ERROR_ON_COPY = True +# OpenGL.FULL_LOGGING = True +from OpenGL.GL import * +from OpenGL.arrays import vbo +from OpenGL.GL import shaders + +import pygame +import pygame.font +import pygame.image + +import math, random +from numpy import linalg + +import pyassimp +from pyassimp.postprocess import * +from pyassimp.helper import * +import transformations + +ROTATION_180_X = numpy.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], dtype=numpy.float32) + +# rendering mode +BASE = "BASE" +COLORS = "COLORS" +SILHOUETTE = "SILHOUETTE" +HELPERS = "HELPERS" + +# Entities type +ENTITY = "entity" +CAMERA = "camera" +MESH = "mesh" + +FLAT_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; + +varying vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +FLAT_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; + +out vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; +attribute vec3 a_normal; + +varying vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; +in vec3 a_normal; + +out vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_FRAGMENT_SHADER_120 = """ +#version 120 + +varying vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +BASIC_FRAGMENT_SHADER_130 = """ +#version 130 + +in vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +GOOCH_VERTEX_SHADER_120 = """ +#version 120 + +// attributes +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_VERTEX_SHADER_130 = """ +#version 130 + +// attributes +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +out vec3 o_normal; +out vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_FRAGMENT_SHADER_120 = """ +#version 120 + +// data from vertex shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + gl_FragColor.rgb = colorOut; + gl_FragColor.a = 1; +} +""" + +GOOCH_FRAGMENT_SHADER_130 = """ +#version 130 + +// data from vertex shader +in vec3 o_normal; +in vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +// output to framebuffer +out vec4 resultingColor; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + resultingColor.rgb = colorOut; + resultingColor.a = 1; +} +""" + +SILHOUETTE_VERTEX_SHADER_120 = """ +#version 120 + +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +varying vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" + +SILHOUETTE_VERTEX_SHADER_130 = """ +#version 130 + +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +out vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" +DEFAULT_CLIP_PLANE_NEAR = 0.001 +DEFAULT_CLIP_PLANE_FAR = 1000.0 + + +def get_world_transform(scene, node): + if node == scene.rootnode: + return numpy.identity(4, dtype=numpy.float32) + + parents = reversed(_get_parent_chain(scene, node, [])) + parent_transform = reduce(numpy.dot, [p.transformation for p in parents]) + return numpy.dot(parent_transform, node.transformation) + + +def _get_parent_chain(scene, node, parents): + parent = node.parent + + parents.append(parent) + + if parent == scene.rootnode: + return parents + + return _get_parent_chain(scene, parent, parents) + + +class DefaultCamera: + def __init__(self, w, h, fov): + self.name = "default camera" + self.type = CAMERA + self.clipplanenear = DEFAULT_CLIP_PLANE_NEAR + self.clipplanefar = DEFAULT_CLIP_PLANE_FAR + self.aspect = w / h + self.horizontalfov = fov * math.pi / 180 + self.transformation = numpy.array([[0.68, -0.32, 0.65, 7.48], + [0.73, 0.31, -0.61, -6.51], + [-0.01, 0.89, 0.44, 5.34], + [0., 0., 0., 1.]], dtype=numpy.float32) + + self.transformation = numpy.dot(self.transformation, ROTATION_180_X) + + def __str__(self): + return self.name + + +class PyAssimp3DViewer: + base_name = "PyASSIMP 3D viewer" + + def __init__(self, model, w=1024, h=768): + + self.w = w + self.h = h + + pygame.init() + pygame.display.set_caption(self.base_name) + pygame.display.set_mode((w, h), pygame.OPENGL | pygame.DOUBLEBUF) + + glClearColor(0.18, 0.18, 0.18, 1.0) + + shader_compilation_succeeded = False + try: + self.set_shaders_v130() + self.prepare_shaders() + except RuntimeError as message: + sys.stderr.write("%s\n" % message) + sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") + + if not shader_compilation_succeeded: + self.set_shaders_v120() + self.prepare_shaders() + + self.scene = None + self.meshes = {} # stores the OpenGL vertex/faces/normals buffers pointers + + self.node2colorid = {} # stores a color ID for each node. Useful for mouse picking and visibility checking + self.colorid2node = {} # reverse dict of node2colorid + + self.currently_selected = None + self.moving = False + self.moving_situation = None + + self.default_camera = DefaultCamera(self.w, self.h, fov=70) + self.cameras = [self.default_camera] + + self.current_cam_index = 0 + self.current_cam = self.default_camera + self.set_camera_projection() + + self.load_model(model) + + # user interactions + self.focal_point = [0, 0, 0] + self.is_rotating = False + self.is_panning = False + self.is_zooming = False + + def set_shaders_v120(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_120 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_120 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_120 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_120 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_120 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_120 + + def set_shaders_v130(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_130 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_130 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_130 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_130 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_130 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_130 + + def prepare_shaders(self): + + ### Base shader + vertex = shaders.compileShader(self.BASIC_VERTEX_SHADER, GL_VERTEX_SHADER) + fragment = shaders.compileShader(self.BASIC_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + + self.shader = shaders.compileProgram(vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse'), + ('a_vertex', + 'a_normal'), self.shader) + + ### Flat shader + flatvertex = shaders.compileShader(self.FLAT_VERTEX_SHADER, GL_VERTEX_SHADER) + self.flatshader = shaders.compileProgram(flatvertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_materialDiffuse',), + ('a_vertex',), self.flatshader) + + ### Silhouette shader + silh_vertex = shaders.compileShader(self.SILHOUETTE_VERTEX_SHADER, GL_VERTEX_SHADER) + self.silhouette_shader = shaders.compileProgram(silh_vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_modelViewMatrix', + 'u_materialDiffuse', + 'u_bordersize' # width of the silhouette + ), + ('a_vertex', + 'a_normal'), self.silhouette_shader) + + ### Gooch shader + gooch_vertex = shaders.compileShader(self.GOOCH_VERTEX_SHADER, GL_VERTEX_SHADER) + gooch_fragment = shaders.compileShader(self.GOOCH_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + self.gooch_shader = shaders.compileProgram(gooch_vertex, gooch_fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse', + 'u_coolColor', + 'u_warmColor', + 'u_alpha', + 'u_beta' + ), + ('a_vertex', + 'a_normal'), self.gooch_shader) + + @staticmethod + def set_shader_accessors(uniforms, attributes, shader): + # add accessors to the shaders uniforms and attributes + for uniform in uniforms: + location = glGetUniformLocation(shader, uniform) + if location in (None, -1): + raise RuntimeError('No uniform: %s (maybe it is not used ' + 'anymore and has been optimized out by' + ' the shader compiler)' % uniform) + setattr(shader, uniform, location) + + for attribute in attributes: + location = glGetAttribLocation(shader, attribute) + if location in (None, -1): + raise RuntimeError('No attribute: %s' % attribute) + setattr(shader, attribute, location) + + @staticmethod + def prepare_gl_buffers(mesh): + + mesh.gl = {} + + # Fill the buffer for vertex and normals positions + v = numpy.array(mesh.vertices, 'f') + n = numpy.array(mesh.normals, 'f') + + mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v, n))) + + # Fill the buffer for vertex positions + mesh.gl["faces"] = glGenBuffers(1) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + numpy.array(mesh.faces, dtype=numpy.int32), + GL_STATIC_DRAW) + + mesh.gl["nbfaces"] = len(mesh.faces) + + # Unbind buffers + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + @staticmethod + def get_rgb_from_colorid(colorid): + r = (colorid >> 0) & 0xff + g = (colorid >> 8) & 0xff + b = (colorid >> 16) & 0xff + + return r, g, b + + def get_color_id(self): + id = random.randint(0, 256 * 256 * 256) + if id not in self.colorid2node: + return id + else: + return self.get_color_id() + + def glize(self, scene, node): + + logger.info("Loading node <%s>" % node) + node.selected = True if self.currently_selected and self.currently_selected == node else False + + node.transformation = node.transformation.astype(numpy.float32) + + if node.meshes: + node.type = MESH + colorid = self.get_color_id() + self.colorid2node[colorid] = node + self.node2colorid[node.name] = colorid + + elif node.name in [c.name for c in scene.cameras]: + + # retrieve the ASSIMP camera object + [cam] = [c for c in scene.cameras if c.name == node.name] + node.type = CAMERA + logger.info("Added camera <%s>" % node.name) + logger.info("Camera position: %.3f, %.3f, %.3f" % tuple(node.transformation[:, 3][:3].tolist())) + self.cameras.append(node) + node.clipplanenear = cam.clipplanenear + node.clipplanefar = cam.clipplanefar + + if numpy.allclose(cam.lookat, [0, 0, -1]) and numpy.allclose(cam.up, [0, 1, 0]): # Cameras in .blend files + + # Rotate by 180deg around X to have Z pointing forward + node.transformation = numpy.dot(node.transformation, ROTATION_180_X) + else: + raise RuntimeError( + "I do not know how to normalize this camera orientation: lookat=%s, up=%s" % (cam.lookat, cam.up)) + + if cam.aspect == 0.0: + logger.warning("Camera aspect not set. Setting to default 4:3") + node.aspect = 1.333 + else: + node.aspect = cam.aspect + + node.horizontalfov = cam.horizontalfov + + else: + node.type = ENTITY + + for child in node.children: + self.glize(scene, child) + + def load_model(self, path, postprocess=aiProcessPreset_TargetRealtime_MaxQuality): + logger.info("Loading model:" + path + "...") + + if postprocess: + self.scene = pyassimp.load(path, processing=postprocess) + else: + self.scene = pyassimp.load(path) + logger.info("Done.") + + scene = self.scene + # log some statistics + logger.info(" meshes: %d" % len(scene.meshes)) + logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) + logger.info(" materials: %d" % len(scene.materials)) + self.bb_min, self.bb_max = get_bounding_box(self.scene) + logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) + + self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] + + for index, mesh in enumerate(scene.meshes): + self.prepare_gl_buffers(mesh) + + self.glize(scene, scene.rootnode) + + # Finally release the model + pyassimp.release(scene) + logger.info("Ready for 3D rendering!") + + def cycle_cameras(self): + + self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras) + self.current_cam = self.cameras[self.current_cam_index] + self.set_camera_projection(self.current_cam) + logger.info("Switched to camera <%s>" % self.current_cam) + + def set_overlay_projection(self): + glViewport(0, 0, self.w, self.h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(0.0, self.w - 1.0, 0.0, self.h - 1.0, -1.0, 1.0) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def set_camera_projection(self, camera=None): + + if not camera: + camera = self.current_cam + + znear = camera.clipplanenear or DEFAULT_CLIP_PLANE_NEAR + zfar = camera.clipplanefar or DEFAULT_CLIP_PLANE_FAR + aspect = camera.aspect + fov = camera.horizontalfov + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + + # Compute gl frustrum + tangent = math.tan(fov / 2.) + h = znear * tangent + w = h * aspect + + # params: left, right, bottom, top, near, far + glFrustum(-w, w, -h, h, znear, zfar) + # equivalent to: + # gluPerspective(fov * 180/math.pi, aspect, znear, zfar) + + self.projection_matrix = glGetFloatv(GL_PROJECTION_MATRIX).transpose() + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def render_colors(self): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + glEnable(GL_CULL_FACE) + + glUseProgram(self.flatshader) + + glUniformMatrix4fv(self.flatshader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, self.flatshader, mode=COLORS) + + glUseProgram(0) + + def get_hovered_node(self, mousex, mousey): + """ + Attention: The performances of this method relies heavily on the size of the display! + """ + + # mouse out of the window? + if mousex < 0 or mousex >= self.w or mousey < 0 or mousey >= self.h: + return None + + self.render_colors() + # Capture image from the OpenGL buffer + buf = (GLubyte * (3 * self.w * self.h))(0) + glReadPixels(0, 0, self.w, self.h, GL_RGB, GL_UNSIGNED_BYTE, buf) + + # Reinterpret the RGB pixel buffer as a 1-D array of 24bits colors + a = numpy.ndarray(len(buf), numpy.dtype('>u1'), buf) + colors = numpy.zeros(len(buf) // 3, numpy.dtype('<u4')) + for i in range(3): + colors.view(dtype='>u1')[i::4] = a.view(dtype='>u1')[i::3] + + colorid = colors[mousex + mousey * self.w] + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + if colorid in self.colorid2node: + return self.colorid2node[colorid] + + def render(self, wireframe=False, twosided=False): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) + glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) + + self.render_grid() + + self.recursive_render(self.scene.rootnode, None, mode=HELPERS) + + ### First, the silhouette + + if False: + shader = self.silhouette_shader + + # glDepthMask(GL_FALSE) + glCullFace(GL_FRONT) # cull front faces + + glUseProgram(shader) + glUniform1f(shader.u_bordersize, 0.01) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader, mode=SILHOUETTE) + + glUseProgram(0) + + ### Then, inner shading + # glDepthMask(GL_TRUE) + glCullFace(GL_BACK) + + use_gooch = False + if use_gooch: + shader = self.gooch_shader + + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + ##### GOOCH specific + glUniform3f(shader.u_coolColor, 159.0 / 255, 148.0 / 255, 255.0 / 255) + glUniform3f(shader.u_warmColor, 255.0 / 255, 75.0 / 255, 75.0 / 255) + glUniform1f(shader.u_alpha, .25) + glUniform1f(shader.u_beta, .25) + ######### + else: + shader = self.shader + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader) + + glUseProgram(0) + + def render_axis(self, + transformation=numpy.identity(4, dtype=numpy.float32), + label=None, + size=0.2, + selected=False): + m = transformation.transpose() # OpenGL row major + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(3 if selected else 1) + + size = 2 * size if selected else size + + glBegin(GL_LINES) + + # draw line for x axis + glColor3f(1.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(size, 0.0, 0.0) + + # draw line for y axis + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, size, 0.0) + + # draw line for Z axis + glColor3f(0.0, 0.0, 1.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, size) + + glEnd() + + if label: + self.showtext(label) + + glPopMatrix() + + @staticmethod + def render_camera(camera, transformation): + + m = transformation.transpose() # OpenGL row major + + aspect = camera.aspect + + u = 0.1 # unit size (in m) + l = 3 * u # length of the camera cone + f = 3 * u # aperture of the camera cone + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(2) + glBegin(GL_LINE_STRIP) + + glColor3f(.2, .2, .2) + + glVertex3f(u, u, -u) + glVertex3f(u, -u, -u) + glVertex3f(-u, -u, -u) + glVertex3f(-u, u, -u) + glVertex3f(u, u, -u) + + glVertex3f(u, u, 0.0) + glVertex3f(u, -u, 0.0) + glVertex3f(-u, -u, 0.0) + glVertex3f(-u, u, 0.0) + glVertex3f(u, u, 0.0) + + glVertex3f(f * aspect, f, l) + glVertex3f(f * aspect, -f, l) + glVertex3f(-f * aspect, -f, l) + glVertex3f(-f * aspect, f, l) + glVertex3f(f * aspect, f, l) + + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(u, -u, -u) + glVertex3f(u, -u, 0.0) + glVertex3f(f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, -u, -u) + glVertex3f(-u, -u, 0.0) + glVertex3f(-f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, u, -u) + glVertex3f(-u, u, 0.0) + glVertex3f(-f * aspect, f, l) + glEnd() + + glPopMatrix() + + @staticmethod + def render_grid(): + + glLineWidth(1) + glColor3f(0.5, 0.5, 0.5) + glBegin(GL_LINES) + for i in range(-10, 11): + glVertex3f(i, -10.0, 0.0) + glVertex3f(i, 10.0, 0.0) + + for i in range(-10, 11): + glVertex3f(-10.0, i, 0.0) + glVertex3f(10.0, i, 0.0) + glEnd() + + def recursive_render(self, node, shader, mode=BASE, with_normals=True): + """ Main recursive rendering method. + """ + + normals = with_normals + + if mode == COLORS: + normals = False + + + if not hasattr(node, "selected"): + node.selected = False + + m = get_world_transform(self.scene, node) + + # HELPERS mode + ### + if mode == HELPERS: + # if node.type == ENTITY: + self.render_axis(m, + label=node.name if node != self.scene.rootnode else None, + selected=node.selected if hasattr(node, "selected") else False) + + if node.type == CAMERA: + self.render_camera(node, m) + + for child in node.children: + self.recursive_render(child, shader, mode) + + return + + # Mesh rendering modes + ### + if node.type == MESH: + + for mesh in node.meshes: + + stride = 24 # 6 * 4 bytes + + if node.selected and mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, 1.0, 0.0, 0.0, 1.0) + glUniformMatrix4fv(shader.u_modelViewMatrix, 1, GL_TRUE, + numpy.dot(self.view_matrix, m)) + + else: + if mode == COLORS: + colorid = self.node2colorid[node.name] + r, g, b = self.get_rgb_from_colorid(colorid) + glUniform4f(shader.u_materialDiffuse, r / 255.0, g / 255.0, b / 255.0, 1.0) + elif mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, .0, .0, .0, 1.0) + else: + if node.selected: + diffuse = (1.0, 0.0, 0.0, 1.0) # selected nodes in red + else: + diffuse = mesh.material.properties["diffuse"] + if len(diffuse) == 3: # RGB instead of expected RGBA + diffuse.append(1.0) + glUniform4f(shader.u_materialDiffuse, *diffuse) + # if ambient: + # glUniform4f( shader.Material_ambient, *mat["ambient"] ) + + if mode == BASE: # not in COLORS or SILHOUETTE + normal_matrix = linalg.inv(numpy.dot(self.view_matrix, m)[0:3, 0:3]).transpose() + glUniformMatrix3fv(shader.u_normalMatrix, 1, GL_TRUE, normal_matrix) + + glUniformMatrix4fv(shader.u_modelMatrix, 1, GL_TRUE, m) + + vbo = mesh.gl["vbo"] + vbo.bind() + + glEnableVertexAttribArray(shader.a_vertex) + if normals: + glEnableVertexAttribArray(shader.a_normal) + + glVertexAttribPointer( + shader.a_vertex, + 3, GL_FLOAT, False, stride, vbo + ) + + if normals: + glVertexAttribPointer( + shader.a_normal, + 3, GL_FLOAT, False, stride, vbo + 12 + ) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glDrawElements(GL_TRIANGLES, mesh.gl["nbfaces"] * 3, GL_UNSIGNED_INT, None) + + vbo.unbind() + glDisableVertexAttribArray(shader.a_vertex) + + if normals: + glDisableVertexAttribArray(shader.a_normal) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + for child in node.children: + self.recursive_render(child, shader, mode) + + + def switch_to_overlay(self): + glPushMatrix() + self.set_overlay_projection() + + def switch_from_overlay(self): + self.set_camera_projection() + glPopMatrix() + + def select_node(self, node): + self.currently_selected = node + self.update_node_select(self.scene.rootnode) + + def update_node_select(self, node): + if node is self.currently_selected: + node.selected = True + else: + node.selected = False + + for child in node.children: + self.update_node_select(child) + + def loop(self): + + pygame.display.flip() + + if not self.process_events(): + return False # ESC has been pressed + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + return True + + def process_events(self): + + LEFT_BUTTON = 1 + MIDDLE_BUTTON = 2 + RIGHT_BUTTON = 3 + WHEEL_UP = 4 + WHEEL_DOWN = 5 + + dx, dy = pygame.mouse.get_rel() + mousex, mousey = pygame.mouse.get_pos() + + zooming_one_shot = False + + ok = True + + for evt in pygame.event.get(): + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == LEFT_BUTTON: + hovered = self.get_hovered_node(mousex, self.h - mousey) + if hovered: + if self.currently_selected and self.currently_selected == hovered: + self.select_node(None) + else: + logger.info("Node %s selected" % hovered) + self.select_node(hovered) + else: + self.is_rotating = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == LEFT_BUTTON: + self.is_rotating = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == MIDDLE_BUTTON: + self.is_panning = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == MIDDLE_BUTTON: + self.is_panning = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == RIGHT_BUTTON: + self.is_zooming = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == RIGHT_BUTTON: + self.is_zooming = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button in [WHEEL_UP, WHEEL_DOWN]: + zooming_one_shot = True + self.is_zooming = True + dy = -10 if evt.button == WHEEL_UP else 10 + + if evt.type == pygame.KEYDOWN: + ok = (ok and self.process_keystroke(evt.key, evt.mod)) + + self.controls_3d(dx, dy, zooming_one_shot) + + return ok + + def process_keystroke(self, key, mod): + + # process arrow keys if an object is selected + if self.currently_selected: + up = 0 + strafe = 0 + + if key == pygame.K_UP: + up = 1 + if key == pygame.K_DOWN: + up = -1 + if key == pygame.K_LEFT: + strafe = -1 + if key == pygame.K_RIGHT: + strafe = 1 + + self.move_selected_node(up, strafe) + + if key == pygame.K_f: + pygame.display.toggle_fullscreen() + + if key == pygame.K_TAB: + self.cycle_cameras() + + if key in [pygame.K_ESCAPE, pygame.K_q]: + return False + + return True + + def controls_3d(self, dx, dy, zooming_one_shot=False): + """ Orbiting the camera is implemented the following way: + + - the rotation is split into a rotation around the *world* Z axis + (controlled by the horizontal mouse motion along X) and a + rotation around the *X* axis of the camera (pitch) *shifted to + the focal origin* (the world origin for now). This is controlled + by the vertical motion of the mouse (Y axis). + - as a result, the resulting transformation of the camera in the + world frame C' is: + C' = (T · Rx · T⁻¹ · (Rz · C)⁻¹)⁻¹ + where: + - C is the original camera transformation in the world frame, + - Rz is the rotation along the Z axis (in the world frame) + - T is the translation camera -> world (ie, the inverse of the + translation part of C + - Rx is the rotation around X in the (translated) camera frame """ + + CAMERA_TRANSLATION_FACTOR = 0.01 + CAMERA_ROTATION_FACTOR = 0.01 + + if not (self.is_rotating or self.is_panning or self.is_zooming): + return + + current_pos = self.current_cam.transformation[:3, 3].copy() + distance = numpy.linalg.norm(self.focal_point - current_pos) + + if self.is_rotating: + rotation_camera_x = dy * CAMERA_ROTATION_FACTOR + rotation_world_z = dx * CAMERA_ROTATION_FACTOR + world_z_rotation = transformations.euler_matrix(0, 0, rotation_world_z) + cam_x_rotation = transformations.euler_matrix(rotation_camera_x, 0, 0) + + after_world_z_rotation = numpy.dot(world_z_rotation, self.current_cam.transformation) + + inverse_transformation = transformations.inverse_matrix(after_world_z_rotation) + + translation = transformations.translation_matrix( + transformations.decompose_matrix(inverse_transformation)[3]) + inverse_translation = transformations.inverse_matrix(translation) + + new_inverse = numpy.dot(inverse_translation, inverse_transformation) + new_inverse = numpy.dot(cam_x_rotation, new_inverse) + new_inverse = numpy.dot(translation, new_inverse) + + self.current_cam.transformation = transformations.inverse_matrix(new_inverse).astype(numpy.float32) + + if self.is_panning: + tx = -dx * CAMERA_TRANSLATION_FACTOR * distance + ty = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((tx, ty, 0)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if self.is_zooming: + tz = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((0, 0, tz)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if zooming_one_shot: + self.is_zooming = False + + self.update_view_camera() + + def update_view_camera(self): + + self.view_matrix = linalg.inv(self.current_cam.transformation) + + # Rotate by 180deg around X to have Z pointing backward (OpenGL convention) + self.view_matrix = numpy.dot(ROTATION_180_X, self.view_matrix) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + glMultMatrixf(self.view_matrix.transpose()) + + def move_selected_node(self, up, strafe): + self.currently_selected.transformation[0][3] += strafe + self.currently_selected.transformation[2][3] += up + + @staticmethod + def showtext(text, x=0, y=0, z=0, size=20): + + # TODO: alpha blending does not work... + # glEnable(GL_BLEND) + # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + font = pygame.font.Font(None, size) + text_surface = font.render(text, True, (10, 10, 10, 255), + (255 * 0.18, 255 * 0.18, 255 * 0.18, 0)) + text_data = pygame.image.tostring(text_surface, "RGBA", True) + glRasterPos3d(x, y, z) + glDrawPixels(text_surface.get_width(), + text_surface.get_height(), + GL_RGBA, GL_UNSIGNED_BYTE, + text_data) + + # glDisable(GL_BLEND) + + +def main(model, width, height): + app = PyAssimp3DViewer(model, w=width, h=height) + + clock = pygame.time.Clock() + + while app.loop(): + + app.update_view_camera() + + ## Main rendering + app.render() + + ## GUI text display + app.switch_to_overlay() + app.showtext("Active camera: %s" % str(app.current_cam), 10, app.h - 30) + if app.currently_selected: + app.showtext("Selected node: %s" % app.currently_selected, 10, app.h - 50) + pos = app.h - 70 + + app.showtext("(%sm, %sm, %sm)" % (app.currently_selected.transformation[0, 3], + app.currently_selected.transformation[1, 3], + app.currently_selected.transformation[2, 3]), 30, pos) + + app.switch_from_overlay() + + # Make sure we do not go over 30fps + clock.tick(30) + + logger.info("Quitting! Bye bye!") + + +######################################################################### +######################################################################### + +if __name__ == '__main__': + if not len(sys.argv) > 1: + print("Usage: " + __file__ + " <model>") + sys.exit(2) + + main(model=sys.argv[1], width=1024, height=768) diff --git a/libs/assimp/port/PyAssimp/scripts/README.md b/libs/assimp/port/PyAssimp/scripts/README.md new file mode 100644 index 0000000..42caa27 --- /dev/null +++ b/libs/assimp/port/PyAssimp/scripts/README.md @@ -0,0 +1,13 @@ +pyassimp examples +================= + +- `sample.py`: shows how to load a model with pyassimp, and display some statistics. +- `3d_viewer.py`: an OpenGL 3D viewer that requires shaders +- `fixed_pipeline_3d_viewer`: an OpenGL 3D viewer using the old fixed-pipeline. + Only for illustration example. Base new projects on `3d_viewer.py`. + + +Requirements for the 3D viewers: + +- `pyopengl` (on Ubuntu/Debian, `sudo apt-get install python-opengl`) +- `pygame` (on Ubuntu/Debian, `sudo apt-get install python-pygame`) diff --git a/libs/assimp/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py b/libs/assimp/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py new file mode 100755 index 0000000..c2f6ceb --- /dev/null +++ b/libs/assimp/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python +#-*- coding: UTF-8 -*- + +""" This program demonstrates the use of pyassimp to load and +render objects with OpenGL. + +'c' cycles between cameras (if any available) +'q' to quit + +This example mixes 'old' OpenGL fixed-function pipeline with +Vertex Buffer Objects. + +Materials are supported but textures are currently ignored. + +For a more advanced example (with shaders + keyboard/mouse +controls), check scripts/sdl_viewer.py + +Author: Séverin Lemaignan, 2012 + +This sample is based on several sources, including: + - http://www.lighthouse3d.com/tutorials + - http://www.songho.ca/opengl/gl_transform.html + - http://code.activestate.com/recipes/325391/ + - ASSIMP's C++ SimpleOpenGL viewer +""" + +import sys +from OpenGL.GLUT import * +from OpenGL.GLU import * +from OpenGL.GL import * + +import logging +logger = logging.getLogger("pyassimp_opengl") +logging.basicConfig(level=logging.INFO) + +import math +import numpy + +import pyassimp +from pyassimp.postprocess import * +from pyassimp.helper import * + + +name = 'pyassimp OpenGL viewer' +height = 600 +width = 900 + +class GLRenderer(): + def __init__(self): + + self.scene = None + + self.using_fixed_cam = False + self.current_cam_index = 0 + + # store the global scene rotation + self.angle = 0. + + # for FPS calculation + self.prev_time = 0 + self.prev_fps_time = 0 + self.frames = 0 + + def prepare_gl_buffers(self, mesh): + """ Creates 3 buffer objets for each mesh, + to store the vertices, the normals, and the faces + indices. + """ + + mesh.gl = {} + + # Fill the buffer for vertex positions + mesh.gl["vertices"] = glGenBuffers(1) + glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["vertices"]) + glBufferData(GL_ARRAY_BUFFER, + mesh.vertices, + GL_STATIC_DRAW) + + # Fill the buffer for normals + mesh.gl["normals"] = glGenBuffers(1) + glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["normals"]) + glBufferData(GL_ARRAY_BUFFER, + mesh.normals, + GL_STATIC_DRAW) + + + # Fill the buffer for vertex positions + mesh.gl["triangles"] = glGenBuffers(1) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["triangles"]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + mesh.faces, + GL_STATIC_DRAW) + + # Unbind buffers + glBindBuffer(GL_ARRAY_BUFFER,0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0) + + def load_model(self, path, postprocess = None): + logger.info("Loading model:" + path + "...") + + if postprocess: + self.scene = pyassimp.load(path, processing=postprocess) + else: + self.scene = pyassimp.load(path) + logger.info("Done.") + + scene = self.scene + #log some statistics + logger.info(" meshes: %d" % len(scene.meshes)) + logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) + logger.info(" materials: %d" % len(scene.materials)) + self.bb_min, self.bb_max = get_bounding_box(self.scene) + logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) + + self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] + + for index, mesh in enumerate(scene.meshes): + self.prepare_gl_buffers(mesh) + + # Finally release the model + pyassimp.release(scene) + + def cycle_cameras(self): + self.current_cam_index + if not self.scene.cameras: + return None + self.current_cam_index = (self.current_cam_index + 1) % len(self.scene.cameras) + cam = self.scene.cameras[self.current_cam_index] + logger.info("Switched to camera " + str(cam)) + return cam + + def set_default_camera(self): + + if not self.using_fixed_cam: + glLoadIdentity() + + gluLookAt(0.,0.,3., + 0.,0.,-5., + 0.,1.,0.) + + + + def set_camera(self, camera): + + if not camera: + return + + self.using_fixed_cam = True + + znear = camera.clipplanenear + zfar = camera.clipplanefar + aspect = camera.aspect + fov = camera.horizontalfov + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + + # Compute gl frustrum + tangent = math.tan(fov/2.) + h = znear * tangent + w = h * aspect + + # params: left, right, bottom, top, near, far + glFrustum(-w, w, -h, h, znear, zfar) + # equivalent to: + #gluPerspective(fov * 180/math.pi, aspect, znear, zfar) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + cam = transform(camera.position, camera.transformation) + at = transform(camera.lookat, camera.transformation) + gluLookAt(cam[0], cam[2], -cam[1], + at[0], at[2], -at[1], + 0, 1, 0) + + def fit_scene(self, restore = False): + """ Compute a scale factor and a translation to fit and center + the whole geometry on the screen. + """ + + x_max = self.bb_max[0] - self.bb_min[0] + y_max = self.bb_max[1] - self.bb_min[1] + tmp = max(x_max, y_max) + z_max = self.bb_max[2] - self.bb_min[2] + tmp = max(z_max, tmp) + + if not restore: + tmp = 1. / tmp + + logger.info("Scaling the scene by %.03f" % tmp) + glScalef(tmp, tmp, tmp) + + # center the model + direction = -1 if not restore else 1 + glTranslatef( direction * self.scene_center[0], + direction * self.scene_center[1], + direction * self.scene_center[2] ) + + return x_max, y_max, z_max + + def apply_material(self, mat): + """ Apply an OpenGL, using one OpenGL display list per material to cache + the operation. + """ + + if not hasattr(mat, "gl_mat"): # evaluate once the mat properties, and cache the values in a glDisplayList. + diffuse = numpy.array(mat.properties.get("diffuse", [0.8, 0.8, 0.8, 1.0])) + specular = numpy.array(mat.properties.get("specular", [0., 0., 0., 1.0])) + ambient = numpy.array(mat.properties.get("ambient", [0.2, 0.2, 0.2, 1.0])) + emissive = numpy.array(mat.properties.get("emissive", [0., 0., 0., 1.0])) + shininess = min(mat.properties.get("shininess", 1.0), 128) + wireframe = mat.properties.get("wireframe", 0) + twosided = mat.properties.get("twosided", 1) + + setattr(mat, "gl_mat", glGenLists(1)) + glNewList(mat.gl_mat, GL_COMPILE) + + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient) + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emissive) + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) + glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) + + glEndList() + + glCallList(mat.gl_mat) + + + + def do_motion(self): + + gl_time = glutGet(GLUT_ELAPSED_TIME) + + self.angle = (gl_time - self.prev_time) * 0.1 + + self.prev_time = gl_time + + # Compute FPS + self.frames += 1 + if gl_time - self.prev_fps_time >= 1000: + current_fps = self.frames * 1000 / (gl_time - self.prev_fps_time) + logger.info('%.0f fps' % current_fps) + self.frames = 0 + self.prev_fps_time = gl_time + + glutPostRedisplay() + + def recursive_render(self, node): + """ Main recursive rendering method. + """ + + # save model matrix and apply node transformation + glPushMatrix() + m = node.transformation.transpose() # OpenGL row major + glMultMatrixf(m) + + for mesh in node.meshes: + self.apply_material(mesh.material) + + glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["vertices"]) + glEnableClientState(GL_VERTEX_ARRAY) + glVertexPointer(3, GL_FLOAT, 0, None) + + glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["normals"]) + glEnableClientState(GL_NORMAL_ARRAY) + glNormalPointer(GL_FLOAT, 0, None) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["triangles"]) + glDrawElements(GL_TRIANGLES,len(mesh.faces) * 3, GL_UNSIGNED_INT, None) + + glDisableClientState(GL_VERTEX_ARRAY) + glDisableClientState(GL_NORMAL_ARRAY) + + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + for child in node.children: + self.recursive_render(child) + + glPopMatrix() + + + def display(self): + """ GLUT callback to redraw OpenGL surface + """ + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) + + glRotatef(self.angle,0.,1.,0.) + self.recursive_render(self.scene.rootnode) + + glutSwapBuffers() + self.do_motion() + return + + #################################################################### + ## GLUT keyboard and mouse callbacks ## + #################################################################### + def onkeypress(self, key, x, y): + if key == 'c': + self.fit_scene(restore = True) + self.set_camera(self.cycle_cameras()) + if key == 'q': + sys.exit(0) + + def render(self, filename=None, fullscreen = False, autofit = True, postprocess = None): + """ + + :param autofit: if true, scale the scene to fit the whole geometry + in the viewport. + """ + + # First initialize the openGL context + glutInit(sys.argv) + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) + if not fullscreen: + glutInitWindowSize(width, height) + glutCreateWindow(name) + else: + glutGameModeString("1024x768") + if glutGameModeGet(GLUT_GAME_MODE_POSSIBLE): + glutEnterGameMode() + else: + print("Fullscreen mode not available!") + sys.exit(1) + + self.load_model(filename, postprocess = postprocess) + + + glClearColor(0.1,0.1,0.1,1.) + #glShadeModel(GL_SMOOTH) + + glEnable(GL_LIGHTING) + + glEnable(GL_CULL_FACE) + glEnable(GL_DEPTH_TEST) + + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) + glEnable(GL_NORMALIZE) + glEnable(GL_LIGHT0) + + glutDisplayFunc(self.display) + + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(35.0, width/float(height) , 0.10, 100.0) + glMatrixMode(GL_MODELVIEW) + self.set_default_camera() + + if autofit: + # scale the whole asset to fit into our view frustum· + self.fit_scene() + + glPushMatrix() + + glutKeyboardFunc(self.onkeypress) + glutIgnoreKeyRepeat(1) + + glutMainLoop() + + +if __name__ == '__main__': + if not len(sys.argv) > 1: + print("Usage: " + __file__ + " <model>") + sys.exit(0) + + glrender = GLRenderer() + glrender.render(sys.argv[1], fullscreen = False, postprocess = aiProcessPreset_TargetRealtime_MaxQuality) + diff --git a/libs/assimp/port/PyAssimp/scripts/quicktest.py b/libs/assimp/port/PyAssimp/scripts/quicktest.py new file mode 100755 index 0000000..cbeccb4 --- /dev/null +++ b/libs/assimp/port/PyAssimp/scripts/quicktest.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +#-*- coding: UTF-8 -*- + +""" +This module uses the sample.py script to load all test models it finds. + +Note: this is not an exhaustive test suite, it does not check the +data structures in detail. It just verifies whether basic +loading and querying of 3d models using pyassimp works. +""" + +import os +import sys + +# Make the development (ie. GIT repo) version of PyAssimp available for import. +sys.path.insert(0, '..') + +import sample +from pyassimp import errors + +# Paths to model files. +basepaths = [os.path.join('..', '..', '..', 'test', 'models'), + os.path.join('..', '..', '..', 'test', 'models-nonbsd')] + +# Valid extensions for 3D model files. +extensions = ['.3ds', '.x', '.lwo', '.obj', '.md5mesh', '.dxf', '.ply', '.stl', + '.dae', '.md5anim', '.lws', '.irrmesh', '.nff', '.off', '.blend'] + + +def run_tests(): + ok, err = 0, 0 + for path in basepaths: + print("Looking for models in %s..." % path) + for root, dirs, files in os.walk(path): + for afile in files: + base, ext = os.path.splitext(afile) + if ext in extensions: + try: + sample.main(os.path.join(root, afile)) + ok += 1 + except errors.AssimpError as error: + # Assimp error is fine; this is a controlled case. + print(error) + err += 1 + except Exception: + print("Error encountered while loading <%s>" + % os.path.join(root, afile)) + print('** Loaded %s models, got controlled errors for %s files' + % (ok, err)) + + +if __name__ == '__main__': + run_tests() diff --git a/libs/assimp/port/PyAssimp/scripts/sample.py b/libs/assimp/port/PyAssimp/scripts/sample.py new file mode 100755 index 0000000..3cd4b3e --- /dev/null +++ b/libs/assimp/port/PyAssimp/scripts/sample.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +#-*- coding: UTF-8 -*- + +""" +This module demonstrates the functionality of PyAssimp. +""" + +import sys +import logging +logging.basicConfig(level=logging.INFO) + +import pyassimp +import pyassimp.postprocess + +def recur_node(node,level = 0): + print(" " + "\t" * level + "- " + str(node)) + for child in node.children: + recur_node(child, level + 1) + + +def main(filename=None): + + scene = pyassimp.load(filename, processing=pyassimp.postprocess.aiProcess_Triangulate) + + #the model we load + print("MODEL:" + filename) + print + + #write some statistics + print("SCENE:") + print(" meshes:" + str(len(scene.meshes))) + print(" materials:" + str(len(scene.materials))) + print(" textures:" + str(len(scene.textures))) + print + + print("NODES:") + recur_node(scene.rootnode) + + print + print("MESHES:") + for index, mesh in enumerate(scene.meshes): + print(" MESH" + str(index+1)) + print(" material id:" + str(mesh.materialindex+1)) + print(" vertices:" + str(len(mesh.vertices))) + print(" first 3 verts:\n" + str(mesh.vertices[:3])) + if mesh.normals.any(): + print(" first 3 normals:\n" + str(mesh.normals[:3])) + else: + print(" no normals") + print(" colors:" + str(len(mesh.colors))) + tcs = mesh.texturecoords + if tcs.any(): + for tc_index, tc in enumerate(tcs): + print(" texture-coords "+ str(tc_index) + ":" + str(len(tcs[tc_index])) + "first3:" + str(tcs[tc_index][:3])) + + else: + print(" no texture coordinates") + print(" uv-component-count:" + str(len(mesh.numuvcomponents))) + print(" faces:" + str(len(mesh.faces)) + " -> first:\n" + str(mesh.faces[:3])) + print(" bones:" + str(len(mesh.bones)) + " -> first:" + str([str(b) for b in mesh.bones[:3]])) + print + + print("MATERIALS:") + for index, material in enumerate(scene.materials): + print(" MATERIAL (id:" + str(index+1) + ")") + for key, value in material.properties.items(): + print(" %s: %s" % (key, value)) + print + + print("TEXTURES:") + for index, texture in enumerate(scene.textures): + print(" TEXTURE" + str(index+1)) + print(" width:" + str(texture.width)) + print(" height:" + str(texture.height)) + print(" hint:" + str(texture.achformathint)) + print(" data (size):" + str(len(texture.data))) + + # Finally release the model + pyassimp.release(scene) + +def usage(): + print("Usage: sample.py <3d model>") + +if __name__ == "__main__": + + if len(sys.argv) != 2: + usage() + else: + main(sys.argv[1]) diff --git a/libs/assimp/port/PyAssimp/scripts/transformations.py b/libs/assimp/port/PyAssimp/scripts/transformations.py new file mode 100644 index 0000000..bf0cac9 --- /dev/null +++ b/libs/assimp/port/PyAssimp/scripts/transformations.py @@ -0,0 +1,1705 @@ +# -*- coding: utf-8 -*- +# transformations.py + +# Copyright (c) 2006, Christoph Gohlke +# Copyright (c) 2006-2009, The Regents of the University of California +# All rights reserved. +# +# Redistribution and use 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 copyright holders nor the names of any +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# 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. + +"""Homogeneous Transformation Matrices and Quaternions. + +A library for calculating 4x4 matrices for translating, rotating, reflecting, +scaling, shearing, projecting, orthogonalizing, and superimposing arrays of +3D homogeneous coordinates as well as for converting between rotation matrices, +Euler angles, and quaternions. Also includes an Arcball control object and +functions to decompose transformation matrices. + +:Authors: + `Christoph Gohlke <http://www.lfd.uci.edu/~gohlke/>`__, + Laboratory for Fluorescence Dynamics, University of California, Irvine + +:Version: 20090418 + +Requirements +------------ + +* `Python 2.6 <http://www.python.org>`__ +* `Numpy 1.3 <http://numpy.scipy.org>`__ +* `transformations.c 20090418 <http://www.lfd.uci.edu/~gohlke/>`__ + (optional implementation of some functions in C) + +Notes +----- + +Matrices (M) can be inverted using numpy.linalg.inv(M), concatenated using +numpy.dot(M0, M1), or used to transform homogeneous coordinates (v) using +numpy.dot(M, v) for shape (4, \*) "point of arrays", respectively +numpy.dot(v, M.T) for shape (\*, 4) "array of points". + +Calculations are carried out with numpy.float64 precision. + +This Python implementation is not optimized for speed. + +Vector, point, quaternion, and matrix function arguments are expected to be +"array like", i.e. tuple, list, or numpy arrays. + +Return types are numpy arrays unless specified otherwise. + +Angles are in radians unless specified otherwise. + +Quaternions ix+jy+kz+w are represented as [x, y, z, w]. + +Use the transpose of transformation matrices for OpenGL glMultMatrixd(). + +A triple of Euler angles can be applied/interpreted in 24 ways, which can +be specified using a 4 character string or encoded 4-tuple: + + *Axes 4-string*: e.g. 'sxyz' or 'ryxy' + + - first character : rotations are applied to 's'tatic or 'r'otating frame + - remaining characters : successive rotation axis 'x', 'y', or 'z' + + *Axes 4-tuple*: e.g. (0, 0, 0, 0) or (1, 1, 1, 1) + + - inner axis: code of axis ('x':0, 'y':1, 'z':2) of rightmost matrix. + - parity : even (0) if inner axis 'x' is followed by 'y', 'y' is followed + by 'z', or 'z' is followed by 'x'. Otherwise odd (1). + - repetition : first and last axis are same (1) or different (0). + - frame : rotations are applied to static (0) or rotating (1) frame. + +References +---------- + +(1) Matrices and transformations. Ronald Goldman. + In "Graphics Gems I", pp 472-475. Morgan Kaufmann, 1990. +(2) More matrices and transformations: shear and pseudo-perspective. + Ronald Goldman. In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991. +(3) Decomposing a matrix into simple transformations. Spencer Thomas. + In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991. +(4) Recovering the data from the transformation matrix. Ronald Goldman. + In "Graphics Gems II", pp 324-331. Morgan Kaufmann, 1991. +(5) Euler angle conversion. Ken Shoemake. + In "Graphics Gems IV", pp 222-229. Morgan Kaufmann, 1994. +(6) Arcball rotation control. Ken Shoemake. + In "Graphics Gems IV", pp 175-192. Morgan Kaufmann, 1994. +(7) Representing attitude: Euler angles, unit quaternions, and rotation + vectors. James Diebel. 2006. +(8) A discussion of the solution for the best rotation to relate two sets + of vectors. W Kabsch. Acta Cryst. 1978. A34, 827-828. +(9) Closed-form solution of absolute orientation using unit quaternions. + BKP Horn. J Opt Soc Am A. 1987. 4(4), 629-642. +(10) Quaternions. Ken Shoemake. + http://www.sfu.ca/~jwa3/cmpt461/files/quatut.pdf +(11) From quaternion to matrix and back. JMP van Waveren. 2005. + http://www.intel.com/cd/ids/developer/asmo-na/eng/293748.htm +(12) Uniform random rotations. Ken Shoemake. + In "Graphics Gems III", pp 124-132. Morgan Kaufmann, 1992. + + +Examples +-------- + +>>> alpha, beta, gamma = 0.123, -1.234, 2.345 +>>> origin, xaxis, yaxis, zaxis = (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1) +>>> I = identity_matrix() +>>> Rx = rotation_matrix(alpha, xaxis) +>>> Ry = rotation_matrix(beta, yaxis) +>>> Rz = rotation_matrix(gamma, zaxis) +>>> R = concatenate_matrices(Rx, Ry, Rz) +>>> euler = euler_from_matrix(R, 'rxyz') +>>> numpy.allclose([alpha, beta, gamma], euler) +True +>>> Re = euler_matrix(alpha, beta, gamma, 'rxyz') +>>> is_same_transform(R, Re) +True +>>> al, be, ga = euler_from_matrix(Re, 'rxyz') +>>> is_same_transform(Re, euler_matrix(al, be, ga, 'rxyz')) +True +>>> qx = quaternion_about_axis(alpha, xaxis) +>>> qy = quaternion_about_axis(beta, yaxis) +>>> qz = quaternion_about_axis(gamma, zaxis) +>>> q = quaternion_multiply(qx, qy) +>>> q = quaternion_multiply(q, qz) +>>> Rq = quaternion_matrix(q) +>>> is_same_transform(R, Rq) +True +>>> S = scale_matrix(1.23, origin) +>>> T = translation_matrix((1, 2, 3)) +>>> Z = shear_matrix(beta, xaxis, origin, zaxis) +>>> R = random_rotation_matrix(numpy.random.rand(3)) +>>> M = concatenate_matrices(T, R, Z, S) +>>> scale, shear, angles, trans, persp = decompose_matrix(M) +>>> numpy.allclose(scale, 1.23) +True +>>> numpy.allclose(trans, (1, 2, 3)) +True +>>> numpy.allclose(shear, (0, math.tan(beta), 0)) +True +>>> is_same_transform(R, euler_matrix(axes='sxyz', *angles)) +True +>>> M1 = compose_matrix(scale, shear, angles, trans, persp) +>>> is_same_transform(M, M1) +True + +""" + +from __future__ import division + +import warnings +import math + +import numpy + +# Documentation in HTML format can be generated with Epydoc +__docformat__ = "restructuredtext en" + + +def identity_matrix(): + """Return 4x4 identity/unit matrix. + + >>> I = identity_matrix() + >>> numpy.allclose(I, numpy.dot(I, I)) + True + >>> numpy.sum(I), numpy.trace(I) + (4.0, 4.0) + >>> numpy.allclose(I, numpy.identity(4, dtype=numpy.float64)) + True + + """ + return numpy.identity(4, dtype=numpy.float64) + + +def translation_matrix(direction): + """Return matrix to translate by direction vector. + + >>> v = numpy.random.random(3) - 0.5 + >>> numpy.allclose(v, translation_matrix(v)[:3, 3]) + True + + """ + M = numpy.identity(4) + M[:3, 3] = direction[:3] + return M + + +def translation_from_matrix(matrix): + """Return translation vector from translation matrix. + + >>> v0 = numpy.random.random(3) - 0.5 + >>> v1 = translation_from_matrix(translation_matrix(v0)) + >>> numpy.allclose(v0, v1) + True + + """ + return numpy.array(matrix, copy=False)[:3, 3].copy() + + +def reflection_matrix(point, normal): + """Return matrix to mirror at plane defined by point and normal vector. + + >>> v0 = numpy.random.random(4) - 0.5 + >>> v0[3] = 1.0 + >>> v1 = numpy.random.random(3) - 0.5 + >>> R = reflection_matrix(v0, v1) + >>> numpy.allclose(2., numpy.trace(R)) + True + >>> numpy.allclose(v0, numpy.dot(R, v0)) + True + >>> v2 = v0.copy() + >>> v2[:3] += v1 + >>> v3 = v0.copy() + >>> v2[:3] -= v1 + >>> numpy.allclose(v2, numpy.dot(R, v3)) + True + + """ + normal = unit_vector(normal[:3]) + M = numpy.identity(4) + M[:3, :3] -= 2.0 * numpy.outer(normal, normal) + M[:3, 3] = (2.0 * numpy.dot(point[:3], normal)) * normal + return M + + +def reflection_from_matrix(matrix): + """Return mirror plane point and normal vector from reflection matrix. + + >>> v0 = numpy.random.random(3) - 0.5 + >>> v1 = numpy.random.random(3) - 0.5 + >>> M0 = reflection_matrix(v0, v1) + >>> point, normal = reflection_from_matrix(M0) + >>> M1 = reflection_matrix(point, normal) + >>> is_same_transform(M0, M1) + True + + """ + M = numpy.array(matrix, dtype=numpy.float64, copy=False) + # normal: unit eigenvector corresponding to eigenvalue -1 + l, V = numpy.linalg.eig(M[:3, :3]) + i = numpy.where(abs(numpy.real(l) + 1.0) < 1e-8)[0] + if not len(i): + raise ValueError("no unit eigenvector corresponding to eigenvalue -1") + normal = numpy.real(V[:, i[0]]).squeeze() + # point: any unit eigenvector corresponding to eigenvalue 1 + l, V = numpy.linalg.eig(M) + i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] + if not len(i): + raise ValueError("no unit eigenvector corresponding to eigenvalue 1") + point = numpy.real(V[:, i[-1]]).squeeze() + point /= point[3] + return point, normal + + +def rotation_matrix(angle, direction, point=None): + """Return matrix to rotate about axis defined by point and direction. + + >>> angle = (random.random() - 0.5) * (2*math.pi) + >>> direc = numpy.random.random(3) - 0.5 + >>> point = numpy.random.random(3) - 0.5 + >>> R0 = rotation_matrix(angle, direc, point) + >>> R1 = rotation_matrix(angle-2*math.pi, direc, point) + >>> is_same_transform(R0, R1) + True + >>> R0 = rotation_matrix(angle, direc, point) + >>> R1 = rotation_matrix(-angle, -direc, point) + >>> is_same_transform(R0, R1) + True + >>> I = numpy.identity(4, numpy.float64) + >>> numpy.allclose(I, rotation_matrix(math.pi*2, direc)) + True + >>> numpy.allclose(2., numpy.trace(rotation_matrix(math.pi/2, + ... direc, point))) + True + + """ + sina = math.sin(angle) + cosa = math.cos(angle) + direction = unit_vector(direction[:3]) + # rotation matrix around unit vector + R = numpy.array(((cosa, 0.0, 0.0), + (0.0, cosa, 0.0), + (0.0, 0.0, cosa)), dtype=numpy.float64) + R += numpy.outer(direction, direction) * (1.0 - cosa) + direction *= sina + R += numpy.array((( 0.0, -direction[2], direction[1]), + ( direction[2], 0.0, -direction[0]), + (-direction[1], direction[0], 0.0)), + dtype=numpy.float64) + M = numpy.identity(4) + M[:3, :3] = R + if point is not None: + # rotation not around origin + point = numpy.array(point[:3], dtype=numpy.float64, copy=False) + M[:3, 3] = point - numpy.dot(R, point) + return M + + +def rotation_from_matrix(matrix): + """Return rotation angle and axis from rotation matrix. + + >>> angle = (random.random() - 0.5) * (2*math.pi) + >>> direc = numpy.random.random(3) - 0.5 + >>> point = numpy.random.random(3) - 0.5 + >>> R0 = rotation_matrix(angle, direc, point) + >>> angle, direc, point = rotation_from_matrix(R0) + >>> R1 = rotation_matrix(angle, direc, point) + >>> is_same_transform(R0, R1) + True + + """ + R = numpy.array(matrix, dtype=numpy.float64, copy=False) + R33 = R[:3, :3] + # direction: unit eigenvector of R33 corresponding to eigenvalue of 1 + l, W = numpy.linalg.eig(R33.T) + i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] + if not len(i): + raise ValueError("no unit eigenvector corresponding to eigenvalue 1") + direction = numpy.real(W[:, i[-1]]).squeeze() + # point: unit eigenvector of R33 corresponding to eigenvalue of 1 + l, Q = numpy.linalg.eig(R) + i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] + if not len(i): + raise ValueError("no unit eigenvector corresponding to eigenvalue 1") + point = numpy.real(Q[:, i[-1]]).squeeze() + point /= point[3] + # rotation angle depending on direction + cosa = (numpy.trace(R33) - 1.0) / 2.0 + if abs(direction[2]) > 1e-8: + sina = (R[1, 0] + (cosa-1.0)*direction[0]*direction[1]) / direction[2] + elif abs(direction[1]) > 1e-8: + sina = (R[0, 2] + (cosa-1.0)*direction[0]*direction[2]) / direction[1] + else: + sina = (R[2, 1] + (cosa-1.0)*direction[1]*direction[2]) / direction[0] + angle = math.atan2(sina, cosa) + return angle, direction, point + + +def scale_matrix(factor, origin=None, direction=None): + """Return matrix to scale by factor around origin in direction. + + Use factor -1 for point symmetry. + + >>> v = (numpy.random.rand(4, 5) - 0.5) * 20.0 + >>> v[3] = 1.0 + >>> S = scale_matrix(-1.234) + >>> numpy.allclose(numpy.dot(S, v)[:3], -1.234*v[:3]) + True + >>> factor = random.random() * 10 - 5 + >>> origin = numpy.random.random(3) - 0.5 + >>> direct = numpy.random.random(3) - 0.5 + >>> S = scale_matrix(factor, origin) + >>> S = scale_matrix(factor, origin, direct) + + """ + if direction is None: + # uniform scaling + M = numpy.array(((factor, 0.0, 0.0, 0.0), + (0.0, factor, 0.0, 0.0), + (0.0, 0.0, factor, 0.0), + (0.0, 0.0, 0.0, 1.0)), dtype=numpy.float64) + if origin is not None: + M[:3, 3] = origin[:3] + M[:3, 3] *= 1.0 - factor + else: + # nonuniform scaling + direction = unit_vector(direction[:3]) + factor = 1.0 - factor + M = numpy.identity(4) + M[:3, :3] -= factor * numpy.outer(direction, direction) + if origin is not None: + M[:3, 3] = (factor * numpy.dot(origin[:3], direction)) * direction + return M + + +def scale_from_matrix(matrix): + """Return scaling factor, origin and direction from scaling matrix. + + >>> factor = random.random() * 10 - 5 + >>> origin = numpy.random.random(3) - 0.5 + >>> direct = numpy.random.random(3) - 0.5 + >>> S0 = scale_matrix(factor, origin) + >>> factor, origin, direction = scale_from_matrix(S0) + >>> S1 = scale_matrix(factor, origin, direction) + >>> is_same_transform(S0, S1) + True + >>> S0 = scale_matrix(factor, origin, direct) + >>> factor, origin, direction = scale_from_matrix(S0) + >>> S1 = scale_matrix(factor, origin, direction) + >>> is_same_transform(S0, S1) + True + + """ + M = numpy.array(matrix, dtype=numpy.float64, copy=False) + M33 = M[:3, :3] + factor = numpy.trace(M33) - 2.0 + try: + # direction: unit eigenvector corresponding to eigenvalue factor + l, V = numpy.linalg.eig(M33) + i = numpy.where(abs(numpy.real(l) - factor) < 1e-8)[0][0] + direction = numpy.real(V[:, i]).squeeze() + direction /= vector_norm(direction) + except IndexError: + # uniform scaling + factor = (factor + 2.0) / 3.0 + direction = None + # origin: any eigenvector corresponding to eigenvalue 1 + l, V = numpy.linalg.eig(M) + i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] + if not len(i): + raise ValueError("no eigenvector corresponding to eigenvalue 1") + origin = numpy.real(V[:, i[-1]]).squeeze() + origin /= origin[3] + return factor, origin, direction + + +def projection_matrix(point, normal, direction=None, + perspective=None, pseudo=False): + """Return matrix to project onto plane defined by point and normal. + + Using either perspective point, projection direction, or none of both. + + If pseudo is True, perspective projections will preserve relative depth + such that Perspective = dot(Orthogonal, PseudoPerspective). + + >>> P = projection_matrix((0, 0, 0), (1, 0, 0)) + >>> numpy.allclose(P[1:, 1:], numpy.identity(4)[1:, 1:]) + True + >>> point = numpy.random.random(3) - 0.5 + >>> normal = numpy.random.random(3) - 0.5 + >>> direct = numpy.random.random(3) - 0.5 + >>> persp = numpy.random.random(3) - 0.5 + >>> P0 = projection_matrix(point, normal) + >>> P1 = projection_matrix(point, normal, direction=direct) + >>> P2 = projection_matrix(point, normal, perspective=persp) + >>> P3 = projection_matrix(point, normal, perspective=persp, pseudo=True) + >>> is_same_transform(P2, numpy.dot(P0, P3)) + True + >>> P = projection_matrix((3, 0, 0), (1, 1, 0), (1, 0, 0)) + >>> v0 = (numpy.random.rand(4, 5) - 0.5) * 20.0 + >>> v0[3] = 1.0 + >>> v1 = numpy.dot(P, v0) + >>> numpy.allclose(v1[1], v0[1]) + True + >>> numpy.allclose(v1[0], 3.0-v1[1]) + True + + """ + M = numpy.identity(4) + point = numpy.array(point[:3], dtype=numpy.float64, copy=False) + normal = unit_vector(normal[:3]) + if perspective is not None: + # perspective projection + perspective = numpy.array(perspective[:3], dtype=numpy.float64, + copy=False) + M[0, 0] = M[1, 1] = M[2, 2] = numpy.dot(perspective-point, normal) + M[:3, :3] -= numpy.outer(perspective, normal) + if pseudo: + # preserve relative depth + M[:3, :3] -= numpy.outer(normal, normal) + M[:3, 3] = numpy.dot(point, normal) * (perspective+normal) + else: + M[:3, 3] = numpy.dot(point, normal) * perspective + M[3, :3] = -normal + M[3, 3] = numpy.dot(perspective, normal) + elif direction is not None: + # parallel projection + direction = numpy.array(direction[:3], dtype=numpy.float64, copy=False) + scale = numpy.dot(direction, normal) + M[:3, :3] -= numpy.outer(direction, normal) / scale + M[:3, 3] = direction * (numpy.dot(point, normal) / scale) + else: + # orthogonal projection + M[:3, :3] -= numpy.outer(normal, normal) + M[:3, 3] = numpy.dot(point, normal) * normal + return M + + +def projection_from_matrix(matrix, pseudo=False): + """Return projection plane and perspective point from projection matrix. + + Return values are same as arguments for projection_matrix function: + point, normal, direction, perspective, and pseudo. + + >>> point = numpy.random.random(3) - 0.5 + >>> normal = numpy.random.random(3) - 0.5 + >>> direct = numpy.random.random(3) - 0.5 + >>> persp = numpy.random.random(3) - 0.5 + >>> P0 = projection_matrix(point, normal) + >>> result = projection_from_matrix(P0) + >>> P1 = projection_matrix(*result) + >>> is_same_transform(P0, P1) + True + >>> P0 = projection_matrix(point, normal, direct) + >>> result = projection_from_matrix(P0) + >>> P1 = projection_matrix(*result) + >>> is_same_transform(P0, P1) + True + >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=False) + >>> result = projection_from_matrix(P0, pseudo=False) + >>> P1 = projection_matrix(*result) + >>> is_same_transform(P0, P1) + True + >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=True) + >>> result = projection_from_matrix(P0, pseudo=True) + >>> P1 = projection_matrix(*result) + >>> is_same_transform(P0, P1) + True + + """ + M = numpy.array(matrix, dtype=numpy.float64, copy=False) + M33 = M[:3, :3] + l, V = numpy.linalg.eig(M) + i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] + if not pseudo and len(i): + # point: any eigenvector corresponding to eigenvalue 1 + point = numpy.real(V[:, i[-1]]).squeeze() + point /= point[3] + # direction: unit eigenvector corresponding to eigenvalue 0 + l, V = numpy.linalg.eig(M33) + i = numpy.where(abs(numpy.real(l)) < 1e-8)[0] + if not len(i): + raise ValueError("no eigenvector corresponding to eigenvalue 0") + direction = numpy.real(V[:, i[0]]).squeeze() + direction /= vector_norm(direction) + # normal: unit eigenvector of M33.T corresponding to eigenvalue 0 + l, V = numpy.linalg.eig(M33.T) + i = numpy.where(abs(numpy.real(l)) < 1e-8)[0] + if len(i): + # parallel projection + normal = numpy.real(V[:, i[0]]).squeeze() + normal /= vector_norm(normal) + return point, normal, direction, None, False + else: + # orthogonal projection, where normal equals direction vector + return point, direction, None, None, False + else: + # perspective projection + i = numpy.where(abs(numpy.real(l)) > 1e-8)[0] + if not len(i): + raise ValueError( + "no eigenvector not corresponding to eigenvalue 0") + point = numpy.real(V[:, i[-1]]).squeeze() + point /= point[3] + normal = - M[3, :3] + perspective = M[:3, 3] / numpy.dot(point[:3], normal) + if pseudo: + perspective -= normal + return point, normal, None, perspective, pseudo + + +def clip_matrix(left, right, bottom, top, near, far, perspective=False): + """Return matrix to obtain normalized device coordinates from frustrum. + + The frustrum bounds are axis-aligned along x (left, right), + y (bottom, top) and z (near, far). + + Normalized device coordinates are in range [-1, 1] if coordinates are + inside the frustrum. + + If perspective is True the frustrum is a truncated pyramid with the + perspective point at origin and direction along z axis, otherwise an + orthographic canonical view volume (a box). + + Homogeneous coordinates transformed by the perspective clip matrix + need to be dehomogenized (divided by w coordinate). + + >>> frustrum = numpy.random.rand(6) + >>> frustrum[1] += frustrum[0] + >>> frustrum[3] += frustrum[2] + >>> frustrum[5] += frustrum[4] + >>> M = clip_matrix(*frustrum, perspective=False) + >>> numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0]) + array([-1., -1., -1., 1.]) + >>> numpy.dot(M, [frustrum[1], frustrum[3], frustrum[5], 1.0]) + array([ 1., 1., 1., 1.]) + >>> M = clip_matrix(*frustrum, perspective=True) + >>> v = numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0]) + >>> v / v[3] + array([-1., -1., -1., 1.]) + >>> v = numpy.dot(M, [frustrum[1], frustrum[3], frustrum[4], 1.0]) + >>> v / v[3] + array([ 1., 1., -1., 1.]) + + """ + if left >= right or bottom >= top or near >= far: + raise ValueError("invalid frustrum") + if perspective: + if near <= _EPS: + raise ValueError("invalid frustrum: near <= 0") + t = 2.0 * near + M = ((-t/(right-left), 0.0, (right+left)/(right-left), 0.0), + (0.0, -t/(top-bottom), (top+bottom)/(top-bottom), 0.0), + (0.0, 0.0, -(far+near)/(far-near), t*far/(far-near)), + (0.0, 0.0, -1.0, 0.0)) + else: + M = ((2.0/(right-left), 0.0, 0.0, (right+left)/(left-right)), + (0.0, 2.0/(top-bottom), 0.0, (top+bottom)/(bottom-top)), + (0.0, 0.0, 2.0/(far-near), (far+near)/(near-far)), + (0.0, 0.0, 0.0, 1.0)) + return numpy.array(M, dtype=numpy.float64) + + +def shear_matrix(angle, direction, point, normal): + """Return matrix to shear by angle along direction vector on shear plane. + + The shear plane is defined by a point and normal vector. The direction + vector must be orthogonal to the plane's normal vector. + + A point P is transformed by the shear matrix into P" such that + the vector P-P" is parallel to the direction vector and its extent is + given by the angle of P-P'-P", where P' is the orthogonal projection + of P onto the shear plane. + + >>> angle = (random.random() - 0.5) * 4*math.pi + >>> direct = numpy.random.random(3) - 0.5 + >>> point = numpy.random.random(3) - 0.5 + >>> normal = numpy.cross(direct, numpy.random.random(3)) + >>> S = shear_matrix(angle, direct, point, normal) + >>> numpy.allclose(1.0, numpy.linalg.det(S)) + True + + """ + normal = unit_vector(normal[:3]) + direction = unit_vector(direction[:3]) + if abs(numpy.dot(normal, direction)) > 1e-6: + raise ValueError("direction and normal vectors are not orthogonal") + angle = math.tan(angle) + M = numpy.identity(4) + M[:3, :3] += angle * numpy.outer(direction, normal) + M[:3, 3] = -angle * numpy.dot(point[:3], normal) * direction + return M + + +def shear_from_matrix(matrix): + """Return shear angle, direction and plane from shear matrix. + + >>> angle = (random.random() - 0.5) * 4*math.pi + >>> direct = numpy.random.random(3) - 0.5 + >>> point = numpy.random.random(3) - 0.5 + >>> normal = numpy.cross(direct, numpy.random.random(3)) + >>> S0 = shear_matrix(angle, direct, point, normal) + >>> angle, direct, point, normal = shear_from_matrix(S0) + >>> S1 = shear_matrix(angle, direct, point, normal) + >>> is_same_transform(S0, S1) + True + + """ + M = numpy.array(matrix, dtype=numpy.float64, copy=False) + M33 = M[:3, :3] + # normal: cross independent eigenvectors corresponding to the eigenvalue 1 + l, V = numpy.linalg.eig(M33) + i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-4)[0] + if len(i) < 2: + raise ValueError("No two linear independent eigenvectors found %s" % l) + V = numpy.real(V[:, i]).squeeze().T + lenorm = -1.0 + for i0, i1 in ((0, 1), (0, 2), (1, 2)): + n = numpy.cross(V[i0], V[i1]) + l = vector_norm(n) + if l > lenorm: + lenorm = l + normal = n + normal /= lenorm + # direction and angle + direction = numpy.dot(M33 - numpy.identity(3), normal) + angle = vector_norm(direction) + direction /= angle + angle = math.atan(angle) + # point: eigenvector corresponding to eigenvalue 1 + l, V = numpy.linalg.eig(M) + i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] + if not len(i): + raise ValueError("no eigenvector corresponding to eigenvalue 1") + point = numpy.real(V[:, i[-1]]).squeeze() + point /= point[3] + return angle, direction, point, normal + + +def decompose_matrix(matrix): + """Return sequence of transformations from transformation matrix. + + matrix : array_like + Non-degenerative homogeneous transformation matrix + + Return tuple of: + scale : vector of 3 scaling factors + shear : list of shear factors for x-y, x-z, y-z axes + angles : list of Euler angles about static x, y, z axes + translate : translation vector along x, y, z axes + perspective : perspective partition of matrix + + Raise ValueError if matrix is of wrong type or degenerative. + + >>> T0 = translation_matrix((1, 2, 3)) + >>> scale, shear, angles, trans, persp = decompose_matrix(T0) + >>> T1 = translation_matrix(trans) + >>> numpy.allclose(T0, T1) + True + >>> S = scale_matrix(0.123) + >>> scale, shear, angles, trans, persp = decompose_matrix(S) + >>> scale[0] + 0.123 + >>> R0 = euler_matrix(1, 2, 3) + >>> scale, shear, angles, trans, persp = decompose_matrix(R0) + >>> R1 = euler_matrix(*angles) + >>> numpy.allclose(R0, R1) + True + + """ + M = numpy.array(matrix, dtype=numpy.float64, copy=True).T + if abs(M[3, 3]) < _EPS: + raise ValueError("M[3, 3] is zero") + M /= M[3, 3] + P = M.copy() + P[:, 3] = 0, 0, 0, 1 + if not numpy.linalg.det(P): + raise ValueError("Matrix is singular") + + scale = numpy.zeros((3, ), dtype=numpy.float64) + shear = [0, 0, 0] + angles = [0, 0, 0] + + if any(abs(M[:3, 3]) > _EPS): + perspective = numpy.dot(M[:, 3], numpy.linalg.inv(P.T)) + M[:, 3] = 0, 0, 0, 1 + else: + perspective = numpy.array((0, 0, 0, 1), dtype=numpy.float64) + + translate = M[3, :3].copy() + M[3, :3] = 0 + + row = M[:3, :3].copy() + scale[0] = vector_norm(row[0]) + row[0] /= scale[0] + shear[0] = numpy.dot(row[0], row[1]) + row[1] -= row[0] * shear[0] + scale[1] = vector_norm(row[1]) + row[1] /= scale[1] + shear[0] /= scale[1] + shear[1] = numpy.dot(row[0], row[2]) + row[2] -= row[0] * shear[1] + shear[2] = numpy.dot(row[1], row[2]) + row[2] -= row[1] * shear[2] + scale[2] = vector_norm(row[2]) + row[2] /= scale[2] + shear[1:] /= scale[2] + + if numpy.dot(row[0], numpy.cross(row[1], row[2])) < 0: + scale *= -1 + row *= -1 + + angles[1] = math.asin(-row[0, 2]) + if math.cos(angles[1]): + angles[0] = math.atan2(row[1, 2], row[2, 2]) + angles[2] = math.atan2(row[0, 1], row[0, 0]) + else: + #angles[0] = math.atan2(row[1, 0], row[1, 1]) + angles[0] = math.atan2(-row[2, 1], row[1, 1]) + angles[2] = 0.0 + + return scale, shear, angles, translate, perspective + + +def compose_matrix(scale=None, shear=None, angles=None, translate=None, + perspective=None): + """Return transformation matrix from sequence of transformations. + + This is the inverse of the decompose_matrix function. + + Sequence of transformations: + scale : vector of 3 scaling factors + shear : list of shear factors for x-y, x-z, y-z axes + angles : list of Euler angles about static x, y, z axes + translate : translation vector along x, y, z axes + perspective : perspective partition of matrix + + >>> scale = numpy.random.random(3) - 0.5 + >>> shear = numpy.random.random(3) - 0.5 + >>> angles = (numpy.random.random(3) - 0.5) * (2*math.pi) + >>> trans = numpy.random.random(3) - 0.5 + >>> persp = numpy.random.random(4) - 0.5 + >>> M0 = compose_matrix(scale, shear, angles, trans, persp) + >>> result = decompose_matrix(M0) + >>> M1 = compose_matrix(*result) + >>> is_same_transform(M0, M1) + True + + """ + M = numpy.identity(4) + if perspective is not None: + P = numpy.identity(4) + P[3, :] = perspective[:4] + M = numpy.dot(M, P) + if translate is not None: + T = numpy.identity(4) + T[:3, 3] = translate[:3] + M = numpy.dot(M, T) + if angles is not None: + R = euler_matrix(angles[0], angles[1], angles[2], 'sxyz') + M = numpy.dot(M, R) + if shear is not None: + Z = numpy.identity(4) + Z[1, 2] = shear[2] + Z[0, 2] = shear[1] + Z[0, 1] = shear[0] + M = numpy.dot(M, Z) + if scale is not None: + S = numpy.identity(4) + S[0, 0] = scale[0] + S[1, 1] = scale[1] + S[2, 2] = scale[2] + M = numpy.dot(M, S) + M /= M[3, 3] + return M + + +def orthogonalization_matrix(lengths, angles): + """Return orthogonalization matrix for crystallographic cell coordinates. + + Angles are expected in degrees. + + The de-orthogonalization matrix is the inverse. + + >>> O = orthogonalization_matrix((10., 10., 10.), (90., 90., 90.)) + >>> numpy.allclose(O[:3, :3], numpy.identity(3, float) * 10) + True + >>> O = orthogonalization_matrix([9.8, 12.0, 15.5], [87.2, 80.7, 69.7]) + >>> numpy.allclose(numpy.sum(O), 43.063229) + True + + """ + a, b, c = lengths + angles = numpy.radians(angles) + sina, sinb, _ = numpy.sin(angles) + cosa, cosb, cosg = numpy.cos(angles) + co = (cosa * cosb - cosg) / (sina * sinb) + return numpy.array(( + ( a*sinb*math.sqrt(1.0-co*co), 0.0, 0.0, 0.0), + (-a*sinb*co, b*sina, 0.0, 0.0), + ( a*cosb, b*cosa, c, 0.0), + ( 0.0, 0.0, 0.0, 1.0)), + dtype=numpy.float64) + + +def superimposition_matrix(v0, v1, scaling=False, usesvd=True): + """Return matrix to transform given vector set into second vector set. + + v0 and v1 are shape (3, \*) or (4, \*) arrays of at least 3 vectors. + + If usesvd is True, the weighted sum of squared deviations (RMSD) is + minimized according to the algorithm by W. Kabsch [8]. Otherwise the + quaternion based algorithm by B. Horn [9] is used (slower when using + this Python implementation). + + The returned matrix performs rotation, translation and uniform scaling + (if specified). + + >>> v0 = numpy.random.rand(3, 10) + >>> M = superimposition_matrix(v0, v0) + >>> numpy.allclose(M, numpy.identity(4)) + True + >>> R = random_rotation_matrix(numpy.random.random(3)) + >>> v0 = ((1,0,0), (0,1,0), (0,0,1), (1,1,1)) + >>> v1 = numpy.dot(R, v0) + >>> M = superimposition_matrix(v0, v1) + >>> numpy.allclose(v1, numpy.dot(M, v0)) + True + >>> v0 = (numpy.random.rand(4, 100) - 0.5) * 20.0 + >>> v0[3] = 1.0 + >>> v1 = numpy.dot(R, v0) + >>> M = superimposition_matrix(v0, v1) + >>> numpy.allclose(v1, numpy.dot(M, v0)) + True + >>> S = scale_matrix(random.random()) + >>> T = translation_matrix(numpy.random.random(3)-0.5) + >>> M = concatenate_matrices(T, R, S) + >>> v1 = numpy.dot(M, v0) + >>> v0[:3] += numpy.random.normal(0.0, 1e-9, 300).reshape(3, -1) + >>> M = superimposition_matrix(v0, v1, scaling=True) + >>> numpy.allclose(v1, numpy.dot(M, v0)) + True + >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False) + >>> numpy.allclose(v1, numpy.dot(M, v0)) + True + >>> v = numpy.empty((4, 100, 3), dtype=numpy.float64) + >>> v[:, :, 0] = v0 + >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False) + >>> numpy.allclose(v1, numpy.dot(M, v[:, :, 0])) + True + + """ + v0 = numpy.array(v0, dtype=numpy.float64, copy=False)[:3] + v1 = numpy.array(v1, dtype=numpy.float64, copy=False)[:3] + + if v0.shape != v1.shape or v0.shape[1] < 3: + raise ValueError("Vector sets are of wrong shape or type.") + + # move centroids to origin + t0 = numpy.mean(v0, axis=1) + t1 = numpy.mean(v1, axis=1) + v0 = v0 - t0.reshape(3, 1) + v1 = v1 - t1.reshape(3, 1) + + if usesvd: + # Singular Value Decomposition of covariance matrix + u, s, vh = numpy.linalg.svd(numpy.dot(v1, v0.T)) + # rotation matrix from SVD orthonormal bases + R = numpy.dot(u, vh) + if numpy.linalg.det(R) < 0.0: + # R does not constitute right handed system + R -= numpy.outer(u[:, 2], vh[2, :]*2.0) + s[-1] *= -1.0 + # homogeneous transformation matrix + M = numpy.identity(4) + M[:3, :3] = R + else: + # compute symmetric matrix N + xx, yy, zz = numpy.sum(v0 * v1, axis=1) + xy, yz, zx = numpy.sum(v0 * numpy.roll(v1, -1, axis=0), axis=1) + xz, yx, zy = numpy.sum(v0 * numpy.roll(v1, -2, axis=0), axis=1) + N = ((xx+yy+zz, yz-zy, zx-xz, xy-yx), + (yz-zy, xx-yy-zz, xy+yx, zx+xz), + (zx-xz, xy+yx, -xx+yy-zz, yz+zy), + (xy-yx, zx+xz, yz+zy, -xx-yy+zz)) + # quaternion: eigenvector corresponding to most positive eigenvalue + l, V = numpy.linalg.eig(N) + q = V[:, numpy.argmax(l)] + q /= vector_norm(q) # unit quaternion + q = numpy.roll(q, -1) # move w component to end + # homogeneous transformation matrix + M = quaternion_matrix(q) + + # scale: ratio of rms deviations from centroid + if scaling: + v0 *= v0 + v1 *= v1 + M[:3, :3] *= math.sqrt(numpy.sum(v1) / numpy.sum(v0)) + + # translation + M[:3, 3] = t1 + T = numpy.identity(4) + T[:3, 3] = -t0 + M = numpy.dot(M, T) + return M + + +def euler_matrix(ai, aj, ak, axes='sxyz'): + """Return homogeneous rotation matrix from Euler angles and axis sequence. + + ai, aj, ak : Euler's roll, pitch and yaw angles + axes : One of 24 axis sequences as string or encoded tuple + + >>> R = euler_matrix(1, 2, 3, 'syxz') + >>> numpy.allclose(numpy.sum(R[0]), -1.34786452) + True + >>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1)) + >>> numpy.allclose(numpy.sum(R[0]), -0.383436184) + True + >>> ai, aj, ak = (4.0*math.pi) * (numpy.random.random(3) - 0.5) + >>> for axes in _AXES2TUPLE.keys(): + ... R = euler_matrix(ai, aj, ak, axes) + >>> for axes in _TUPLE2AXES.keys(): + ... R = euler_matrix(ai, aj, ak, axes) + + """ + try: + firstaxis, parity, repetition, frame = _AXES2TUPLE[axes] + except (AttributeError, KeyError): + _ = _TUPLE2AXES[axes] + firstaxis, parity, repetition, frame = axes + + i = firstaxis + j = _NEXT_AXIS[i+parity] + k = _NEXT_AXIS[i-parity+1] + + if frame: + ai, ak = ak, ai + if parity: + ai, aj, ak = -ai, -aj, -ak + + si, sj, sk = math.sin(ai), math.sin(aj), math.sin(ak) + ci, cj, ck = math.cos(ai), math.cos(aj), math.cos(ak) + cc, cs = ci*ck, ci*sk + sc, ss = si*ck, si*sk + + M = numpy.identity(4) + if repetition: + M[i, i] = cj + M[i, j] = sj*si + M[i, k] = sj*ci + M[j, i] = sj*sk + M[j, j] = -cj*ss+cc + M[j, k] = -cj*cs-sc + M[k, i] = -sj*ck + M[k, j] = cj*sc+cs + M[k, k] = cj*cc-ss + else: + M[i, i] = cj*ck + M[i, j] = sj*sc-cs + M[i, k] = sj*cc+ss + M[j, i] = cj*sk + M[j, j] = sj*ss+cc + M[j, k] = sj*cs-sc + M[k, i] = -sj + M[k, j] = cj*si + M[k, k] = cj*ci + return M + + +def euler_from_matrix(matrix, axes='sxyz'): + """Return Euler angles from rotation matrix for specified axis sequence. + + axes : One of 24 axis sequences as string or encoded tuple + + Note that many Euler angle triplets can describe one matrix. + + >>> R0 = euler_matrix(1, 2, 3, 'syxz') + >>> al, be, ga = euler_from_matrix(R0, 'syxz') + >>> R1 = euler_matrix(al, be, ga, 'syxz') + >>> numpy.allclose(R0, R1) + True + >>> angles = (4.0*math.pi) * (numpy.random.random(3) - 0.5) + >>> for axes in _AXES2TUPLE.keys(): + ... R0 = euler_matrix(axes=axes, *angles) + ... R1 = euler_matrix(axes=axes, *euler_from_matrix(R0, axes)) + ... if not numpy.allclose(R0, R1): print axes, "failed" + + """ + try: + firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()] + except (AttributeError, KeyError): + _ = _TUPLE2AXES[axes] + firstaxis, parity, repetition, frame = axes + + i = firstaxis + j = _NEXT_AXIS[i+parity] + k = _NEXT_AXIS[i-parity+1] + + M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:3, :3] + if repetition: + sy = math.sqrt(M[i, j]*M[i, j] + M[i, k]*M[i, k]) + if sy > _EPS: + ax = math.atan2( M[i, j], M[i, k]) + ay = math.atan2( sy, M[i, i]) + az = math.atan2( M[j, i], -M[k, i]) + else: + ax = math.atan2(-M[j, k], M[j, j]) + ay = math.atan2( sy, M[i, i]) + az = 0.0 + else: + cy = math.sqrt(M[i, i]*M[i, i] + M[j, i]*M[j, i]) + if cy > _EPS: + ax = math.atan2( M[k, j], M[k, k]) + ay = math.atan2(-M[k, i], cy) + az = math.atan2( M[j, i], M[i, i]) + else: + ax = math.atan2(-M[j, k], M[j, j]) + ay = math.atan2(-M[k, i], cy) + az = 0.0 + + if parity: + ax, ay, az = -ax, -ay, -az + if frame: + ax, az = az, ax + return ax, ay, az + + +def euler_from_quaternion(quaternion, axes='sxyz'): + """Return Euler angles from quaternion for specified axis sequence. + + >>> angles = euler_from_quaternion([0.06146124, 0, 0, 0.99810947]) + >>> numpy.allclose(angles, [0.123, 0, 0]) + True + + """ + return euler_from_matrix(quaternion_matrix(quaternion), axes) + + +def quaternion_from_euler(ai, aj, ak, axes='sxyz'): + """Return quaternion from Euler angles and axis sequence. + + ai, aj, ak : Euler's roll, pitch and yaw angles + axes : One of 24 axis sequences as string or encoded tuple + + >>> q = quaternion_from_euler(1, 2, 3, 'ryxz') + >>> numpy.allclose(q, [0.310622, -0.718287, 0.444435, 0.435953]) + True + + """ + try: + firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()] + except (AttributeError, KeyError): + _ = _TUPLE2AXES[axes] + firstaxis, parity, repetition, frame = axes + + i = firstaxis + j = _NEXT_AXIS[i+parity] + k = _NEXT_AXIS[i-parity+1] + + if frame: + ai, ak = ak, ai + if parity: + aj = -aj + + ai /= 2.0 + aj /= 2.0 + ak /= 2.0 + ci = math.cos(ai) + si = math.sin(ai) + cj = math.cos(aj) + sj = math.sin(aj) + ck = math.cos(ak) + sk = math.sin(ak) + cc = ci*ck + cs = ci*sk + sc = si*ck + ss = si*sk + + quaternion = numpy.empty((4, ), dtype=numpy.float64) + if repetition: + quaternion[i] = cj*(cs + sc) + quaternion[j] = sj*(cc + ss) + quaternion[k] = sj*(cs - sc) + quaternion[3] = cj*(cc - ss) + else: + quaternion[i] = cj*sc - sj*cs + quaternion[j] = cj*ss + sj*cc + quaternion[k] = cj*cs - sj*sc + quaternion[3] = cj*cc + sj*ss + if parity: + quaternion[j] *= -1 + + return quaternion + + +def quaternion_about_axis(angle, axis): + """Return quaternion for rotation about axis. + + >>> q = quaternion_about_axis(0.123, (1, 0, 0)) + >>> numpy.allclose(q, [0.06146124, 0, 0, 0.99810947]) + True + + """ + quaternion = numpy.zeros((4, ), dtype=numpy.float64) + quaternion[:3] = axis[:3] + qlen = vector_norm(quaternion) + if qlen > _EPS: + quaternion *= math.sin(angle/2.0) / qlen + quaternion[3] = math.cos(angle/2.0) + return quaternion + + +def quaternion_matrix(quaternion): + """Return homogeneous rotation matrix from quaternion. + + >>> R = quaternion_matrix([0.06146124, 0, 0, 0.99810947]) + >>> numpy.allclose(R, rotation_matrix(0.123, (1, 0, 0))) + True + + """ + q = numpy.array(quaternion[:4], dtype=numpy.float64, copy=True) + nq = numpy.dot(q, q) + if nq < _EPS: + return numpy.identity(4) + q *= math.sqrt(2.0 / nq) + q = numpy.outer(q, q) + return numpy.array(( + (1.0-q[1, 1]-q[2, 2], q[0, 1]-q[2, 3], q[0, 2]+q[1, 3], 0.0), + ( q[0, 1]+q[2, 3], 1.0-q[0, 0]-q[2, 2], q[1, 2]-q[0, 3], 0.0), + ( q[0, 2]-q[1, 3], q[1, 2]+q[0, 3], 1.0-q[0, 0]-q[1, 1], 0.0), + ( 0.0, 0.0, 0.0, 1.0) + ), dtype=numpy.float64) + + +def quaternion_from_matrix(matrix): + """Return quaternion from rotation matrix. + + >>> R = rotation_matrix(0.123, (1, 2, 3)) + >>> q = quaternion_from_matrix(R) + >>> numpy.allclose(q, [0.0164262, 0.0328524, 0.0492786, 0.9981095]) + True + + """ + q = numpy.empty((4, ), dtype=numpy.float64) + M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:4, :4] + t = numpy.trace(M) + if t > M[3, 3]: + q[3] = t + q[2] = M[1, 0] - M[0, 1] + q[1] = M[0, 2] - M[2, 0] + q[0] = M[2, 1] - M[1, 2] + else: + i, j, k = 0, 1, 2 + if M[1, 1] > M[0, 0]: + i, j, k = 1, 2, 0 + if M[2, 2] > M[i, i]: + i, j, k = 2, 0, 1 + t = M[i, i] - (M[j, j] + M[k, k]) + M[3, 3] + q[i] = t + q[j] = M[i, j] + M[j, i] + q[k] = M[k, i] + M[i, k] + q[3] = M[k, j] - M[j, k] + q *= 0.5 / math.sqrt(t * M[3, 3]) + return q + + +def quaternion_multiply(quaternion1, quaternion0): + """Return multiplication of two quaternions. + + >>> q = quaternion_multiply([1, -2, 3, 4], [-5, 6, 7, 8]) + >>> numpy.allclose(q, [-44, -14, 48, 28]) + True + + """ + x0, y0, z0, w0 = quaternion0 + x1, y1, z1, w1 = quaternion1 + return numpy.array(( + x1*w0 + y1*z0 - z1*y0 + w1*x0, + -x1*z0 + y1*w0 + z1*x0 + w1*y0, + x1*y0 - y1*x0 + z1*w0 + w1*z0, + -x1*x0 - y1*y0 - z1*z0 + w1*w0), dtype=numpy.float64) + + +def quaternion_conjugate(quaternion): + """Return conjugate of quaternion. + + >>> q0 = random_quaternion() + >>> q1 = quaternion_conjugate(q0) + >>> q1[3] == q0[3] and all(q1[:3] == -q0[:3]) + True + + """ + return numpy.array((-quaternion[0], -quaternion[1], + -quaternion[2], quaternion[3]), dtype=numpy.float64) + + +def quaternion_inverse(quaternion): + """Return inverse of quaternion. + + >>> q0 = random_quaternion() + >>> q1 = quaternion_inverse(q0) + >>> numpy.allclose(quaternion_multiply(q0, q1), [0, 0, 0, 1]) + True + + """ + return quaternion_conjugate(quaternion) / numpy.dot(quaternion, quaternion) + + +def quaternion_slerp(quat0, quat1, fraction, spin=0, shortestpath=True): + """Return spherical linear interpolation between two quaternions. + + >>> q0 = random_quaternion() + >>> q1 = random_quaternion() + >>> q = quaternion_slerp(q0, q1, 0.0) + >>> numpy.allclose(q, q0) + True + >>> q = quaternion_slerp(q0, q1, 1.0, 1) + >>> numpy.allclose(q, q1) + True + >>> q = quaternion_slerp(q0, q1, 0.5) + >>> angle = math.acos(numpy.dot(q0, q)) + >>> numpy.allclose(2.0, math.acos(numpy.dot(q0, q1)) / angle) or \ + numpy.allclose(2.0, math.acos(-numpy.dot(q0, q1)) / angle) + True + + """ + q0 = unit_vector(quat0[:4]) + q1 = unit_vector(quat1[:4]) + if fraction == 0.0: + return q0 + elif fraction == 1.0: + return q1 + d = numpy.dot(q0, q1) + if abs(abs(d) - 1.0) < _EPS: + return q0 + if shortestpath and d < 0.0: + # invert rotation + d = -d + q1 *= -1.0 + angle = math.acos(d) + spin * math.pi + if abs(angle) < _EPS: + return q0 + isin = 1.0 / math.sin(angle) + q0 *= math.sin((1.0 - fraction) * angle) * isin + q1 *= math.sin(fraction * angle) * isin + q0 += q1 + return q0 + + +def random_quaternion(rand=None): + """Return uniform random unit quaternion. + + rand: array like or None + Three independent random variables that are uniformly distributed + between 0 and 1. + + >>> q = random_quaternion() + >>> numpy.allclose(1.0, vector_norm(q)) + True + >>> q = random_quaternion(numpy.random.random(3)) + >>> q.shape + (4,) + + """ + if rand is None: + rand = numpy.random.rand(3) + else: + assert len(rand) == 3 + r1 = numpy.sqrt(1.0 - rand[0]) + r2 = numpy.sqrt(rand[0]) + pi2 = math.pi * 2.0 + t1 = pi2 * rand[1] + t2 = pi2 * rand[2] + return numpy.array((numpy.sin(t1)*r1, + numpy.cos(t1)*r1, + numpy.sin(t2)*r2, + numpy.cos(t2)*r2), dtype=numpy.float64) + + +def random_rotation_matrix(rand=None): + """Return uniform random rotation matrix. + + rnd: array like + Three independent random variables that are uniformly distributed + between 0 and 1 for each returned quaternion. + + >>> R = random_rotation_matrix() + >>> numpy.allclose(numpy.dot(R.T, R), numpy.identity(4)) + True + + """ + return quaternion_matrix(random_quaternion(rand)) + + +class Arcball(object): + """Virtual Trackball Control. + + >>> ball = Arcball() + >>> ball = Arcball(initial=numpy.identity(4)) + >>> ball.place([320, 320], 320) + >>> ball.down([500, 250]) + >>> ball.drag([475, 275]) + >>> R = ball.matrix() + >>> numpy.allclose(numpy.sum(R), 3.90583455) + True + >>> ball = Arcball(initial=[0, 0, 0, 1]) + >>> ball.place([320, 320], 320) + >>> ball.setaxes([1,1,0], [-1, 1, 0]) + >>> ball.setconstrain(True) + >>> ball.down([400, 200]) + >>> ball.drag([200, 400]) + >>> R = ball.matrix() + >>> numpy.allclose(numpy.sum(R), 0.2055924) + True + >>> ball.next() + + """ + + def __init__(self, initial=None): + """Initialize virtual trackball control. + + initial : quaternion or rotation matrix + + """ + self._axis = None + self._axes = None + self._radius = 1.0 + self._center = [0.0, 0.0] + self._vdown = numpy.array([0, 0, 1], dtype=numpy.float64) + self._constrain = False + + if initial is None: + self._qdown = numpy.array([0, 0, 0, 1], dtype=numpy.float64) + else: + initial = numpy.array(initial, dtype=numpy.float64) + if initial.shape == (4, 4): + self._qdown = quaternion_from_matrix(initial) + elif initial.shape == (4, ): + initial /= vector_norm(initial) + self._qdown = initial + else: + raise ValueError("initial not a quaternion or matrix.") + + self._qnow = self._qpre = self._qdown + + def place(self, center, radius): + """Place Arcball, e.g. when window size changes. + + center : sequence[2] + Window coordinates of trackball center. + radius : float + Radius of trackball in window coordinates. + + """ + self._radius = float(radius) + self._center[0] = center[0] + self._center[1] = center[1] + + def setaxes(self, *axes): + """Set axes to constrain rotations.""" + if axes is None: + self._axes = None + else: + self._axes = [unit_vector(axis) for axis in axes] + + def setconstrain(self, constrain): + """Set state of constrain to axis mode.""" + self._constrain = constrain == True + + def getconstrain(self): + """Return state of constrain to axis mode.""" + return self._constrain + + def down(self, point): + """Set initial cursor window coordinates and pick constrain-axis.""" + self._vdown = arcball_map_to_sphere(point, self._center, self._radius) + self._qdown = self._qpre = self._qnow + + if self._constrain and self._axes is not None: + self._axis = arcball_nearest_axis(self._vdown, self._axes) + self._vdown = arcball_constrain_to_axis(self._vdown, self._axis) + else: + self._axis = None + + def drag(self, point): + """Update current cursor window coordinates.""" + vnow = arcball_map_to_sphere(point, self._center, self._radius) + + if self._axis is not None: + vnow = arcball_constrain_to_axis(vnow, self._axis) + + self._qpre = self._qnow + + t = numpy.cross(self._vdown, vnow) + if numpy.dot(t, t) < _EPS: + self._qnow = self._qdown + else: + q = [t[0], t[1], t[2], numpy.dot(self._vdown, vnow)] + self._qnow = quaternion_multiply(q, self._qdown) + + def next(self, acceleration=0.0): + """Continue rotation in direction of last drag.""" + q = quaternion_slerp(self._qpre, self._qnow, 2.0+acceleration, False) + self._qpre, self._qnow = self._qnow, q + + def matrix(self): + """Return homogeneous rotation matrix.""" + return quaternion_matrix(self._qnow) + + +def arcball_map_to_sphere(point, center, radius): + """Return unit sphere coordinates from window coordinates.""" + v = numpy.array(((point[0] - center[0]) / radius, + (center[1] - point[1]) / radius, + 0.0), dtype=numpy.float64) + n = v[0]*v[0] + v[1]*v[1] + if n > 1.0: + v /= math.sqrt(n) # position outside of sphere + else: + v[2] = math.sqrt(1.0 - n) + return v + + +def arcball_constrain_to_axis(point, axis): + """Return sphere point perpendicular to axis.""" + v = numpy.array(point, dtype=numpy.float64, copy=True) + a = numpy.array(axis, dtype=numpy.float64, copy=True) + v -= a * numpy.dot(a, v) # on plane + n = vector_norm(v) + if n > _EPS: + if v[2] < 0.0: + v *= -1.0 + v /= n + return v + if a[2] == 1.0: + return numpy.array([1, 0, 0], dtype=numpy.float64) + return unit_vector([-a[1], a[0], 0]) + + +def arcball_nearest_axis(point, axes): + """Return axis, which arc is nearest to point.""" + point = numpy.array(point, dtype=numpy.float64, copy=False) + nearest = None + mx = -1.0 + for axis in axes: + t = numpy.dot(arcball_constrain_to_axis(point, axis), point) + if t > mx: + nearest = axis + mx = t + return nearest + + +# epsilon for testing whether a number is close to zero +_EPS = numpy.finfo(float).eps * 4.0 + +# axis sequences for Euler angles +_NEXT_AXIS = [1, 2, 0, 1] + +# map axes strings to/from tuples of inner axis, parity, repetition, frame +_AXES2TUPLE = { + 'sxyz': (0, 0, 0, 0), 'sxyx': (0, 0, 1, 0), 'sxzy': (0, 1, 0, 0), + 'sxzx': (0, 1, 1, 0), 'syzx': (1, 0, 0, 0), 'syzy': (1, 0, 1, 0), + 'syxz': (1, 1, 0, 0), 'syxy': (1, 1, 1, 0), 'szxy': (2, 0, 0, 0), + 'szxz': (2, 0, 1, 0), 'szyx': (2, 1, 0, 0), 'szyz': (2, 1, 1, 0), + 'rzyx': (0, 0, 0, 1), 'rxyx': (0, 0, 1, 1), 'ryzx': (0, 1, 0, 1), + 'rxzx': (0, 1, 1, 1), 'rxzy': (1, 0, 0, 1), 'ryzy': (1, 0, 1, 1), + 'rzxy': (1, 1, 0, 1), 'ryxy': (1, 1, 1, 1), 'ryxz': (2, 0, 0, 1), + 'rzxz': (2, 0, 1, 1), 'rxyz': (2, 1, 0, 1), 'rzyz': (2, 1, 1, 1)} + +_TUPLE2AXES = dict((v, k) for k, v in _AXES2TUPLE.items()) + +# helper functions + +def vector_norm(data, axis=None, out=None): + """Return length, i.e. eucledian norm, of ndarray along axis. + + >>> v = numpy.random.random(3) + >>> n = vector_norm(v) + >>> numpy.allclose(n, numpy.linalg.norm(v)) + True + >>> v = numpy.random.rand(6, 5, 3) + >>> n = vector_norm(v, axis=-1) + >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=2))) + True + >>> n = vector_norm(v, axis=1) + >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1))) + True + >>> v = numpy.random.rand(5, 4, 3) + >>> n = numpy.empty((5, 3), dtype=numpy.float64) + >>> vector_norm(v, axis=1, out=n) + >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1))) + True + >>> vector_norm([]) + 0.0 + >>> vector_norm([1.0]) + 1.0 + + """ + data = numpy.array(data, dtype=numpy.float64, copy=True) + if out is None: + if data.ndim == 1: + return math.sqrt(numpy.dot(data, data)) + data *= data + out = numpy.atleast_1d(numpy.sum(data, axis=axis)) + numpy.sqrt(out, out) + return out + else: + data *= data + numpy.sum(data, axis=axis, out=out) + numpy.sqrt(out, out) + + +def unit_vector(data, axis=None, out=None): + """Return ndarray normalized by length, i.e. eucledian norm, along axis. + + >>> v0 = numpy.random.random(3) + >>> v1 = unit_vector(v0) + >>> numpy.allclose(v1, v0 / numpy.linalg.norm(v0)) + True + >>> v0 = numpy.random.rand(5, 4, 3) + >>> v1 = unit_vector(v0, axis=-1) + >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=2)), 2) + >>> numpy.allclose(v1, v2) + True + >>> v1 = unit_vector(v0, axis=1) + >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=1)), 1) + >>> numpy.allclose(v1, v2) + True + >>> v1 = numpy.empty((5, 4, 3), dtype=numpy.float64) + >>> unit_vector(v0, axis=1, out=v1) + >>> numpy.allclose(v1, v2) + True + >>> list(unit_vector([])) + [] + >>> list(unit_vector([1.0])) + [1.0] + + """ + if out is None: + data = numpy.array(data, dtype=numpy.float64, copy=True) + if data.ndim == 1: + data /= math.sqrt(numpy.dot(data, data)) + return data + else: + if out is not data: + out[:] = numpy.array(data, copy=False) + data = out + length = numpy.atleast_1d(numpy.sum(data*data, axis)) + numpy.sqrt(length, length) + if axis is not None: + length = numpy.expand_dims(length, axis) + data /= length + if out is None: + return data + + +def random_vector(size): + """Return array of random doubles in the half-open interval [0.0, 1.0). + + >>> v = random_vector(10000) + >>> numpy.all(v >= 0.0) and numpy.all(v < 1.0) + True + >>> v0 = random_vector(10) + >>> v1 = random_vector(10) + >>> numpy.any(v0 == v1) + False + + """ + return numpy.random.random(size) + + +def inverse_matrix(matrix): + """Return inverse of square transformation matrix. + + >>> M0 = random_rotation_matrix() + >>> M1 = inverse_matrix(M0.T) + >>> numpy.allclose(M1, numpy.linalg.inv(M0.T)) + True + >>> for size in range(1, 7): + ... M0 = numpy.random.rand(size, size) + ... M1 = inverse_matrix(M0) + ... if not numpy.allclose(M1, numpy.linalg.inv(M0)): print size + + """ + return numpy.linalg.inv(matrix) + + +def concatenate_matrices(*matrices): + """Return concatenation of series of transformation matrices. + + >>> M = numpy.random.rand(16).reshape((4, 4)) - 0.5 + >>> numpy.allclose(M, concatenate_matrices(M)) + True + >>> numpy.allclose(numpy.dot(M, M.T), concatenate_matrices(M, M.T)) + True + + """ + M = numpy.identity(4) + for i in matrices: + M = numpy.dot(M, i) + return M + + +def is_same_transform(matrix0, matrix1): + """Return True if two matrices perform same transformation. + + >>> is_same_transform(numpy.identity(4), numpy.identity(4)) + True + >>> is_same_transform(numpy.identity(4), random_rotation_matrix()) + False + + """ + matrix0 = numpy.array(matrix0, dtype=numpy.float64, copy=True) + matrix0 /= matrix0[3, 3] + matrix1 = numpy.array(matrix1, dtype=numpy.float64, copy=True) + matrix1 /= matrix1[3, 3] + return numpy.allclose(matrix0, matrix1) + + +def _import_module(module_name, warn=True, prefix='_py_', ignore='_'): + """Try import all public attributes from module into global namespace. + + Existing attributes with name clashes are renamed with prefix. + Attributes starting with underscore are ignored by default. + + Return True on successful import. + + """ + try: + module = __import__(module_name) + except ImportError: + if warn: + warnings.warn("Failed to import module " + module_name) + else: + for attr in dir(module): + if ignore and attr.startswith(ignore): + continue + if prefix: + if attr in globals(): + globals()[prefix + attr] = globals()[attr] + elif warn: + warnings.warn("No Python implementation of " + attr) + globals()[attr] = getattr(module, attr) + return True diff --git a/libs/assimp/port/PyAssimp/setup.py b/libs/assimp/port/PyAssimp/setup.py new file mode 100644 index 0000000..a3497d6 --- /dev/null +++ b/libs/assimp/port/PyAssimp/setup.py @@ -0,0 +1,26 @@ + #!/usr/bin/env python + # -*- coding: utf-8 -*- +import os +from distutils.core import setup + +def readme(): + with open('README.rst') as f: + return f.read() + +setup(name='pyassimp', + version='4.1.4', + license='ISC', + description='Python bindings for the Open Asset Import Library (ASSIMP)', + long_description=readme(), + url='https://github.com/assimp/assimp', + author='ASSIMP developers', + author_email='assimp-discussions@lists.sourceforge.net', + maintainer='Séverin Lemaignan', + maintainer_email='severin@guakamole.org', + packages=['pyassimp'], + data_files=[ + ('share/pyassimp', ['README.rst']), + ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')]) + ], + requires=['numpy'] + ) diff --git a/libs/assimp/port/assimp_rs/Cargo.lock b/libs/assimp/port/assimp_rs/Cargo.lock new file mode 100644 index 0000000..4f571f3 --- /dev/null +++ b/libs/assimp/port/assimp_rs/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "assimp_rs" +version = "0.1.0" + diff --git a/libs/assimp/port/assimp_rs/Cargo.toml b/libs/assimp/port/assimp_rs/Cargo.toml new file mode 100644 index 0000000..073a2b2 --- /dev/null +++ b/libs/assimp/port/assimp_rs/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "assimp_rs" +version = "0.1.0" +authors = ["David Golembiowski <dmgolembiowski@gmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/libs/assimp/port/assimp_rs/src/camera/mod.rs b/libs/assimp/port/assimp_rs/src/camera/mod.rs new file mode 100644 index 0000000..26ca118 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/camera/mod.rs @@ -0,0 +1 @@ +pub use self::structs::{Camera}; diff --git a/libs/assimp/port/assimp_rs/src/core/mod.rs b/libs/assimp/port/assimp_rs/src/core/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/core/mod.rs diff --git a/libs/assimp/port/assimp_rs/src/errors/mod.rs b/libs/assimp/port/assimp_rs/src/errors/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/errors/mod.rs diff --git a/libs/assimp/port/assimp_rs/src/formats/mod.rs b/libs/assimp/port/assimp_rs/src/formats/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/formats/mod.rs diff --git a/libs/assimp/port/assimp_rs/src/lib.rs b/libs/assimp/port/assimp_rs/src/lib.rs new file mode 100644 index 0000000..dbb6488 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/lib.rs @@ -0,0 +1,17 @@ +pub mod camera; +pub mod core; +pub mod errors; +pub mod formats; +pub mod material; +pub mod postprocess; +pub mod shims; +pub mod socket; +pub mod structs; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(true, true); + } +} diff --git a/libs/assimp/port/assimp_rs/src/material/mod.rs b/libs/assimp/port/assimp_rs/src/material/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/material/mod.rs diff --git a/libs/assimp/port/assimp_rs/src/postprocess/mod.rs b/libs/assimp/port/assimp_rs/src/postprocess/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/postprocess/mod.rs diff --git a/libs/assimp/port/assimp_rs/src/shims/mod.rs b/libs/assimp/port/assimp_rs/src/shims/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/shims/mod.rs diff --git a/libs/assimp/port/assimp_rs/src/socket/mod.rs b/libs/assimp/port/assimp_rs/src/socket/mod.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/socket/mod.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/anim/anim.rs b/libs/assimp/port/assimp_rs/src/structs/anim/anim.rs new file mode 100644 index 0000000..5374151 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/anim/anim.rs @@ -0,0 +1,44 @@ +pub struct Animation<'mA, 'mMA, 'nA> { + /* The name of the animation. If the modeling package this data was + * exported from does support only a single animation channel, this + * name is usually empty (length is zero). + */ + m_name: Option<String>, + // Duration of the animation in ticks + m_duration: f64, + // Ticks per second. Zero (0.000... ticks/second) if not + // specified in the imported file + m_ticks_per_second: Option<f64>, + /* Number of bone animation channels. + Each channel affects a single node. + */ + m_num_channels: u64, + /* Node animation channels. Each channel + affects a single node. + ?? -> The array is m_num_channels in size. + (maybe refine to a derivative type of usize?) + */ + m_channels: &'nA NodeAnim, + /* Number of mesh animation channels. Each + channel affects a single mesh and defines + vertex-based animation. + */ + m_num_mesh_channels: u64, + /* The mesh animation channels. Each channel + affects a single mesh. + The array is m_num_mesh_channels in size + (maybe refine to a derivative of usize?) + */ + m_mesh_channels: &'mA MeshAnim, + /* The number of mesh animation channels. Each channel + affects a single mesh and defines some morphing animation. + */ + m_num_morph_mesh_channels: u64, + /* The morph mesh animation channels. Each channel affects a single mesh. + The array is mNumMorphMeshChannels in size. + */ + m_morph_mesh_channels: &'mMA MeshMorphAnim +} +pub struct NodeAnim {} +pub struct MeshAnim {} +pub struct MeshMorphAnim {} diff --git a/libs/assimp/port/assimp_rs/src/structs/anim/mod.rs b/libs/assimp/port/assimp_rs/src/structs/anim/mod.rs new file mode 100644 index 0000000..a0d4b7d --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/anim/mod.rs @@ -0,0 +1,6 @@ +mod anim; +pub use self::anim::{ + Animation, + NodeAnim, + MeshAnim, + MeshMorphAnim}; diff --git a/libs/assimp/port/assimp_rs/src/structs/blob/blob.rs b/libs/assimp/port/assimp_rs/src/structs/blob/blob.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/blob/blob.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/blob/mod.rs b/libs/assimp/port/assimp_rs/src/structs/blob/mod.rs new file mode 100644 index 0000000..ad7612c --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/blob/mod.rs @@ -0,0 +1,2 @@ +mod blob; + diff --git a/libs/assimp/port/assimp_rs/src/structs/bone/bone.rs b/libs/assimp/port/assimp_rs/src/structs/bone/bone.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/bone/bone.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/bone/mod.rs b/libs/assimp/port/assimp_rs/src/structs/bone/mod.rs new file mode 100644 index 0000000..758a15a --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/bone/mod.rs @@ -0,0 +1,2 @@ +mod bone; + diff --git a/libs/assimp/port/assimp_rs/src/structs/camera/camera.rs b/libs/assimp/port/assimp_rs/src/structs/camera/camera.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/camera/camera.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/camera/mod.rs b/libs/assimp/port/assimp_rs/src/structs/camera/mod.rs new file mode 100644 index 0000000..d4d79d0 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/camera/mod.rs @@ -0,0 +1,2 @@ +mod camera; + diff --git a/libs/assimp/port/assimp_rs/src/structs/color/color.rs b/libs/assimp/port/assimp_rs/src/structs/color/color.rs new file mode 100644 index 0000000..0b5fc64 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/color/color.rs @@ -0,0 +1,27 @@ +#[derive(Clone, Debug, Copy)] +struct Color3D { + r: f32, + g: f32, + b: f32 +} + +impl Color3D { + pub fn new(r_f32: f32, g_f32: f32, b_f32: f32) -> Color3D { + Color3D {r: r_f32, g: g_f32, b: b_f32 } + } +} + +#[derive(Clone, Debug, Copy)] +struct Color4D { + r: f32, + g: f32, + b: f32, + a: f32 +} + +impl Color4D { + pub fn new(r_f32: f32, g_f32: f32, b_f32: f32, a_f32: f32) -> Color4D { + Color4D {r: r_f32, g: g_f32, b: b_f32, a: a_f32 } + } +} + diff --git a/libs/assimp/port/assimp_rs/src/structs/color/mod.rs b/libs/assimp/port/assimp_rs/src/structs/color/mod.rs new file mode 100644 index 0000000..d88527e --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/color/mod.rs @@ -0,0 +1,5 @@ +mod color; +pub use self::color::{ + Color3D, + Color4D +}; diff --git a/libs/assimp/port/assimp_rs/src/structs/face/face.rs b/libs/assimp/port/assimp_rs/src/structs/face/face.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/face/face.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/face/mod.rs b/libs/assimp/port/assimp_rs/src/structs/face/mod.rs new file mode 100644 index 0000000..ae5aa5b --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/face/mod.rs @@ -0,0 +1,2 @@ +mod face; + diff --git a/libs/assimp/port/assimp_rs/src/structs/key/key.rs b/libs/assimp/port/assimp_rs/src/structs/key/key.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/key/key.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/key/mod.rs b/libs/assimp/port/assimp_rs/src/structs/key/mod.rs new file mode 100644 index 0000000..b23779d --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/key/mod.rs @@ -0,0 +1,2 @@ +mod key; + diff --git a/libs/assimp/port/assimp_rs/src/structs/light/light.rs b/libs/assimp/port/assimp_rs/src/structs/light/light.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/light/light.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/light/mod.rs b/libs/assimp/port/assimp_rs/src/structs/light/mod.rs new file mode 100644 index 0000000..a68b519 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/light/mod.rs @@ -0,0 +1,2 @@ +mod light; + diff --git a/libs/assimp/port/assimp_rs/src/structs/material/material.rs b/libs/assimp/port/assimp_rs/src/structs/material/material.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/material/material.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/material/mod.rs b/libs/assimp/port/assimp_rs/src/structs/material/mod.rs new file mode 100644 index 0000000..54de8b3 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/material/mod.rs @@ -0,0 +1,2 @@ +mod material; + diff --git a/libs/assimp/port/assimp_rs/src/structs/matrix/matrix.rs b/libs/assimp/port/assimp_rs/src/structs/matrix/matrix.rs new file mode 100644 index 0000000..4673b2d --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/matrix/matrix.rs @@ -0,0 +1,64 @@ +#[derive(Clone, Debug, Copy)] +struct Matrix3x3 { + a1: f32, + a2: f32, + a3: f32, + b1: f32, + b2: f32, + b3: f32, + c1: f32, + c2: f32, + c3: f32 +} + +#[derive(Clone, Debug, Copy)] +struct Matrix4x4 { + a1: f32, + a2: f32, + a3: f32, + a4: f32, + b1: f32, + b2: f32, + b3: f32, + b4: f32, + c1: f32, + c2: f32, + c3: f32, + c4: f32, + d1: f32, + d2: f32, + d3: f32, + d4: f32 +} + +impl Matrix3x3 { + pub fn new( + a1_f32: f32, a2_f32: f32, a3_f32: f32, + b1_f32: f32, b2_f32: f32, b3_f32: f32, + c1_f32: f32, c2_f32: f32, c3_f32: f32 + ) -> Matrix3x3 { + Matrix3x3 { + a1: a1_f32, a2: a2_f32, a3: a3_f32, + b1: b1_f32, b2: b2_f32, b3: b3_f32, + c1: c1_f32, c2: c2_f32, c3: c3_f32 + } + } +} + +impl Matrix4x4 { + pub fn new( + a1_f32: f32, a2_f32: f32, a3_f32: f32, a4_f32: f32, + b1_f32: f32, b2_f32: f32, b3_f32: f32, b4_f32: f32, + c1_f32: f32, c2_f32: f32, c3_f32: f32, c4_f32: f32, + d1_f32: f32, d2_f32: f32, d3_f32: f32, d4_f32: f32 + ) -> Matrix4x4 { + Matrix4x4 { + a1: a1_f32, a2: a2_f32, a3: a3_f32, a4: a4_f32, + b1: b1_f32, b2: b2_f32, b3: b3_f32, b4: b4_f32, + c1: c1_f32, c2: c2_f32, c3: c3_f32, c4: c4_f32, + d1: d1_f32, d2: d2_f32, d3: d3_f32, d4: d4_f32 + } + } +} + + diff --git a/libs/assimp/port/assimp_rs/src/structs/matrix/mod.rs b/libs/assimp/port/assimp_rs/src/structs/matrix/mod.rs new file mode 100644 index 0000000..b0fb1e1 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/matrix/mod.rs @@ -0,0 +1,4 @@ +mod matrix; +pub use self::matrix::{ + Matrix3x3, + Matrix4x4}; diff --git a/libs/assimp/port/assimp_rs/src/structs/memory/memory.rs b/libs/assimp/port/assimp_rs/src/structs/memory/memory.rs new file mode 100644 index 0000000..c076f17 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/memory/memory.rs @@ -0,0 +1,35 @@ +#[derive(Clone, Debug, Copy)] +struct MemoryInfo { + textures: u32, + materials: u32, + meshes: u32, + nodes: u32, + animations: u32, + cameras: u32, + lights: u32, + total: u32 +} + +impl MemoryInfo { + pub fn new( + textures_uint: u32, + materials_uint: u32, + meshes_uint: u32, + nodes_uint: u32, + animations_uint: u32, + cameras_uint: u32, + lights_uint: u32, + total_uint: u32) -> MemoryInfo { + + MemoryInfo { + textures: textures_uint, + materials: materials_uint, + meshes: meshes_uint, + nodes: nodes_uint, + animations: animations_uint, + cameras: cameras_uint, + lights: lights_uint, + total: total_uint + } + } +} diff --git a/libs/assimp/port/assimp_rs/src/structs/memory/mod.rs b/libs/assimp/port/assimp_rs/src/structs/memory/mod.rs new file mode 100644 index 0000000..8c8c31c --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/memory/mod.rs @@ -0,0 +1,2 @@ +mod memory; +pub use self::memory::MemoryInfo; diff --git a/libs/assimp/port/assimp_rs/src/structs/mesh/mesh.rs b/libs/assimp/port/assimp_rs/src/structs/mesh/mesh.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/mesh/mesh.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/mesh/mod.rs b/libs/assimp/port/assimp_rs/src/structs/mesh/mod.rs new file mode 100644 index 0000000..1c3ef65 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/mesh/mod.rs @@ -0,0 +1,3 @@ +mod mesh; + + diff --git a/libs/assimp/port/assimp_rs/src/structs/meta/meta.rs b/libs/assimp/port/assimp_rs/src/structs/meta/meta.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/meta/meta.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/meta/mod.rs b/libs/assimp/port/assimp_rs/src/structs/meta/mod.rs new file mode 100644 index 0000000..0452947 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/meta/mod.rs @@ -0,0 +1,2 @@ +mod meta; + diff --git a/libs/assimp/port/assimp_rs/src/structs/mod.rs b/libs/assimp/port/assimp_rs/src/structs/mod.rs new file mode 100644 index 0000000..fd90876 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/mod.rs @@ -0,0 +1,61 @@ +mod anim; +/* Animation + * NodeAnim + * MeshAnim + * MeshMorphAnim + */ +mod blob; +/* ExportDataBlob + */ +mod vec; +/* Vector2d + * Vector3d + * */ +mod matrix; +/* Matrix3by3 + * Matrix4by4 + */ +mod camera; +/* Camera */ +mod color; +/* Color3d + * Color4d + */ +mod key; +/* MeshKey + * MeshMorphKey + * QuatKey + * VectorKey + */ +mod texel; +mod plane; +mod string; +/* String + */ +mod material; +/* Material + * MaterialPropery + * MaterialPropertyString + */ +mod mem; +mod quaternion; +mod face; +mod vertex_weight; +mod mesh; +/* Mesh + */ +mod meta; +/* Metadata + * MetadataEntry + */ +mod node; +/* Node + * */ +mod light; +mod texture; +mod ray; +mod transform; +/* UVTransform */ +mod bone; +mod scene; +/* Scene */ diff --git a/libs/assimp/port/assimp_rs/src/structs/node/mod.rs b/libs/assimp/port/assimp_rs/src/structs/node/mod.rs new file mode 100644 index 0000000..c1fc34c --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/node/mod.rs @@ -0,0 +1,2 @@ +mod node; + diff --git a/libs/assimp/port/assimp_rs/src/structs/node/node.rs b/libs/assimp/port/assimp_rs/src/structs/node/node.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/node/node.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/plane/mod.rs b/libs/assimp/port/assimp_rs/src/structs/plane/mod.rs new file mode 100644 index 0000000..c73a8ed --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/plane/mod.rs @@ -0,0 +1,2 @@ +mod plane; + diff --git a/libs/assimp/port/assimp_rs/src/structs/plane/plane.rs b/libs/assimp/port/assimp_rs/src/structs/plane/plane.rs new file mode 100644 index 0000000..2b0b744 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/plane/plane.rs @@ -0,0 +1,23 @@ +#[derive(Clone, Debug, Copy)] +struct Plane { + a: f32, + b: f32, + c: f32, + d: f32 +} + +impl Plane { + pub fn new( + a_f32: f32, + b_f32: f32, + c_f32: f32, + d_f32: f32 + ) -> Plane { + Plane { + a: a_f32, + b: b_f32, + c: b_f32, + d: d_f32 + } + } +} diff --git a/libs/assimp/port/assimp_rs/src/structs/quaternion/mod.rs b/libs/assimp/port/assimp_rs/src/structs/quaternion/mod.rs new file mode 100644 index 0000000..bb2c061 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/quaternion/mod.rs @@ -0,0 +1,3 @@ +mod quaternion; + +pub use self::quaternion::Quaternion; diff --git a/libs/assimp/port/assimp_rs/src/structs/quaternion/quaternion.rs b/libs/assimp/port/assimp_rs/src/structs/quaternion/quaternion.rs new file mode 100644 index 0000000..970f5cc --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/quaternion/quaternion.rs @@ -0,0 +1,7 @@ +use crate::vec; + +#[derive(Clone, Debug, Copy)] +pub struct Quaternion { + _coordinates: vec::Vector4d + +} diff --git a/libs/assimp/port/assimp_rs/src/structs/ray/mod.rs b/libs/assimp/port/assimp_rs/src/structs/ray/mod.rs new file mode 100644 index 0000000..7f0be07 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/ray/mod.rs @@ -0,0 +1,2 @@ +mod ray; + diff --git a/libs/assimp/port/assimp_rs/src/structs/ray/ray.rs b/libs/assimp/port/assimp_rs/src/structs/ray/ray.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/ray/ray.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/scene/mod.rs b/libs/assimp/port/assimp_rs/src/structs/scene/mod.rs new file mode 100644 index 0000000..5aea638 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/scene/mod.rs @@ -0,0 +1,2 @@ +mod scene; + diff --git a/libs/assimp/port/assimp_rs/src/structs/scene/scene.rs b/libs/assimp/port/assimp_rs/src/structs/scene/scene.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/scene/scene.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/string/mod.rs b/libs/assimp/port/assimp_rs/src/structs/string/mod.rs new file mode 100644 index 0000000..f599ba7 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/string/mod.rs @@ -0,0 +1,3 @@ +mod string; +pub use self::string::MAXLEN; +pub use self::string::Str; diff --git a/libs/assimp/port/assimp_rs/src/structs/string/string.rs b/libs/assimp/port/assimp_rs/src/structs/string/string.rs new file mode 100644 index 0000000..b88457d --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/string/string.rs @@ -0,0 +1,41 @@ +pub const MAXLEN: usize = 1024; + +/// Want to consider replacing `Vec<char>` +/// with a comparable definition at +/// https://doc.rust-lang.org/src/alloc/string.rs.html#415-417 +#[derive(Clone, Debug)] +struct Str { + length: usize, + data: Vec<char> +} + +impl Str { + pub fn new(len_u32: usize, data_string: String) -> Str { + Str { + length: len_u32, + data: data_string.chars().collect() + } + } +} + +/// MaterialPropertyStr +/// The size of length is truncated to 4 bytes on a 64-bit platform when used as a +/// material property (see MaterialSystem.cpp, as aiMaterial::AddProperty() ). +#[derive(Clone, Debug)] +struct MaterialPropertyStr { + length: usize, + data: Vec<char> +} + + +impl MaterialPropertyStr { + pub fn new(len_u32: usize, data_string: String) -> MaterialPropertyStr { + MaterialPropertyStr { + length: len_u32, + data: data_string.chars().collect() + } + } +} + + + diff --git a/libs/assimp/port/assimp_rs/src/structs/texture/mod.rs b/libs/assimp/port/assimp_rs/src/structs/texture/mod.rs new file mode 100644 index 0000000..1b5c930 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/texture/mod.rs @@ -0,0 +1,3 @@ +mod texture; +pub use self::texture::Texel; + diff --git a/libs/assimp/port/assimp_rs/src/structs/texture/texture.rs b/libs/assimp/port/assimp_rs/src/structs/texture/texture.rs new file mode 100644 index 0000000..b2c72f3 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/texture/texture.rs @@ -0,0 +1,19 @@ +#[derive(Clone, Debug, Copy)] +struct Texel { + b: u32, + g: u32, + r: u32, + a: u32 +} + +impl Texel { + pub fn new(b_u32: u32, g_u32: u32, + r_u32: u32, a_u32: u32) -> Texel { + Texel { + b: b_u32, + g: g_u32, + r: r_u32, + a: a_u32 + } + } +} diff --git a/libs/assimp/port/assimp_rs/src/structs/transform/mod.rs b/libs/assimp/port/assimp_rs/src/structs/transform/mod.rs new file mode 100644 index 0000000..b80c43d --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/transform/mod.rs @@ -0,0 +1,2 @@ +mod transform; + diff --git a/libs/assimp/port/assimp_rs/src/structs/transform/transform.rs b/libs/assimp/port/assimp_rs/src/structs/transform/transform.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/transform/transform.rs diff --git a/libs/assimp/port/assimp_rs/src/structs/vec/mod.rs b/libs/assimp/port/assimp_rs/src/structs/vec/mod.rs new file mode 100644 index 0000000..3613d5d --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/vec/mod.rs @@ -0,0 +1,2 @@ +mod vec; + diff --git a/libs/assimp/port/assimp_rs/src/structs/vec/vec.rs b/libs/assimp/port/assimp_rs/src/structs/vec/vec.rs new file mode 100644 index 0000000..ee0d194 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/vec/vec.rs @@ -0,0 +1,48 @@ +struct Vector2d { + x: f32, + y: f32 +} + +struct Vector3d { + x: f32, + y: f32, + z: f32 +} + +struct Vector4d { + x: f32, + y: f32, + z: f32, + w: f32 +} + +impl Vector2d { + pub fn new(x_f32: f32, y_f32: f32) -> Vector2d { + Vector2d { + x: x_f32, + y: y_f32 + } + } +} + +impl Vector3d { + pub fn new(x_f32: f32, y_f32: f32, z_f32: f32) -> Vector3d { + Vector3d { + x: x_f32, + y: y_f32, + z: z_f32 + } + } +} + +impl Vector4d { + pub fn new(x_f32: f32, y_f32: f32, z_f32: f32, w_f32: f32) -> Vector4d { + Vector4d { + x: x_f32, + y: y_f32, + z: z_f32, + w: w_f32 + } + } +} + diff --git a/libs/assimp/port/assimp_rs/src/structs/vertex/mod.rs b/libs/assimp/port/assimp_rs/src/structs/vertex/mod.rs new file mode 100644 index 0000000..97ae3ec --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/vertex/mod.rs @@ -0,0 +1,2 @@ +mod vertex; +// pub use self::vertex:: diff --git a/libs/assimp/port/assimp_rs/src/structs/vertex/vertex.rs b/libs/assimp/port/assimp_rs/src/structs/vertex/vertex.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/assimp/port/assimp_rs/src/structs/vertex/vertex.rs diff --git a/libs/assimp/port/dAssimp/README b/libs/assimp/port/dAssimp/README new file mode 100644 index 0000000..af82cb1 --- /dev/null +++ b/libs/assimp/port/dAssimp/README @@ -0,0 +1,13 @@ +D bindings for the Assimp library (http://assimp.sf.net). +--- + +These bindings provide access to Assimp's C API. They were directly created +from the C header files. + +You should be able to create sufficient DDoc documentation for the bindings +using your favourite build tool (such as Rebuild). Please refer to the main +(Doxygen-generated) documentation for general topics. + +Please note that the bindings have only been tested on 32 bit systems, they have +yet to be adapted for the different size of the integer types in 64 bit builds +of Assimp. diff --git a/libs/assimp/port/dAssimp/assimp/animation.d b/libs/assimp/port/dAssimp/assimp/animation.d new file mode 100644 index 0000000..9a36940 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/animation.d @@ -0,0 +1,240 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * The data structures which are used to store the imported animation data. + */ +module assimp.animation; + +import assimp.math; +import assimp.types; + +extern ( C ) { + /** + * A time-value pair specifying a certain 3D vector for the given time. + */ + struct aiVectorKey { + /** + * The time of this key. + */ + double mTime; + + /** + * The value of this key. + */ + aiVector3D mValue; + } + + /** + * A time-value pair specifying a rotation for the given time. For joint + * animations, the rotation is usually expressed using a quaternion. + */ + struct aiQuatKey { + /** + * The time of this key. + */ + double mTime; + + /** + * The value of this key. + */ + aiQuaternion mValue; + } + + /** + * Defines how an animation channel behaves outside the defined time + * range. This corresponds to <code>aiNodeAnim.mPreState</code> and + * <code>aiNodeAnim.mPostState</code>. + */ + enum aiAnimBehaviour : uint { + /** + * The value from the default node transformation is used. + */ + DEFAULT = 0x0, + + /** + * The nearest key value is used without interpolation. + */ + CONSTANT = 0x1, + + /** + * The value of the nearest two keys is linearly extrapolated for the + * current time value. + */ + LINEAR = 0x2, + + /** + * The animation is repeated. + * + * If the animation key go from n to m and the current time is t, use the + * value at (t-n) % (|m-n|). + */ + REPEAT = 0x3 + } + + /** + * Describes the animation of a single node. + * + * The name specifies the bone/node which is affected by this animation + * channel. The keyframes are given in three separate series of values, one + * each for position, rotation and scaling. The transformation matrix + * computed from these values replaces the node's original transformation + * matrix at a specific time. This means all keys are absolute and not + * relative to the bone default pose. + * + * The order in which the transformations are applied is – + * as usual – scaling, rotation, translation. + * + * Note: All keys are returned in their correct, chronological order. + * Duplicate keys don't pass the validation step. Most likely there will + * be no negative time values, but they are not forbidden (so + * implementations need to cope with them!). + */ + struct aiNodeAnim { + /** + * The name of the node affected by this animation. The node must exist + * and it must be unique. + */ + aiString mNodeName; + + /** + * The number of position keys. + */ + uint mNumPositionKeys; + + /** + * The position keys of this animation channel. Positions are specified + * as 3D vectors. The array is <code>mNumPositionKeys</code> in size. + * + * If there are position keys, there will also be at least one scaling + * and one rotation key. + */ + aiVectorKey* mPositionKeys; + + /** + * The number of rotation keys. + */ + uint mNumRotationKeys; + + /** + * The rotation keys of this animation channel. Rotations are given as + * quaternions. The array is <code>mNumRotationKeys</code> in size. + * + * If there are rotation keys, there will also be at least one scaling + * and one position key. + */ + aiQuatKey* mRotationKeys; + + + /** + * The number of scaling keys. + */ + uint mNumScalingKeys; + + /** + * The scaling keys of this animation channel. Scalings are specified as + * 3D vectors. The array is <code>mNumScalingKeys</code> in size. + * + * If there are scaling keys, there will also be at least one position + * and one rotation key. + */ + aiVectorKey* mScalingKeys; + + + /** + * Defines how the animation behaves before the first key is encountered. + * + * The default value is <code>aiAnimBehaviour.DEFAULT</code> (the original + * transformation matrix of the affected node is used). + */ + aiAnimBehaviour mPreState; + + /** + * Defines how the animation behaves after the last key was processed. + * + * The default value is <code>aiAnimBehaviour.DEFAULT</code> (the original + * transformation matrix of the affected node is used). + */ + aiAnimBehaviour mPostState; + } + + /** + * An animation consists of keyframe data for a number of nodes. + * + * For each node affected by the animation, a separate series of data is + * given. + */ + struct aiAnimation { + /** + * The name of the animation. + * + * If the modeling package this data was + * exported from does support only a single animation channel, this + * name is usually empty (length is zero). + */ + aiString mName; + + /** + * Duration of the animation in ticks. + */ + double mDuration; + + /** + * Ticks per second. 0 if not specified in the imported file. + */ + double mTicksPerSecond; + + /** + * The number of bone animation channels. + * + * Each channel affects a single node. + */ + uint mNumChannels; + + /** + * The node animation channels. The array is <code>mNumChannels</code> + * in size. + * + * Each channel affects a single node. + */ + aiNodeAnim** mChannels; + } +}
\ No newline at end of file diff --git a/libs/assimp/port/dAssimp/assimp/api.d b/libs/assimp/port/dAssimp/assimp/api.d new file mode 100644 index 0000000..bc7a157 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/api.d @@ -0,0 +1,686 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * The C-style interface to the Open Asset import library. + * + * All functions of the C API have been collected in this module as function + * pointers, which are set by the dynamic library loader + * (<code>assimp.loader</code>). + */ +module assimp.api; + +import assimp.fileIO; +import assimp.material; +import assimp.math; +import assimp.scene; +import assimp.types; + +extern ( C ) { + /** + * Reads the given file and returns its content. + * + * If the call succeeds, the imported data is returned in an <code>aiScene</code> + * structure. The data is intended to be read-only, it stays property of the + * Assimp library and will be stable until <code>aiReleaseImport()</code> is + * called. After you're done with it, call <code>aiReleaseImport()</code> to + * free the resources associated with this file. + * + * If an error is encountered, null is returned instead. Call + * <code>aiGetErrorString()</code> to retrieve a human-readable error + * description. + * + * Params: + * pFile = Path and filename of the file to be imported, + * expected to be a null-terminated C-string. null is not a valid value. + * pFlags = Optional post processing steps to be executed after a + * successful import. Provide a bitwise combination of the + * <code>aiPostProcessSteps</code> flags. If you wish to inspect the + * imported scene first in order to fine-tune your post-processing + * setup, consider to use <code>aiApplyPostProcessing()</code>. + * + * Returns: + * A pointer to the imported data, null if the import failed. + */ + aiScene* function( char* pFile, uint pFile ) aiImportFile; + + /** + * Reads the given file using user-defined I/O functions and returns its + * content. + * + * If the call succeeds, the imported data is returned in an <code>aiScene</code> + * structure. The data is intended to be read-only, it stays property of the + * Assimp library and will be stable until <code>aiReleaseImport()</code> is + * called. After you're done with it, call <code>aiReleaseImport()</code> to + * free the resources associated with this file. + * + * If an error is encountered, null is returned instead. Call + * <code>aiGetErrorString()</code> to retrieve a human-readable error + * description. + * + * Params: + * pFile = Path and filename of the file to be imported, + * expected to be a null-terminated C-string. null is not a valid value. + * pFlags = Optional post processing steps to be executed after a + * successful import. Provide a bitwise combination of the + * <code>aiPostProcessSteps</code> flags. If you wish to inspect the + * imported scene first in order to fine-tune your post-processing + * setup, consider to use <code>aiApplyPostProcessing()</code>. + * pFS = An aiFileIO which will be used to open the model file itself + * and any other files the loader needs to open. + * + * Returns: + * A pointer to the imported data, null if the import failed. + */ + aiScene* function( char* pFile, uint pFlags, aiFileIO* pFS ) aiImportFileEx; + + /** + * Reads the scene from the given memory buffer. + * + * Reads the given file using user-defined I/O functions and returns its + * content. + * + * If the call succeeds, the imported data is returned in an <code>aiScene</code> + * structure. The data is intended to be read-only, it stays property of the + * Assimp library and will be stable until <code>aiReleaseImport()</code> is + * called. After you're done with it, call <code>aiReleaseImport()</code> to + * free the resources associated with this file. + * + * If an error is encountered, null is returned instead. Call + * <code>aiGetErrorString()</code> to retrieve a human-readable error + * description. + * + * Params: + * pBuffer = Pointer to the scene data. + * pLength = Size of pBuffer in bytes. + * pFlags = Optional post processing steps to be executed after a + * successful import. Provide a bitwise combination of the + * <code>aiPostProcessSteps</code> flags. If you wish to inspect the + * imported scene first in order to fine-tune your post-processing + * setup, consider to use <code>aiApplyPostProcessing()</code>. + * pHint = An additional hint to the library. If this is a non empty + * string, the library looks for a loader to support the file + * extension specified and passes the file to the first matching + * loader. If this loader is unable to complete the request, the + * library continues and tries to determine the file format on its + * own, a task that may or may not be successful. + * + * Returns: + * A pointer to the imported data, null if the import failed. + * + * Note: + * This is a straightforward way to decode models from memory buffers, + * but it doesn't handle model formats spreading their data across + * multiple files or even directories. Examples include OBJ or MD3, which + * outsource parts of their material stuff into external scripts. If you + * need the full functionality, provide a custom IOSystem to make Assimp + * find these files. + */ + aiScene* function( + char* pBuffer, + uint pLength, + uint pFlags, + char* pHint + ) aiImportFileFromMemory; + + /** + * Apply post-processing to an already-imported scene. + * + * This is strictly equivalent to calling <code>aiImportFile()</code> or + * <code>aiImportFileEx()</code> with the same flags. However, you can use + * this separate function to inspect the imported scene first to fine-tune + * your post-processing setup. + * + * Params: + * pScene = Scene to work on. + * pFlags = Provide a bitwise combination of the + * <code>aiPostProcessSteps</code> flags. + * + * Returns: + * A pointer to the post-processed data. Post processing is done in-place, + * meaning this is still the same <code>aiScene</code> which you passed + * for pScene. However, if post-processing failed, the scene could now be + * null. That's quite a rare case, post processing steps are not really + * designed to fail. To be exact, <code>aiProcess.ValidateDS</code> is + * currently the only post processing step which can actually cause the + * scene to be reset to null. + */ + aiScene* function( aiScene* pScene, uint pFlags ) aiApplyPostProcessing; + + /** + * Get one of the predefined log streams. This is the quick'n'easy solution + * to access Assimp's log system. Attaching a log stream can slightly reduce + * Assimp's overall import performance. + * + * Examples: + * --- + * aiLogStream stream = aiGetPredefinedLogStream( + * aiDefaultLogStream.FILE, "assimp.log.txt" ); + * if ( stream.callback !is null ) { + * aiAttachLogStream( &stream ); + * } + * --- + * + * Params: + * pStreams = The log stream destination. + * file = Solely for the <code>aiDefaultLogStream.FILE</code> flag: + * specifies the file to write to. Pass null for all other flags. + * + * Returns: + * The log stream, null if something went wrong. + */ + aiLogStream function( aiDefaultLogStream pStreams, char* file ) aiGetPredefinedLogStream; + + /** + * Attach a custom log stream to the libraries' logging system. + * + * Attaching a log stream can slightly reduce Assimp's overall import + * performance. Multiple log-streams can be attached. + * + * Params: + * stream = Describes the new log stream. + * + * Note: To ensure proper destruction of the logging system, you need to + * manually call <code>aiDetachLogStream()</code> on every single log + * stream you attach. Alternatively, <code>aiDetachAllLogStreams()</code> + * is provided. + */ + void function( aiLogStream* stream ) aiAttachLogStream; + + /** + * Enable verbose logging. + * + * Verbose logging includes debug-related stuff and detailed import + * statistics. This can have severe impact on import performance and memory + * consumption. However, it might be useful to find out why a file is not + * read correctly. + * + * Param: + * d = Whether verbose logging should be enabled. + */ + void function( aiBool d ) aiEnableVerboseLogging; + + /** + * Detach a custom log stream from the libraries' logging system. + * + * This is the counterpart of #aiAttachPredefinedLogStream. If you attached a stream, + * don't forget to detach it again. + * + * Params: + * stream = The log stream to be detached. + * + * Returns: + * <code>aiReturn.SUCCESS</code> if the log stream has been detached + * successfully. + * + * See: <code>aiDetachAllLogStreams</code> + */ + aiReturn function( aiLogStream* stream ) aiDetachLogStream; + + /** + * Detach all active log streams from the libraries' logging system. + * + * This ensures that the logging system is terminated properly and all + * resources allocated by it are actually freed. If you attached a stream, + * don't forget to detach it again. + * + * See: <code>aiAttachLogStream</code>, <code>aiDetachLogStream</code> + */ + void function() aiDetachAllLogStreams; + + /** + * Releases all resources associated with the given import process. + * + * Call this function after you're done with the imported data. + * + * Params: + * pScene = The imported data to release. null is a valid value. + */ + void function( aiScene* pScene ) aiReleaseImport; + + /** + * Returns the error text of the last failed import process. + * + * Returns: + * A textual description of the error that occurred at the last importing + * process. null if there was no error. There can't be an error if you + * got a non-null <code>aiScene</code> from + * <code>aiImportFile()/aiImportFileEx()/aiApplyPostProcessing()</code>. + */ + char* function() aiGetErrorString; + + /** + * Returns whether a given file extension is supported by this Assimp build. + * + * Params: + * szExtension = Extension for which to query support. Must include a + * leading dot '.'. Example: ".3ds", ".md3" + * + * Returns: + * <code>TRUE</code> if the file extension is supported. + */ + aiBool function( char* szExtension ) aiIsExtensionSupported; + + /** + * Gets a list of all file extensions supported by ASSIMP. + * + * Format of the list: "*.3ds;*.obj;*.dae". + * + * If a file extension is contained in the list this does, of course, not + * mean that Assimp is able to load all files with this extension. + * + * Params: + * szOut = String to receive the extension list. null is not a valid + * parameter. + */ + void function( aiString* szOut ) aiGetExtensionList; + + /** + * Gets the storage required by an imported asset + * + * Params: + * pIn = Asset to query storage size for. + * info = Data structure to be filled. + */ + void function( aiScene* pIn, aiMemoryInfo* info ) aiGetMemoryRequirements; + + /** + * Sets an integer property. + * + * Properties are always shared by all imports. It is not possible to + * specify them per import. + * + * Params: + * szName = Name of the configuration property to be set. All supported + * public properties are defined in the <code>config</code> module. + * value = New value for the property. + */ + void function( char* szName, int value ) aiSetImportPropertyInteger; + + /** + * Sets a floating-point property. + * + * Properties are always shared by all imports. It is not possible to + * specify them per import. + * + * Params: + * szName = Name of the configuration property to be set. All supported + * public properties are defined in the <code>config</code> module. + * value = New value for the property. + */ + void function( char* szName, float value ) aiSetImportPropertyFloat; + + /** + * Sets a string property. + * + * Properties are always shared by all imports. It is not possible to + * specify them per import. + * + * Params: + * szName = Name of the configuration property to be set. All supported + * public properties are defined in the <code>config</code> module. + * st = New value for the property. + */ + void function( char* szName, aiString* st ) aiSetImportPropertyString; + + + /* + * Mathematical helper functions. + */ + + /** + * Constructs a quaternion from a 3x3 rotation matrix. + * + * Params: + * quat = Receives the output quaternion. + * mat = Matrix to 'quaternionize'. + */ + void function( aiQuaternion* quat, aiMatrix3x3* mat ) aiCreateQuaternionFromMatrix; + + /** + * Decomposes a transformation matrix into its rotational, translational and + * scaling components. + * + * Params: + * mat = Matrix to decompose. + * scaling = Receives the scaling component. + * rotation = Receives the rotational component. + * position = Receives the translational component. + */ + void function( + aiMatrix4x4* mat, + aiVector3D* scaling, + aiQuaternion* rotation, + aiVector3D* position + ) aiDecomposeMatrix; + + /** + * Transposes a 4x4 matrix (in-place). + * + * Params: + * mat = The matrix to be transposed. + */ + void function( aiMatrix4x4* mat ) aiTransposeMatrix4; + + /** + * Transposes a 3x3 matrix (in-place). + * + * Params: + * mat = The matrix to be transposed. + */ + void function( aiMatrix3x3* mat ) aiTransposeMatrix3; + + /** + * Transforms a vector by a 3x3 matrix (in-place). + * + * Params: + * vec = Vector to be transformed. + * mat = Matrix to transform the vector with. + */ + void function( aiVector3D* vec, aiMatrix3x3* mat ) aiTransformVecByMatrix3; + + /** + * Transforms a vector by a 4x4 matrix (in-place). + * + * Params: + * vec = Vector to be transformed. + * mat = Matrix to transform the vector with. + */ + void function( aiVector3D* vec, aiMatrix4x4* mat ) aiTransformVecByMatrix4; + + /** + * Multiplies two 4x4 matrices. + * + * Params: + * dst = First factor, receives result. + * src = Matrix to be multiplied with 'dst'. + */ + void function( aiMatrix4x4* dst, aiMatrix4x4* src ) aiMultiplyMatrix4; + + /** + * Multiplies two 3x3 matrices. + * + * Params: + * dst = First factor, receives result. + * src = Matrix to be multiplied with 'dst'. + */ + void function( aiMatrix3x3* dst, aiMatrix3x3* src ) aiMultiplyMatrix3; + + /** + * Constructs a 3x3 identity matrix. + * + * Params: + * mat = Matrix to receive its personal identity. + */ + void function( aiMatrix3x3* mat ) aiIdentityMatrix3; + + /** + * Constructs a 4x4 identity matrix. + * + * Params: + * mat = Matrix to receive its personal identity. + */ + void function( aiMatrix4x4* mat ) aiIdentityMatrix4; + + + /* + * Material system functions. + */ + + /** + * Retrieves a material property with a specific key from the material. + * + * Params: + * pMat = Pointer to the input material. May not be null. + * pKey = Key to search for. One of the <code>AI_MATKEY_XXX</code> + * constants. + * type = Specifies the <code>aiTextureType</code> of the texture to be + * retrieved, 0 for non-texture properties. + * index = Index of the texture to be retrieved, + * 0 for non-texture properties. + * pPropOut = Pointer to receive a pointer to a valid + * <code>aiMaterialProperty</code> structure or null if the key has + * not been found. + */ + aiReturn function( + aiMaterial* pMat, + char* pKey, + uint type, + uint index, + aiMaterialProperty** pPropOut + ) aiGetMaterialProperty; + + /** + * Retrieves a single float value or an array of float values from the + * material. + * + * Examples: + * --- + * const FLOATS_IN_UV_TRANSFORM = ( aiUVTransform.sizeof / float.sizeof ); + * uint valuesRead = FLOATS_IN_UV_TRANSFORM; + * bool success = + * ( aiGetMaterialFloatArray( &material, AI_MATKEY_UVTRANSFORM, + * aiTextureType.DIFFUSE, 0, cast( float* ) &trafo, &valuesRead ) == + * aiReturn.SUCCESS ) && + * ( valuesRead == FLOATS_IN_UV_TRANSFORM ); + * --- + * + * Params: + * pMat = Pointer to the input material. May not be null. + * pKey = Key to search for. One of the AI_MATKEY_XXX constants. + * type = Specifies the <code>aiTextureType</code> of the texture to be + * retrieved, 0 for non-texture properties. + * index = Index of the texture to be retrieved, + * 0 for non-texture properties. + * pOut = Pointer to a buffer to receive the result. + * pMax = Specifies the size of the given buffer in floats. Receives the + * number of values (not bytes!) read. null to read a scalar property. + * + * Returns: + * Specifies whether the key has been found. If not, the output arrays + * remains unmodified and pMax is set to 0. + */ + aiReturn function( + aiMaterial* pMat, + char* pKey, + uint type, + uint index, + float* pOut, + uint* pMax = null + ) aiGetMaterialFloatArray; + + /** + * Convenience alias for <code>aiGetMaterialFloatArray()</code>. + */ + alias aiGetMaterialFloatArray aiGetMaterialFloat; + + /** + * Retrieves a single integer value or an array of integer values from the + * material. + * + * See: <code>aiGetMaterialFloatArray()</code> + */ + aiReturn function( + aiMaterial* pMat, + char* pKey, + uint type, + uint index, + int* pOut, + uint* pMax = null + ) aiGetMaterialIntegerArray; + + /** + * Convenience alias for <code>aiGetMaterialIntegerArray()</code>. + */ + alias aiGetMaterialIntegerArray aiGetMaterialInteger; + + /** + * Retrieves a color value from the material. + * + * See: <code>aiGetMaterialFloatArray()</code> + */ + aiReturn function( + aiMaterial* pMat, + char* pKey, + uint type, + uint index, + aiColor4D* pOut + ) aiGetMaterialColor; + + /** + * Retrieves a string value from the material. + * + * See: <code>aiGetMaterialFloatArray()</code> + */ + aiReturn function( + aiMaterial* pMat, + char* pKey, + uint type, + uint index, + aiString* pOut + ) aiGetMaterialString; + + /** + * Get the number of textures for a particular texture type. + * + * Params: + * pMat = Pointer to the input material. May not be NULL + * type = Texture type to check for + * + * Returns: + * Number of textures for this type. + */ + uint function( aiMaterial* pMat, aiTextureType type ) aiGetMaterialTextureCount; + + /** + * Helper function to get all values pertaining to a particular texture slot + * from a material structure. + * + * This function is provided just for convenience. You could also read the + * texture by parsing all of its properties manually. This function bundles + * all of them in a huge function monster. + * + * Params: + * mat = Pointer to the input material. May not be null. + * type = Specifies the texture stack (<code>aiTextureType</code>) to + * read from. + * index = Index of the texture. The function fails if the requested + * index is not available for this texture type. + * <code>aiGetMaterialTextureCount()</code> can be used to determine + * the number of textures in a particular texture stack. + * path = Receives the output path. null is not a valid value. + * mapping = Receives the texture mapping mode to be used. + * Pass null if you are not interested in this information. + * uvindex = For UV-mapped textures: receives the index of the UV source + * channel. Unmodified otherwise. Pass null if you are not interested + * in this information. + * blend = Receives the blend factor for the texture. + * Pass null if you are not interested in this information. + * op = Receives the texture blend operation to be perform between this + * texture and the previous texture. Pass null if you are not + * interested in this information. + * mapmode = Receives the mapping modes to be used for the texture. Pass + * a pointer to an array of two aiTextureMapMode's (one for each axis, + * UV order) or null if you are not interested in this information. + * + * Returns: + * <code>aiReturn.SUCCESS</code> on success, otherwise something else. + */ + aiReturn function( + aiMaterial* mat, + aiTextureType type, + uint index, + aiString* path, + aiTextureMapping* mapping = null, + uint* uvindex = null, + float* blend = null, + aiTextureOp* op = null, + aiTextureMapMode* mapmode = null + ) aiGetMaterialTexture; + + + /* + * Versioning functions. + */ + + /** + * Returns a string with legal copyright and licensing information about + * Assimp. + * + * The string may include multiple lines. + * + * Returns: + * Pointer to static string. + */ + char* function() aiGetLegalString; + + /** + * Returns the current minor version number of the Assimp library. + * + * Returns: + * Minor version of the Assimp library. + */ + uint function() aiGetVersionMinor; + + /** + * Returns the current major version number of the Assimp library. + * + * Returns: + * Major version of the Assimp library. + */ + uint function() aiGetVersionMajor; + + /** + * Returns the repository revision of the Assimp library. + * + * Returns: + * SVN Repository revision number of the Assimp library. + */ + uint function() aiGetVersionRevision; + + /** + * Returns the flags Assimp was compiled with. + * + * Returns: + * Any bitwise combination of the ASSIMP_CFLAGS_xxx constants. + */ + uint function() aiGetCompileFlags; +} diff --git a/libs/assimp/port/dAssimp/assimp/assimp.d b/libs/assimp/port/dAssimp/assimp/assimp.d new file mode 100644 index 0000000..a147ee2 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/assimp.d @@ -0,0 +1,63 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Include-all module provided for convenience. + */ +module assimp.assimp; + +public { + import assimp.animation; + import assimp.api; + import assimp.camera; + import assimp.config; + import assimp.fileIO; + import assimp.light; + import assimp.loader; + import assimp.material; + import assimp.math; + import assimp.mesh; + import assimp.postprocess; + import assimp.scene; + import assimp.texture; + import assimp.types; + import assimp.versionInfo; +} diff --git a/libs/assimp/port/dAssimp/assimp/camera.d b/libs/assimp/port/dAssimp/assimp/camera.d new file mode 100644 index 0000000..5567be2 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/camera.d @@ -0,0 +1,182 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Contains the data structure which is used to store the imported information + * about the virtual cameras in the scene. + */ +module assimp.camera; + +import assimp.math; +import assimp.types; + +extern ( C ) { + /** + * Helper structure to describe a virtual camera. + * + * Cameras have a representation in the node graph and can be animated. + * An important aspect is that the camera itself is also part of the + * scenegraph. This means, any values such as the look-at vector are not + * absolute, they're <em>relative</em> to the coordinate system defined + * by the node which corresponds to the camera. This allows for camera + * animations. Static cameras parameters like the look-at or up vectors are + * usually specified directly in the class members, but beware, they could + * also be encoded in the node transformation. The following (pseudo)code + * sample shows how to do it. + * + * Examples: + * --- + * // Get the camera matrix for a camera at a specific time + * // if the node hierarchy for the camera does not contain + * // at least one animated node this is a static computation + * get-camera-matrix (node sceneRoot, camera cam) : matrix + * { + * node cnd = find-node-for-camera(cam) + * matrix cmt = identity() + * + * // as usual - get the absolute camera transformation for this frame + * for each node nd in hierarchy from sceneRoot to cnd + * matrix cur + * if (is-animated(nd)) + * cur = eval-animation(nd) + * else cur = nd->mTransformation; + * cmt = mult-matrices( cmt, cur ) + * end for + * + * // now multiply with the camera's own local transform + * cam = mult-matrices (cam, get-camera-matrix(cmt) ) + * } + * --- + * + * Note: Some file formats (such as 3DS, ASE) export a "target point" – the + * point the camera is looking at (it can even be animated). Assimp + * writes the target point as a subnode of the camera's main node, called + * "<camName>.Target". However, this is just additional information; the + * transformation applied to the main camera node already makes the + * camera face the right direction. + */ + struct aiCamera { + /** + * The name of the camera. + * + * There must be a node in the scenegraph with the same name. This node + * specifies the position of the camera in the scene hierarchy and can + * be animated. + */ + aiString mName; + + + /** + * Position of the camera relative to the coordinate space defined by the + * corresponding node. + * + * The default value is 0|0|0. + */ + aiVector3D mPosition; + + /** + * Up vector of the camera coordinate system relative to the + * coordinate space defined by the corresponding node. + * + * The right vector of the camera coordinate system is the cross + * product of the up and lookAt vectors. + * + * The default value is 0|1|0. The vector may be normalized, but it + * needn't. + */ + aiVector3D mUp; + + /** + * Look-at vector of the camera coordinate system relative to the + * coordinate space defined by the corresponding node. + * + * This is the viewing direction of the user. + * + * The default value is 0|0|1. The vector may be normalized, but it + * needn't. + */ + aiVector3D mLookAt; + + + /** + * Half horizontal field of view angle, in radians. + * + * The field of view angle is the angle between the center line of the + * screen and the left or right border. + * + * The default value is PI/4. + */ + float mHorizontalFOV; + + /** + * Distance of the near clipping plane from the camera. + * + * The value may not be 0.f (for arithmetic reasons to prevent + * a division through zero). + * + * The default value is 0.1f. + */ + float mClipPlaneNear; + + /** + * Distance of the far clipping plane from the camera. + * + * The far clipping plane must, of course, be further away than the + * near clipping plane. The ratio between the near and the far plane + * should not be too large (between 1000-10000 should be ok) to avoid + * floating-point inaccuracies which could lead to z-fighting. + * + * The default value is 1000.f. + */ + float mClipPlaneFar; + + /** + * Screen aspect ratio. + * + * This is the ration between the width and the height of the + * screen. Typical values are 4/3, 1/2 or 1/1. This value is + * 0 if the aspect ratio is not defined in the source file. + * + * 0 is also the default value. + */ + float mAspect; + } +} diff --git a/libs/assimp/port/dAssimp/assimp/config.d b/libs/assimp/port/dAssimp/assimp/config.d new file mode 100644 index 0000000..761156b --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/config.d @@ -0,0 +1,705 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Defines constants for configurable properties for the library. + * + * These are set via <code>aiSetImportPropertyInteger()</code>, + * <code>aiSetImportPropertyFloat()</code> and + * <code>aiSetImportPropertyString()</code>. + */ +module assimp.config; + +extern ( C ) { + /* + * Library settings. + * + * General, global settings. + */ + + /** + * Enables time measurements. + * + * If enabled, measures the time needed for each part of the loading + * process (i.e. IO time, importing, postprocessing, ..) and dumps these + * timings to the DefaultLogger. See the performance page in the main + * Assimp docs information on this topic. + * + * Property type: bool. Default value: false. + */ + const char* AI_CONFIG_GLOB_MEASURE_TIME = "GLOB_MEASURE_TIME"; + + version( none ) { // not implemented yet + /** + * Set Assimp's multithreading policy. + * + * This setting is ignored if Assimp was built without boost.thread support + * (<code>ASSIMP_BUILD_NO_THREADING</code>, which is implied by + * <code>ASSIMP_BUILD_BOOST_WORKAROUND</code>). + * + * Possible values are: -1 to let Assimp decide what to do, 0 to disable + * multithreading entirely and any number larger than 0 to force a specific + * number of threads. Assimp is always free to ignore this settings, which + * is merely a hint. Usually, the default value (-1) will be fine. However, + * if Assimp is used concurrently from multiple user threads, it might be + * useful to limit each Importer instance to a specific number of cores. + * + * For more information, see the threading page in the main Assimp docs. + * + * Property type: int, default value: -1. + */ + const char* AI_CONFIG_GLOB_MULTITHREADING = "GLOB_MULTITHREADING"; + } + + + /* + * Post processing settings. + * + * Various options to fine-tune the behavior of a specific post processing step. + */ + + /** + * Specifies the maximum angle that may be between two vertex tangents that + * their tangents and bitangents are smoothed. + * + * This applies to the <code>CalcTangentSpace</code> step. The angle is + * specified in degrees, so 180 corresponds to PI radians. + * + * The default value is 45, the maximum value is 175. + * + * Property type: float. + */ + const char* AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE = "PP_CT_MAX_SMOOTHING_ANGLE"; + + /** + * Specifies the maximum angle that may be between two face normals at the + * same vertex position that their are smoothed together. Sometimes referred + * to as 'crease angle'. + * + * This applies to the <code>GenSmoothNormals</code> step. The angle is + * specified in degrees, so 180 corresponds to PI radians. + * + * The default value is 175 degrees (all vertex normals are smoothed), the + * maximum value is 175, too. + * + * Property type: float. + * + * Warning: + * Setting this option may cause a severe loss of performance. The + * performance is unaffected if the <code>AI_CONFIG_FAVOUR_SPEED</code> + * flag is set but the output quality may be reduced. + */ + const char* AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE = "PP_GSN_MAX_SMOOTHING_ANGLE"; + + /** + * Sets the colormap (= palette) to be used to decode embedded textures in + * MDL (Quake or 3DGS) files. + * + * This must be a valid path to a file. The file is 768 (256*3) bytes large + * and contains RGB triplets for each of the 256 palette entries. The + * default value is colormap.lmp. If the file is not found, a default + * palette (from Quake 1) is used. + * + * Property type: string. + */ + const char* AI_CONFIG_IMPORT_MDL_COLORMAP = "IMPORT_MDL_COLORMAP"; + + /** + * Configures the <code>RemoveRedundantMaterials</code> step to keep + * materials matching a name in a given list. + * + * This is a list of 1 to n strings, ' ' serves as delimiter character. + * Identifiers containing whitespaces must be enclosed in <em>single</em> + * quotation marks. For example: <code> + * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'"</code>. + * Linefeeds, tabs or carriage returns are treated as whitespace. + * + * If a material matches on of these names, it will not be modified or + * removed by the postprocessing step nor will other materials be replaced + * by a reference to it. + * + * This option might be useful if you are using some magic material names + * to pass additional semantics through the content pipeline. This ensures + * they won't be optimized away, but a general optimization is still + * performed for materials not contained in the list. + * + * Default value: n/a + * + * Property type: string. + * + * Note: Material names are case sensitive. + */ + const char* AI_CONFIG_PP_RRM_EXCLUDE_LIST = "PP_RRM_EXCLUDE_LIST"; + + /** + * Configures the <code>PretransformVertices</code> step to keep the scene + * hierarchy. Meshes are moved to worldspace, but no optimization is + * performed (meshes with equal materials are not joined, the total number + * of meshes will not change). + * + * This option could be of use for you if the scene hierarchy contains + * important additional information which you intend to parse. + * For rendering, you can still render all meshes in the scene without + * any transformations. + * + * Default value: false. + * + * Property type: bool. + */ + const char* AI_CONFIG_PP_PTV_KEEP_HIERARCHY = "PP_PTV_KEEP_HIERARCHY"; + + /** + * Configures the <code>PretransformVertices</code> step to normalize all + * vertex components into the -1...1 range. That is, a bounding box for the + * whole scene is computed, the maximum component is taken and all meshes + * are scaled appropriately (uniformly of course!). + * + * This might be useful if you don't know the spatial dimension of the input + * data. + */ + const char* AI_CONFIG_PP_PTV_NORMALIZE = "PP_PTV_NORMALIZE"; + + /** + * Configures the <code>FindDegenerates</code> step to remove degenerated + * primitives from the import – immediately. + * + * The default behaviour converts degenerated triangles to lines and + * degenerated lines to points. See the documentation to the + * <code>FindDegenerates</code> step for a detailed example of the various + * ways to get rid of these lines and points if you don't want them. + * + * Default value: false. + * + * Property type: bool. + */ + const char* AI_CONFIG_PP_FD_REMOVE = "PP_FD_REMOVE"; + + /** + * Configures the <code>OptimizeGraph</code> step to preserve nodes matching + * a name in a given list. + * + * This is a list of 1 to n strings, ' ' serves as delimiter character. + * Identifiers containing whitespaces must be enclosed in <em>single</em> + * quotation marks. For example: <code> + * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'"</code>. + * Linefeeds, tabs or carriage returns are treated as whitespace. + * + * If a node matches on of these names, it will not be modified or + * removed by the postprocessing step. + * + * This option might be useful if you are using some magic node names + * to pass additional semantics through the content pipeline. This ensures + * they won't be optimized away, but a general optimization is still + * performed for nodes not contained in the list. + * + * Default value: n/a + * + * Property type: string. + * + * Note: Node names are case sensitive. + */ + const char* AI_CONFIG_PP_OG_EXCLUDE_LIST = "PP_OG_EXCLUDE_LIST"; + + /** + * Sets the maximum number of triangles in a mesh. + * + * This is used by the <code>SplitLargeMeshes</code> step to determine + * whether a mesh must be split or not. + * + * Default value: AI_SLM_DEFAULT_MAX_TRIANGLES. + * + * Property type: integer. + */ + const char* AI_CONFIG_PP_SLM_TRIANGLE_LIMIT = "PP_SLM_TRIANGLE_LIMIT"; + + /** + * The default value for the AI_CONFIG_PP_SLM_TRIANGLE_LIMIT setting. + */ + const AI_SLM_DEFAULT_MAX_TRIANGLES = 1000000; + + /** + * Sets the maximum number of vertices in a mesh. + * + * This is used by the <code>SplitLargeMeshes</code> step to determine + * whether a mesh must be split or not. + * + * Default value: AI_SLM_DEFAULT_MAX_VERTICES + * + * Property type: integer. + */ + const char* AI_CONFIG_PP_SLM_VERTEX_LIMIT = "PP_SLM_VERTEX_LIMIT"; + + /** + * The default value for the AI_CONFIG_PP_SLM_VERTEX_LIMIT setting. + */ + const AI_SLM_DEFAULT_MAX_VERTICES = 1000000; + + /** + * Sets the maximum number of bones affecting a single vertex. + * + * This is used by the <code>LimitBoneWeights</code> step. + * + * Default value: AI_LBW_MAX_WEIGHTS + * + * Property type: integer. + */ + const char* AI_CONFIG_PP_LBW_MAX_WEIGHTS = "PP_LBW_MAX_WEIGHTS"; + + /** + * The default value for the AI_CONFIG_PP_LBW_MAX_WEIGHTS setting. + */ + const AI_LMW_MAX_WEIGHTS = 0x4; + + /** + * Sets the size of the post-transform vertex cache to optimize the + * vertices for. This configures the <code>ImproveCacheLocality</code> step. + * + * The size is given in vertices. Of course you can't know how the vertex + * format will exactly look like after the import returns, but you can still + * guess what your meshes will probably have. + * + * The default value results in slight performance improvements for most + * nVidia/AMD cards since 2002. + * + * Default value: PP_ICL_PTCACHE_SIZE + * + * Property type: integer. + */ + const char* AI_CONFIG_PP_ICL_PTCACHE_SIZE = "PP_ICL_PTCACHE_SIZE"; + + /** + * The default value for the AI_CONFIG_PP_ICL_PTCACHE_SIZE config option. + */ + const PP_ICL_PTCACHE_SIZE = 12; + + /** + * Components of the <code>aiScene</code> and <code>aiMesh</code> data + * structures that can be excluded from the import by using the + * <code>RemoveComponent</code> step. + * + * See the documentation to <code>RemoveComponent</code> for more details. + */ + enum aiComponent : uint { + /** + * Normal vectors. + */ + NORMALS = 0x2, + + /** + * Tangents and bitangents. + */ + TANGENTS_AND_BITANGENTS = 0x4, + + /** + * <em>All</em> color sets. + * + * Use aiComponent_COLORSn( N ) to specify the N'th set. + */ + COLORS = 0x8, + + /** + * <em>All</em> texture UV coordinate sets. + * + * Use aiComponent_TEXCOORDn( N ) to specify the N'th set. + */ + TEXCOORDS = 0x10, + + /** + * Bone weights from all meshes. + * + * The corresponding scenegraph nodes are <em>not</em> removed. Use the + * <code>OptimizeGraph</code> step to do this. + */ + BONEWEIGHTS = 0x20, + + /** + * Node animations (<code>aiScene.mAnimations</code>). + * + * The corresponding scenegraph nodes are <em>not</em> removed. Use the + * <code>OptimizeGraph</code> step to do this. + */ + ANIMATIONS = 0x40, + + /** + * Embedded textures (<code>aiScene.mTextures</code>). + */ + TEXTURES = 0x80, + + /** + * Light sources (<code>aiScene.mLights</code>). + * + * The corresponding scenegraph nodes are <em>not</em> removed. Use the + * <code>OptimizeGraph</code> step to do this. + */ + LIGHTS = 0x100, + + /** + * Cameras (<code>aiScene.mCameras</code>). + * + * The corresponding scenegraph nodes are <em>not</em> removed. Use the + * <code>OptimizeGraph</code> step to do this. + */ + CAMERAS = 0x200, + + /** + * Meshes (<code>aiScene.mMeshes</code>). + */ + MESHES = 0x400, + + /** Materials. + * + * One default material will be generated, so + * <code>aiScene.mNumMaterials</code> will be 1. + */ + MATERIALS = 0x800 + } + + /** + * Specifies a certain color channel to remove. + */ + uint aiComponent_COLORSn( uint n ) { return 1u << ( n + 20u ); } + + /** + * Specifies a certain UV coordinate channel to remove. + */ + uint aiComponent_TEXCOORDSn( uint n ) { return 1u << ( n + 25u ); } + + /** + * Input parameter to the <code>RemoveComponent</code> step: + * Specifies the parts of the data structure to be removed. + * + * See the documentation to this step for further details. + * + * Default value: 0 + * + * Property type: integer (bitwise combination of <code>aiComponent</code> + * flags). + * + * Note: If no valid mesh is remaining after the step has been executed, the + * import <em>fails</em>, because there is no data to work on anymore. + */ + const char* AI_CONFIG_PP_RVC_FLAGS = "PP_RVC_FLAGS"; + + /** + * Input parameter to the <code>SortByPType</code> step: + * Specifies which primitive types are removed by the step. + * + * This is a bitwise combination of the <code>aiPrimitiveType</code> flags. + * Specifying all of them is illegal, of course. A typical use would be to + * exclude all line and point meshes from the import. + * + * Default value: 0 + * + * Property type: integer. + */ + const char* AI_CONFIG_PP_SBP_REMOVE = "PP_SBP_REMOVE"; + + /** + * Input parameter to the <code>FindInvalidData</code> step: + * Specifies the floating-point accuracy for animation values. + * + * The step checks for animation tracks where all frame values are + * absolutely equal and removes them. This tweakable controls the epsilon + * for floating-point comparisons – two keys are considered equal if the + * invariant abs(n0-n1) > epsilon holds true for all vector respectively + * quaternion components. + * + * Default value: 0 (exact comparison). + * + * Property type: float. + */ + const char* AI_CONFIG_PP_FID_ANIM_ACCURACY = "PP_FID_ANIM_ACCURACY"; + + /** + * The <code>TransformUVCoords</code> step evaluates UV scalings. + */ + const AI_UVTRAFO_SCALING = 0x1; + + /** + * The <code>TransformUVCoords</code> step evaluates UV rotations. + */ + const AI_UVTRAFO_ROTATION = 0x2; + + /** + * The <code>TransformUVCoords</code> step evaluates UV translation. + */ + const AI_UVTRAFO_TRANSLATION = 0x4; + + /** + * The <code>TransformUVCoords</code> step evaluates all UV translations. + */ + const AI_UVTRAFO_ALL = + AI_UVTRAFO_SCALING + | AI_UVTRAFO_ROTATION + | AI_UVTRAFO_TRANSLATION; + + /** + * Input parameter to the <code>TransformUVCoords</code> step: Specifies + * which UV transformations are evaluated. + * + * Default value: AI_UVTRAFO_ALL. + * + * Property type: integer (bitwise combination of the + * <code>AI_UVTRAFO_XXX<code> flag). + */ + const char* AI_CONFIG_PP_TUV_EVALUATE = "PP_TUV_EVALUATE"; + + /** + * A hint to assimp to favour speed against import quality. + * + * Enabling this option may result in faster loading, but it needn't. + * It represents just a hint to loaders and post-processing steps to use + * faster code paths, if possible. + * + * Default value: false. + * + * Property type: bool. + */ + const char* AI_CONFIG_FAVOUR_SPEED = "FAVOUR_SPEED"; + + + /* + * Importer settings. + * + * Various stuff to fine-tune the behaviour of specific importer plugins. + */ + + /** + * Set the vertex animation keyframe to be imported. + * + * Assimp does not support vertex keyframes (only bone animation is + * supported). The library reads only one frame of models with vertex + * animations. + * + * Default value: 0 (first frame). + * + * Property type: integer. + * + * Note: This option applies to all importers. However, it is also possible + * to override the global setting for a specific loader. You can use the + * AI_CONFIG_IMPORT_XXX_KEYFRAME options (where XXX is a placeholder for + * the file format for which you want to override the global setting). + */ + const char* AI_CONFIG_IMPORT_GLOBAL_KEYFRAME = "IMPORT_GLOBAL_KEYFRAME"; + + const char* AI_CONFIG_IMPORT_MD3_KEYFRAME = "IMPORT_MD3_KEYFRAME"; + const char* AI_CONFIG_IMPORT_MD2_KEYFRAME = "IMPORT_MD2_KEYFRAME"; + const char* AI_CONFIG_IMPORT_MDL_KEYFRAME = "IMPORT_MDL_KEYFRAME"; + const char* AI_CONFIG_IMPORT_MDC_KEYFRAME = "IMPORT_MDC_KEYFRAME"; + const char* AI_CONFIG_IMPORT_SMD_KEYFRAME = "IMPORT_SMD_KEYFRAME"; + const char* AI_CONFIG_IMPORT_UNREAL_KEYFRAME = "IMPORT_UNREAL_KEYFRAME"; + + + /** + * Configures the AC loader to collect all surfaces which have the + * "Backface cull" flag set in separate meshes. + * + * Default value: true. + * + * Property type: bool. + */ + const char* AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL = "IMPORT_AC_SEPARATE_BFCULL"; + + /** + * Configures the UNREAL 3D loader to separate faces with different surface + * flags (e.g. two-sided vs. single-sided). + * + * Default value: true. + * + * Property type: bool. + */ + const char* AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS = "UNREAL_HANDLE_FLAGS"; + + /** + * Configures the terragen import plugin to compute uv's for terrains, if + * not given. Furthermore, a default texture is assigned. + * + * UV coordinates for terrains are so simple to compute that you'll usually + * want to compute them on your own, if you need them. This option is intended + * for model viewers which want to offer an easy way to apply textures to + * terrains. + * + * Default value: false. + * + * Property type: bool. + */ + const char* AI_CONFIG_IMPORT_TER_MAKE_UVS = "IMPORT_TER_MAKE_UVS"; + + /** + * Configures the ASE loader to always reconstruct normal vectors basing on + * the smoothing groups loaded from the file. + * + * Many ASE files have invalid normals (they're not orthonormal). + * + * Default value: true. + * + * Property type: bool. + */ + const char* AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS = "IMPORT_ASE_RECONSTRUCT_NORMALS"; + + /** + * Configures the M3D loader to detect and process multi-part Quake player + * models. + * + * These models usually consist of three files, <code>lower.md3</code>, + * <code>upper.md3</code> and <code>head.md3</code>. If this property is set + * to true, Assimp will try to load and combine all three files if one of + * them is loaded. + * + * Default value: true. + * + * Property type: bool. + */ + const char* AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART = "IMPORT_MD3_HANDLE_MULTIPART"; + + /** + * Tells the MD3 loader which skin files to load. + * + * When loading MD3 files, Assimp checks whether a file + * <code><md3_file_name>_<skin_name>.skin</code> is existing. These files + * are used by Quake 3 to be able to assign different skins (e.g. red and + * blue team) to models. 'default', 'red', 'blue' are typical skin names. + * + * Default value: "default". + * + * Property type: string. + */ + const char* AI_CONFIG_IMPORT_MD3_SKIN_NAME = "IMPORT_MD3_SKIN_NAME"; + + /** + * Specify the Quake 3 shader file to be used for a particular MD3 file. + * This can also be a search path. + * + * By default Assimp's behaviour is as follows: If a MD3 file + * <code>[any_path]/models/[any_q3_subdir]/[model_name]/[file_name].md3</code> + * is loaded, the library tries to locate the corresponding shader file in + * <code>[any_path]/scripts/[model_name].shader</code>. This property + * overrides this behaviour. It can either specify a full path to the shader + * to be loaded or alternatively the path (relative or absolute) to the + * directory where the shaders for all MD3s to be loaded reside. Assimp + * attempts to open <code>[dir]/[model_name].shader</code> first, + * <code>[dir]/[file_name].shader</code> is the fallback file. Note that + * <code>[dir]</code> should have a terminal (back)slash. + * + * Default value: n/a. + * + * Property type: string. + */ + const char* AI_CONFIG_IMPORT_MD3_SHADER_SRC = "IMPORT_MD3_SHADER_SRC"; + + /** + * Configures the LWO loader to load just one layer from the model. + * + * LWO files consist of layers and in some cases it could be useful to load + * only one of them. This property can be either a string – which specifies + * the name of the layer – or an integer – the index of the layer. If the + * property is not set the whole LWO model is loaded. Loading fails if the + * requested layer is not available. The layer index is zero-based and the + * layer name may not be empty. + * + * Default value: all layers are loaded. + * + * Property type: integer/string. + */ + const char* AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY = "IMPORT_LWO_ONE_LAYER_ONLY"; + + /** + * Configures the MD5 loader to not load the MD5ANIM file for a MD5MESH file + * automatically. + * + * The default strategy is to look for a file with the same name but the + * MD5ANIM extension in the same directory. If it is found, it is loaded + * and combined with the MD5MESH file. This configuration option can be + * used to disable this behaviour. + * + * Default value: false. + * + * Property type: bool. + */ + const char* AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD = "IMPORT_MD5_NO_ANIM_AUTOLOAD"; + + /** + * Defines the begin of the time range for which the LWS loader evaluates + * animations and computes <code>aiNodeAnim</code>s. + * + * Assimp provides full conversion of LightWave's envelope system, including + * pre and post conditions. The loader computes linearly subsampled animation + * chanels with the frame rate given in the LWS file. This property defines + * the start time. Note: animation channels are only generated if a node + * has at least one envelope with more tan one key assigned. This property. + * is given in frames, '0' is the first frame. By default, if this property + * is not set, the importer takes the animation start from the input LWS + * file ('FirstFrame' line). + * + * Default value: read from file. + * + * Property type: integer. + * + * See: <code>AI_CONFIG_IMPORT_LWS_ANIM_END</code> – end of the imported + * time range + */ + const char* AI_CONFIG_IMPORT_LWS_ANIM_START = "IMPORT_LWS_ANIM_START"; + const char* AI_CONFIG_IMPORT_LWS_ANIM_END = "IMPORT_LWS_ANIM_END"; + + /** + * Defines the output frame rate of the IRR loader. + * + * IRR animations are difficult to convert for Assimp and there will always + * be a loss of quality. This setting defines how many keys per second are + * returned by the converter. + * + * Default value: 100. + * + * Property type: integer. + */ + const char* AI_CONFIG_IMPORT_IRR_ANIM_FPS = "IMPORT_IRR_ANIM_FPS"; + + /** + * Ogre Importer will try to load this material file. + * + * Ogre Mehs contain only the material name, not the material file. If there + * is no material file with the same name as the material, Ogre Importer + * will try to load this file and search the material in it. + * + * Property type: string. Default value: "Scene.material". + */ + const char* AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE = "IMPORT_OGRE_MATERIAL_FILE"; +} diff --git a/libs/assimp/port/dAssimp/assimp/fileIO.d b/libs/assimp/port/dAssimp/assimp/fileIO.d new file mode 100644 index 0000000..108d883 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/fileIO.d @@ -0,0 +1,140 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * The data structures necessary to use Assimip with a custom IO system. + */ +module assimp.fileIO; + +import assimp.types; + +extern ( C ) { + // aiFile callbacks + alias size_t function( aiFile*, char*, size_t, size_t ) aiFileWriteProc; + alias size_t function( aiFile*, char*, size_t, size_t ) aiFileReadProc; + alias size_t function( aiFile* ) aiFileTellProc; + alias void function( aiFile* ) aiFileFlushProc; + alias aiReturn function( aiFile*, size_t, aiOrigin ) aiFileSeek; + + // aiFileIO callbacks + alias aiFile* function( aiFileIO*, char*, char* ) aiFileOpenProc; + alias void function( aiFileIO*, aiFile* ) aiFileCloseProc; + + /** + * Represents user-defined data. + */ + alias char* aiUserData; + + /** + * File system callbacks. + * + * Provided are functions to open and close files. Supply a custom structure + * to the import function. If you don't, a default implementation is used. + * Use custom file systems to enable reading from other sources, such as + * ZIPs or memory locations. + */ + struct aiFileIO { + /** + * Function used to open a new file + */ + aiFileOpenProc OpenProc; + + /** + * Function used to close an existing file + */ + aiFileCloseProc CloseProc; + + /** + * User-defined, opaque data. + */ + aiUserData UserData; + } + + /** + * File callbacks. + * + * Actually, it's a data structure to wrap a set of <code>fXXXX</code> + * (e.g <code>fopen()</code>) replacement functions. + * + * The default implementation of the functions utilizes the <code>fXXX</code> + * functions from the CRT. However, you can supply a custom implementation + * to Assimp by passing a custom <code>aiFileIO</code>. Use this to enable + * reading from other sources such as ZIP archives or memory locations. + */ + struct aiFile { + /** + * Callback to read from a file. + */ + aiFileReadProc ReadProc; + + /** + * Callback to write to a file. + */ + aiFileWriteProc WriteProc; + + /** + * Callback to retrieve the current position of the file cursor + * (<code>ftell()</code>). + */ + aiFileTellProc TellProc; + + /** + * Callback to retrieve the size of the file, in bytes. + */ + aiFileTellProc FileSizeProc; + + /** + * Callback to set the current position of the file cursor + * (<code>fseek()</code>). + */ + aiFileSeek SeekProc; + + /** + * Callback to flush the file contents. + */ + aiFileFlushProc FlushProc; + + /** + * User-defined, opaque data. + */ + aiUserData UserData; + } +} diff --git a/libs/assimp/port/dAssimp/assimp/light.d b/libs/assimp/port/dAssimp/assimp/light.d new file mode 100644 index 0000000..0842d67 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/light.d @@ -0,0 +1,215 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Contains the data structures which are used to store the imported information + * about the light sources in the scene. + */ +module assimp.light; + +import assimp.math; +import assimp.types; + +extern ( C ) { + /** + * Enumerates all supported types of light sources. + */ + enum aiLightSourceType : uint { + UNDEFINED = 0x0, + + /** + * A directional light source has a well-defined direction but is + * infinitely far away. That's quite a good approximation for sun light. + */ + DIRECTIONAL = 0x1, + + /** + * A point light source has a well-defined position in space but no + * direction – it emits light in all directions. A normal bulb is a point + * light. + */ + POINT = 0x2, + + /** + * A spot light source emits light in a specific angle. It has a position + * and a direction it is pointing to. A good example for a spot light is + * a light spot in sport arenas. + */ + SPOT = 0x3 + } + + /** + * Helper structure to describe a light source. + * + * Assimp supports multiple sorts of light sources, including directional, + * point and spot lights. All of them are defined with just a single + * structure and distinguished by their parameters. + * + * Note: Some file formats (such as 3DS, ASE) export a "target point" – the + * point a spot light is looking at (it can even be animated). Assimp + * writes the target point as a subnode of a spotlights's main node, called + * <code>[spotName].Target</code>. However, this is just additional + * information then, the transformation tracks of the main node make the + * spot light already point in the right direction. + */ + struct aiLight { + /** + * The name of the light source. + * + * There must be a node in the scenegraph with the same name. This node + * specifies the position of the light in the scenehierarchy and can be + * animated. + */ + aiString mName; + + /** + * The type of the light source. + * + * <code>aiLightSource.UNDEFINED</code> is not a valid value for this + * member. + */ + aiLightSourceType mType; + + /** + * Position of the light source in space. Relative to the transformation + * of the node corresponding to the light. + * + * The position is undefined for directional lights. + */ + aiVector3D mPosition; + + /** + * Direction of the light source in space. Relative to the transformation + * of the node corresponding to the light. + * + * The direction is undefined for point lights. The vector may be + * normalized, but it needn't. + */ + aiVector3D mDirection; + + /** + * Constant light attenuation factor. + * + * The intensity of the light source at a given distance + * <code>d</code> from the light's position is + * <code>1/( att0 + att1 * d + att2 * d * d )</code>. This member + * corresponds to the <code>att0</code> variable in the equation. + * + * Naturally undefined for directional lights. + */ + float mAttenuationConstant; + + /** + * Linear light attenuation factor. + * + * The intensity of the light source at a given distance + * <code>d</code> from the light's position is + * <code>1/( att0 + att1 * d + att2 * d * d )</code>. This member + * corresponds to the <code>att1</code> variable in the equation. + * + * Naturally undefined for directional lights. + */ + float mAttenuationLinear; + + /** + * Quadratic light attenuation factor. + * + * The intensity of the light source at a given distance + * <code>d</code> from the light's position is + * <code>1/( att0 + att1 * d + att2 * d * d )</code>. This member + * corresponds to the <code>att2</code> variable in the equation. + * + * Naturally undefined for directional lights. + */ + float mAttenuationQuadratic; + + /** + * Diffuse color of the light source + * + * The diffuse light color is multiplied with the diffuse material color + * to obtain the final color that contributes to the diffuse shading term. + */ + aiColor3D mColorDiffuse; + + /** + * Specular color of the light source + * + * The specular light color is multiplied with the specular material + * color to obtain the final color that contributes to the specular + * shading term. + */ + aiColor3D mColorSpecular; + + /** + * Ambient color of the light source + * + * The ambient light color is multiplied with the ambient material color + * to obtain the final color that contributes to the ambient shading term. + * + * Most renderers will ignore this value it, is just a remaining of the + * fixed-function pipeline that is still supported by quite many file + * formats. + */ + aiColor3D mColorAmbient; + + /** + * Inner angle of a spot light's light cone. + * + * The spot light has maximum influence on objects inside this angle. The + * angle is given in radians. It is 2PI for point lights and undefined + * for directional lights. + */ + float mAngleInnerCone; + + /** + * Outer angle of a spot light's light cone. + * + * The spot light does not affect objects outside this angle. The angle + * is given in radians. It is 2PI for point lights and undefined for + * directional lights. The outer angle must be greater than or equal to + * the inner angle. + * + * It is assumed that the application uses a smooth interpolation between + * the inner and the outer cone of the spot light. + */ + float mAngleOuterCone; + } +} diff --git a/libs/assimp/port/dAssimp/assimp/loader.d b/libs/assimp/port/dAssimp/assimp/loader.d new file mode 100644 index 0000000..279f0a7 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/loader.d @@ -0,0 +1,193 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Provides facilities for dynamically loading the Assimp library. + * + * Currently requires Tango, but there is no reason why Phobos could not be + * supported too. + */ +module assimp.loader; + +import assimp.api; +import tango.io.Stdout; +import tango.sys.SharedLib; + +const uint ASSIMP_BINDINGS_MAJOR = 2; +const uint ASSIMP_BINDINGS_MINOR = 0; + +/** + * Loader class for dynamically loading the Assimp library. + * + * The library is »reference-counted«, meaning that the library is not + * unloaded on a call to <code>unload()</code> if there are still other + * references to it. + */ +struct Assimp { +public: + /** + * Loads the library if it is not already loaded and increases the + * reference counter. + * + * The library file (<code>libassimp.so</code> on POSIX systems, + * <code>Assimp32.dll</code> on Win32) is loaded via Tango's SharedLib + * class. + */ + static void load() { + if ( m_sRefCount == 0 ) { + version ( Posix ) { + version ( OSX ) { + m_sLibrary = SharedLib.load( "libassimp.dylib" ); + } else { + m_sLibrary = SharedLib.load( "libassimp.so" ); + } + } + version ( Win32 ) { + m_sLibrary = SharedLib.load( "Assimp32.dll" ); + } + + // Versioning + mixin( bindCode( "aiGetLegalString" ) ); + mixin( bindCode( "aiGetVersionMinor" ) ); + mixin( bindCode( "aiGetVersionMajor" ) ); + mixin( bindCode( "aiGetVersionRevision" ) ); + mixin( bindCode( "aiGetCompileFlags" ) ); + + // Check for version mismatch between the external, dynamically loaded + // library and the version the bindings were created against. + uint libMajor = aiGetVersionMajor(); + uint libMinor = aiGetVersionMinor(); + + if ( ( libMajor < ASSIMP_BINDINGS_MAJOR ) || + ( libMinor < ASSIMP_BINDINGS_MINOR ) ) { + Stdout.format( + "WARNING: Assimp version too old (loaded library: {}.{}, " ~ + "bindings: {}.{})!", + libMajor, + libMinor, + ASSIMP_BINDINGS_MAJOR, + ASSIMP_BINDINGS_MINOR + ).newline; + } + + if ( libMajor > ASSIMP_BINDINGS_MAJOR ) { + Stdout.format( + "WARNING: Assimp version too new (loaded library: {}.{}, " ~ + "bindings: {}.{})!", + libMajor, + libMinor, + ASSIMP_BINDINGS_MAJOR, + ASSIMP_BINDINGS_MINOR + ).newline; + } + + // General API + mixin( bindCode( "aiImportFile" ) ); + mixin( bindCode( "aiImportFileEx" ) ); + mixin( bindCode( "aiImportFileFromMemory" ) ); + mixin( bindCode( "aiApplyPostProcessing" ) ); + mixin( bindCode( "aiGetPredefinedLogStream" ) ); + mixin( bindCode( "aiAttachLogStream" ) ); + mixin( bindCode( "aiEnableVerboseLogging" ) ); + mixin( bindCode( "aiDetachLogStream" ) ); + mixin( bindCode( "aiDetachAllLogStreams" ) ); + mixin( bindCode( "aiReleaseImport" ) ); + mixin( bindCode( "aiGetErrorString" ) ); + mixin( bindCode( "aiIsExtensionSupported" ) ); + mixin( bindCode( "aiGetExtensionList" ) ); + mixin( bindCode( "aiGetMemoryRequirements" ) ); + mixin( bindCode( "aiSetImportPropertyInteger" ) ); + mixin( bindCode( "aiSetImportPropertyFloat" ) ); + mixin( bindCode( "aiSetImportPropertyString" ) ); + + // Mathematical functions + mixin( bindCode( "aiCreateQuaternionFromMatrix" ) ); + mixin( bindCode( "aiDecomposeMatrix" ) ); + mixin( bindCode( "aiTransposeMatrix4" ) ); + mixin( bindCode( "aiTransposeMatrix3" ) ); + mixin( bindCode( "aiTransformVecByMatrix3" ) ); + mixin( bindCode( "aiTransformVecByMatrix4" ) ); + mixin( bindCode( "aiMultiplyMatrix4" ) ); + mixin( bindCode( "aiMultiplyMatrix3" ) ); + mixin( bindCode( "aiIdentityMatrix3" ) ); + mixin( bindCode( "aiIdentityMatrix4" ) ); + + // Material system + mixin( bindCode( "aiGetMaterialProperty" ) ); + mixin( bindCode( "aiGetMaterialFloatArray" ) ); + mixin( bindCode( "aiGetMaterialIntegerArray" ) ); + mixin( bindCode( "aiGetMaterialColor" ) ); + mixin( bindCode( "aiGetMaterialString" ) ); + mixin( bindCode( "aiGetMaterialTextureCount" ) ); + mixin( bindCode( "aiGetMaterialTexture" ) ); + } + ++m_sRefCount; + } + + /** + * Decreases the reference counter and unloads the library if this was the + * last reference. + */ + static void unload() { + assert( m_sRefCount > 0 ); + --m_sRefCount; + + if ( m_sRefCount == 0 ) { + m_sLibrary.unload(); + } + } + +private: + /// Current number of references to the library. + static uint m_sRefCount; + + /// Library handle. + static SharedLib m_sLibrary; +} + +/** + * Private helper function which constructs the bind command for a symbol to + * keep the code DRY. + */ +private char[] bindCode( char[] symbol ) { + return symbol ~ " = cast( typeof( " ~ symbol ~ + " ) )m_sLibrary.getSymbol( `" ~ symbol ~ "` );"; +} diff --git a/libs/assimp/port/dAssimp/assimp/material.d b/libs/assimp/port/dAssimp/assimp/material.d new file mode 100644 index 0000000..f0eae86 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/material.d @@ -0,0 +1,641 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Contains the material system which stores the imported material information. + */ +module assimp.material; + +import assimp.math; +import assimp.types; + +extern ( C ) { + /** + * Default material names for meshes without UV coordinates. + */ + const char* AI_DEFAULT_MATERIAL_NAME = "aiDefaultMat"; + + /** + * Default material names for meshes with UV coordinates. + */ + const char* AI_DEFAULT_TEXTURED_MATERIAL_NAME = "TexturedDefaultMaterial"; + + /** + * Defines how the Nth texture of a specific type is combined with the + * result of all previous layers. + * + * Example (left: key, right: value): + * <pre> DiffColor0 - gray + * DiffTextureOp0 - aiTextureOpMultiply + * DiffTexture0 - tex1.png + * DiffTextureOp0 - aiTextureOpAdd + * DiffTexture1 - tex2.png</pre> + * Written as equation, the final diffuse term for a specific pixel would be: + * <pre>diffFinal = DiffColor0 * sampleTex( DiffTexture0, UV0 ) + + * sampleTex( DiffTexture1, UV0 ) * diffContrib;</pre> + * where <code>diffContrib</code> is the intensity of the incoming light for + * that pixel. + */ + enum aiTextureOp : uint { + /** + * <code>T = T1 * T2</code> + */ + Multiply = 0x0, + + /** + * <code>T = T1 + T2</code> + */ + Add = 0x1, + + /** + * <code>T = T1 - T2</code> + */ + Subtract = 0x2, + + /** + * <code>T = T1 / T2</code> + */ + Divide = 0x3, + + /** + * <code>T = ( T1 + T2 ) - ( T1 * T2 )</code> + */ + SmoothAdd = 0x4, + + /** + * <code>T = T1 + ( T2 - 0.5 )</code> + */ + SignedAdd = 0x5 + } + + /** + * Defines how UV coordinates outside the <code>[0..1]</code> range are + * handled. + * + * Commonly referred to as 'wrapping mode'. + */ + enum aiTextureMapMode : uint { + /** + * A texture coordinate <code>u | v</code> is translated to + * <code>(u%1) | (v%1)</code>. + */ + Wrap = 0x0, + + /** + * Texture coordinates are clamped to the nearest valid value. + */ + Clamp = 0x1, + + /** + * If the texture coordinates for a pixel are outside + * <code>[0..1]</code>, the texture is not applied to that pixel. + */ + Decal = 0x3, + + /** + * A texture coordinate <code>u | v</code> becomes + * <code>(u%1) | (v%1)</code> if <code>(u-(u%1))%2</code> is + * zero and <code>(1-(u%1)) | (1-(v%1))</code> otherwise. + */ + Mirror = 0x2 + } + + /** + * Defines how the mapping coords for a texture are generated. + * + * Real-time applications typically require full UV coordinates, so the use of + * the <code>aiProcess.GenUVCoords</code> step is highly recommended. It + * generates proper UV channels for non-UV mapped objects, as long as an + * accurate description how the mapping should look like (e.g spherical) is + * given. See the <code>AI_MATKEY_MAPPING</code> property for more details. + */ + enum aiTextureMapping : uint { + /** + * The mapping coordinates are taken from an UV channel. + * + * The <code>AI_MATKEY_UVSRC</code> key specifies from which (remember, + * meshes can have more than one UV channel). + */ + UV = 0x0, + + /** + * Spherical mapping. + */ + SPHERE = 0x1, + + /** + * Cylindrical mapping. + */ + CYLINDER = 0x2, + + /** + * Cubic mapping. + */ + BOX = 0x3, + + /** + * Planar mapping. + */ + PLANE = 0x4, + + /** + * Undefined mapping. + */ + OTHER = 0x5 + } + + /** + * Defines the purpose of a texture + * + * This is a very difficult topic. Different 3D packages support different + * kinds of textures. For very common texture types, such as bumpmaps, the + * rendering results depend on implementation details in the rendering + * pipelines of these applications. Assimp loads all texture references from + * the model file and tries to determine which of the predefined texture + * types below is the best choice to match the original use of the texture + * as closely as possible. + * + * In content pipelines you'll usually define how textures have to be + * handled, and the artists working on models have to conform to this + * specification, regardless which 3D tool they're using. + */ + enum aiTextureType : uint { + /** + * No texture, but the value to be used for + * <code>aiMaterialProperty.mSemantic</code> for all material properties + * <em>not</em> related to textures. + */ + NONE = 0x0, + + /** + * The texture is combined with the result of the diffuse lighting + * equation. + */ + DIFFUSE = 0x1, + + /** + * The texture is combined with the result of the specular lighting + * equation. + */ + SPECULAR = 0x2, + + /** + * The texture is combined with the result of the ambient lighting + * equation. + */ + AMBIENT = 0x3, + + /** + * The texture is added to the result of the lighting calculation. It + * isn't influenced by incoming light. + */ + EMISSIVE = 0x4, + + /** + * The texture is a height map. + * + * By convention, higher grey-scale values stand for higher elevations + * from the base height. + */ + HEIGHT = 0x5, + + /** + * The texture is a (tangent space) normal-map. + * + * Again, there are several conventions for tangent-space normal maps. + * Assimp does (intentionally) not differenciate here. + */ + NORMALS = 0x6, + + /** + * The texture defines the glossiness of the material. + * + * The glossiness is in fact the exponent of the specular (phong) + * lighting equation. Usually there is a conversion function defined to + * map the linear color values in the texture to a suitable exponent. + */ + SHININESS = 0x7, + + /** + * The texture defines per-pixel opacity. + * + * Usually white means opaque and black means transparent. + */ + OPACITY = 0x8, + + /** + * Displacement texture. + * + * The exact purpose and format is application-dependent. Higher color + * values stand for higher vertex displacements. + */ + DISPLACEMENT = 0x9, + + /** + * Lightmap or ambient occlusion texture. + * + * Both lightmaps and dedicated ambient occlusion maps are covered by + * this material property. The texture contains a scaling value for the + * final color value of a pixel. Its intensity is not affected by + * incoming light. + */ + LIGHTMAP = 0xA, + + /** + * Reflection texture. + * + * Contains the color of a perfect mirror reflection. Rarely used, almost + * never for real-time applications. + */ + REFLECTION = 0xB, + + /** + * Unknown texture. + * + * A texture reference that does not match any of the definitions above is + * considered to be 'unknown'. It is still imported, but is excluded from + * any further postprocessing. + */ + UNKNOWN = 0xC + } + + /** + * Defines all shading models supported by the library + * + * The list of shading modes has been taken from Blender. See Blender + * documentation for more information. The API does not distinguish between + * "specular" and "diffuse" shaders (thus the specular term for diffuse + * shading models like Oren-Nayar remains undefined). + * + * Again, this value is just a hint. Assimp tries to select the shader whose + * most common implementation matches the original rendering results of the + * 3D modeller which wrote a particular model as closely as possible. + */ + enum aiShadingMode : uint { + /** + * Flat shading. + * + * Shading is done on per-face base diffuse only. Also known as + * »faceted shading«. + */ + Flat = 0x1, + + /** + * Simple Gouraud shading. + */ + Gouraud = 0x2, + + /** + * Phong-Shading. + */ + Phong = 0x3, + + /** + * Phong-Blinn-Shading. + */ + Blinn = 0x4, + + /** + * Per-pixel toon shading. + * + * Often referred to as »comic shading«. + */ + Toon = 0x5, + + /** + * Per-pixel Oren-Nayar shading. + * + * Extension to standard Lambertian shading, taking the roughness of the + * material into account. + */ + OrenNayar = 0x6, + + /** + * Per-pixel Minnaert shading. + * + * Extension to standard Lambertian shading, taking the "darkness" of the + * material into account. + */ + Minnaert = 0x7, + + /** + * Per-pixel Cook-Torrance shading. + * + * Special shader for metallic surfaces. + */ + CookTorrance = 0x8, + + /** + * No shading at all. + * + * Constant light influence of 1. + */ + NoShading = 0x9, + + /** + * Fresnel shading. + */ + Fresnel = 0xa + } + + /** + * Defines some mixed flags for a particular texture. + * + * Usually you'll instruct your cg artists how textures have to look like + * and how they will be processed in your application. However, if you use + * Assimp for completely generic loading purposes you might also need to + * process these flags in order to display as many 'unknown' 3D models as + * possible correctly. + * + * This corresponds to the <code>AI_MATKEY_TEXFLAGS</code> property. + */ + enum aiTextureFlags : uint { + /** + * The texture's color values have to be inverted (i.e. <code>1-n</code> + * component-wise). + */ + Invert = 0x1, + + /** + * Explicit request to the application to process the alpha channel of the + * texture. + * + * Mutually exclusive with <code>IgnoreAlpha</code>. These flags are + * set if the library can say for sure that the alpha channel is used/is + * not used. If the model format does not define this, it is left to the + * application to decide whether the texture alpha channel – if any – is + * evaluated or not. + */ + UseAlpha = 0x2, + + /** + * Explicit request to the application to ignore the alpha channel of the + * texture. + * + * Mutually exclusive with <code>UseAlpha</code>. + */ + IgnoreAlpha = 0x4 + } + + + /** + * Defines alpha-blend flags. + * + * If you're familiar with OpenGL or D3D, these flags aren't new to you. + * They define how the final color value of a pixel is computed, based on + * the previous color at that pixel and the new color value from the + * material. + * + * The basic blending formula is + * <code>SourceColor * SourceBlend + DestColor * DestBlend</code>, + * where <code>DestColor</code> is the previous color in the framebuffer at + * this position and <code>SourceColor</code> is the material color before + * the transparency calculation. + * + * This corresponds to the <code>AI_MATKEY_BLEND_FUNC</code> property. + */ + enum aiBlendMode :uint { + /** + * Formula: + * <code>SourceColor * SourceAlpha + DestColor * (1 - SourceAlpha)</code> + */ + Default = 0x0, + + /** + * Additive blending. + * + * Formula: <code>SourceColor*1 + DestColor*1</code> + */ + Additive = 0x1 + } + + /** + * Defines how an UV channel is transformed. + * + * This is just a helper structure for the <code>AI_MATKEY_UVTRANSFORM</code> + * key. See its documentation for more details. + */ + struct aiUVTransform { + align ( 1 ) : + /** + * Translation on the u and v axes. + * + * The default value is (0|0). + */ + aiVector2D mTranslation; + + /** + * Scaling on the u and v axes. + * + * The default value is (1|1). + */ + aiVector2D mScaling; + + /** + * Rotation - in counter-clockwise direction. + * + * The rotation angle is specified in radians. The rotation center is + * 0.5|0.5. The default value is 0. + */ + float mRotation; + } + + /** + * A very primitive RTTI system to store the data type of a material + * property. + */ + enum aiPropertyTypeInfo : uint { + /** + * Array of single-precision (32 bit) floats. + * + * It is possible to use <code>aiGetMaterialInteger[Array]()</code> to + * query properties stored in floating-point format. The material system + * performs the type conversion automatically. + */ + Float = 0x1, + + /** + * aiString property. + * + * Arrays of strings aren't possible, <code>aiGetMaterialString()</code> + * must be used to query a string property. + */ + String = 0x3, + + /** + * Array of (32 bit) integers. + * + * It is possible to use <code>aiGetMaterialFloat[Array]()</code> to + * query properties stored in integer format. The material system + * performs the type conversion automatically. + */ + Integer = 0x4, + + /** + * Simple binary buffer, content undefined. Not convertible to anything. + */ + Buffer = 0x5 + } + + /** + * Data structure for a single material property. + * + * As an user, you'll probably never need to deal with this data structure. + * Just use the provided <code>aiGetMaterialXXX()</code> functions to query + * material properties easily. Processing them manually is faster, but it is + * not the recommended way. It isn't worth the effort. + * + * Material property names follow a simple scheme: + * + * <code>$[name]</code>: A public property, there must be a corresponding + * AI_MATKEY_XXX constant. + * + * <code>?[name]</code>: Also public, but ignored by the + * <code>aiProcess.RemoveRedundantMaterials</code> post-processing step. + * + * <code>~[name]</code>: A temporary property for internal use. + */ + struct aiMaterialProperty { + /** + * Specifies the name of the property (key). + * + * Keys are generally case insensitive. + */ + aiString mKey; + + /** + * For texture properties, this specifies the exact usage semantic. + * + * For non-texture properties, this member is always 0 (or rather + * <code>aiTextureType.NONE</code>). + */ + uint mSemantic; + + /** + * For texture properties, this specifies the index of the texture. + * + * For non-texture properties, this member is always 0. + */ + uint mIndex; + + /** + * Size of the buffer <code>mData</code> is pointing to (in bytes). + * + * This value may not be 0. + */ + uint mDataLength; + + /** + * Type information for the property. + * + * Defines the data layout inside the data buffer. This is used by the + * library internally to perform debug checks and to utilize proper type + * conversions. + */ + aiPropertyTypeInfo mType; + + /** + * Binary buffer to hold the property's value. + * + * The size of the buffer is always <code>mDataLength</code>. + */ + char* mData; + } + + /** + * Data structure for a material + * + * Material data is stored using a key-value structure. A single key-value + * pair is called a <em>material property</em>. The properties can be + * queried using the <code>aiMaterialGetXXX</code> family of functions. The + * library defines a set of standard keys (AI_MATKEY_XXX). + */ + struct aiMaterial { + /** + * List of all material properties loaded. + */ + aiMaterialProperty** mProperties; + + /** + * Number of properties loaded. + */ + uint mNumProperties; + uint mNumAllocated; /// ditto + } + + /** + * Standard material property keys. Always pass 0 for texture type and index + * when querying these keys. + */ + const char* AI_MATKEY_NAME = "?mat.name"; + const char* AI_MATKEY_TWOSIDED = "$mat.twosided"; /// ditto + const char* AI_MATKEY_SHADING_MODEL = "$mat.shadingm"; /// ditto + const char* AI_MATKEY_ENABLE_WIREFRAME = "$mat.wireframe"; /// ditto + const char* AI_MATKEY_BLEND_FUNC = "$mat.blend"; /// ditto + const char* AI_MATKEY_OPACITY = "$mat.opacity"; /// ditto + const char* AI_MATKEY_BUMPSCALING = "$mat.bumpscaling"; /// ditto + const char* AI_MATKEY_SHININESS = "$mat.shininess"; /// ditto + const char* AI_MATKEY_REFLECTIVITY = "$mat.reflectivity"; /// ditto + const char* AI_MATKEY_SHININESS_STRENGTH = "$mat.shinpercent"; /// ditto + const char* AI_MATKEY_REFRACTI = "$mat.refracti"; /// ditto + const char* AI_MATKEY_COLOR_DIFFUSE = "$clr.diffuse"; /// ditto + const char* AI_MATKEY_COLOR_AMBIENT = "$clr.ambient"; /// ditto + const char* AI_MATKEY_COLOR_SPECULAR = "$clr.specular"; /// ditto + const char* AI_MATKEY_COLOR_EMISSIVE = "$clr.emissive"; /// ditto + const char* AI_MATKEY_COLOR_TRANSPARENT = "$clr.transparent"; /// ditto + const char* AI_MATKEY_COLOR_REFLECTIVE = "$clr.reflective"; /// ditto + const char* AI_MATKEY_GLOBAL_BACKGROUND_IMAGE = "?bg.global"; /// ditto + + /** + * Texture material property keys. Do not forget to specify texture type and + * index for these keys. + */ + const char* AI_MATKEY_TEXTURE = "$tex.file"; + const char* AI_MATKEY_UVWSRC = "$tex.uvwsrc"; /// ditto + const char* AI_MATKEY_TEXOP = "$tex.op"; /// ditto + const char* AI_MATKEY_MAPPING = "$tex.mapping"; /// ditto + const char* AI_MATKEY_TEXBLEND = "$tex.blend"; /// ditto + const char* AI_MATKEY_MAPPINGMODE_U = "$tex.mapmodeu"; /// ditto + const char* AI_MATKEY_MAPPINGMODE_V = "$tex.mapmodev"; /// ditto + const char* AI_MATKEY_TEXMAP_AXIS = "$tex.mapaxis"; /// ditto + const char* AI_MATKEY_UVTRANSFORM = "$tex.uvtrafo"; /// ditto + const char* AI_MATKEY_TEXFLAGS = "$tex.flags"; /// ditto +} diff --git a/libs/assimp/port/dAssimp/assimp/math.d b/libs/assimp/port/dAssimp/assimp/math.d new file mode 100644 index 0000000..057bbd5 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/math.d @@ -0,0 +1,155 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Mathematical structures in which the imported data is stored. + */ +module assimp.math; + +extern( C ) { + /** + * Represents a two-dimensional vector. + */ + struct aiVector2D { + align ( 1 ): + float x, y; + } + + /** + * Represents a three-dimensional vector. + */ + struct aiVector3D { + align ( 1 ): + float x, y, z; + } + + /** + * Represents a quaternion. + */ + struct aiQuaternion { + float w, x, y, z; + } + + /** + * Represents a row-major 3x3 matrix + * + * There is much confusion about matrix layouts (column vs. row order). This + * is <em>always</em> a row-major matrix, even when using the + * <code>ConvertToLeftHanded</code> post processing step. + */ + struct aiMatrix3x3 { + float a1, a2, a3; + float b1, b2, b3; + float c1, c2, c3; + } + + /** + * Represents a row-major 3x3 matrix + * + * There is much confusion about matrix layouts (column vs. row order). This + * is <em>always</em> a row-major matrix, even when using the + * <code>ConvertToLeftHanded</code> post processing step. + */ + struct aiMatrix4x4 { + align ( 1 ): + float a1, a2, a3, a4; + float b1, b2, b3, b4; + float c1, c2, c3, c4; + float d1, d2, d3, d4; + } + + /** + * Represents a plane in a three-dimensional, euclidean space + */ + struct aiPlane { + align ( 1 ): + /** + * Coefficients of the plane equation (<code>ax + by + cz = d</code>). + */ + float a; + float b; /// ditto + float c; /// ditto + float d; /// ditto + } + + /** + * Represents a ray. + */ + struct aiRay { + align ( 1 ): + /** + * Origin of the ray. + */ + aiVector3D pos; + + /** + * Direction of the ray. + */ + aiVector3D dir; + } + + /** + * Represents a color in RGB space. + */ + struct aiColor3D { + align ( 1 ): + /** + * Red, green and blue values. + */ + float r; + float g; /// ditto + float b; /// ditto + } + + /** + * Represents a color in RGB space including an alpha component. + */ + struct aiColor4D { + align ( 1 ): + /** + * Red, green, blue and alpha values. + */ + float r; + float g; /// ditto + float b; /// ditto + float a; /// ditto + } +} diff --git a/libs/assimp/port/dAssimp/assimp/mesh.d b/libs/assimp/port/dAssimp/assimp/mesh.d new file mode 100644 index 0000000..48162b7 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/mesh.d @@ -0,0 +1,465 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Contains the data structures in which the imported geometry is returned by + * Assimp. + */ +module assimp.mesh; + +import assimp.math; +import assimp.types; + +extern ( C ) { + /* + * These limits are required to match the settings Assimp was compiled + * against. Therefore, do not redefine them unless you build the library + * from source using the same definitions. + */ + + /** + * Maximum number of indices per face (polygon). + */ + const AI_MAX_FACE_INDICES = 0x7fff; + + /** + * Maximum number of indices per face (polygon). + */ + const AI_MAX_BONE_WEIGHTS = 0x7fffffff; + + /** + * Maximum number of vertices per mesh. + */ + const AI_MAX_VERTICES = 0x7fffffff; + + /** + * Maximum number of faces per mesh. + */ + const AI_MAX_FACES = 0x7fffffff; + + /** + * Supported number of vertex color sets per mesh. + */ + const AI_MAX_NUMBER_OF_COLOR_SETS = 0x4; + + /** + * Supported number of texture coord sets (UV(W) channels) per mesh. + */ + const AI_MAX_NUMBER_OF_TEXTURECOORDS = 0x4; + + + /** + * A single face in a mesh, referring to multiple vertices. + * + * If <code>mNumIndices</code> is 3, we call the face <em>triangle</em>, for + * for <code>mNumIndices > 3</code> it's called <em>polygon</em>. + * + * <code>aiMesh.mPrimitiveTypes</code> can be queried to quickly examine + * which types of primitive are actually present in a mesh. The + * <code>aiProcess.SortByPType</code> flag post-processing step splits + * meshes containing different primitive types (e.g. lines and triangles) in + * several "clean" submeshes. + * + * Furthermore, there is a configuration option + * (<code>AI_CONFIG_PP_SBP_REMOVE</code>) to force <code>SortByPType</code> + * to completely remove specific kinds of primitives from the imported scene. + * In many cases you'll probably want to set this setting to + * <code>aiPrimitiveType.LINE | aiPrimitiveType.POINT</code>. Together with + * the <code>aiProcess.Triangulate</code> flag you can then be sure that + * <code>mNumIndices</code> is always 3. + */ + struct aiFace { + /** + * Number of indices defining this face. + * + * The maximum value for this member is <code>AI_MAX_FACE_INDICES</code>. + */ + uint mNumIndices; + + /** + * Array of the indices defining the face. + * + * The size is given in <code>mNumIndices</code>. + */ + uint* mIndices; + } + + /** + * A single influence of a bone on a vertex. + */ + struct aiVertexWeight { + /** + * Index of the vertex which is influenced by the bone. + */ + uint mVertexId; + + /** + * The strength of the influence in the range <code>[0..1]</code>. + * + * The influence from all bones at one vertex sums up to 1. + */ + float mWeight; + } + + /** + * A single bone of a mesh. + * + * A bone has a name by which it can be found in the frame hierarchy and by + * which it can be addressed by animations. In addition it has a number of + * influences on vertices. + */ + struct aiBone { + /** + * The name of the bone. + */ + aiString mName; + + /** + * The number of vertices affected by this bone. + * + * The maximum value for this member is <code>AI_MAX_BONE_WEIGHTS</code>. + */ + uint mNumWeights; + + /** + * The vertices affected by this bone. + * + * This array is <code>mNumWeights</code> entries in size. + */ + aiVertexWeight* mWeights; + + /** + * Matrix that transforms from mesh space to bone space (in the bind + * pose). + */ + aiMatrix4x4 mOffsetMatrix; + } + + /** + * Enumerates the types of geometric primitives supported by Assimp. + * + * See: <code>aiFace</code>, <code>aiProcess.SortByPType</code>, + * <code>aiProcess.Triangulate</code>, + * <code>AI_CONFIG_PP_SBP_REMOVE</code>. + */ + enum aiPrimitiveType : uint { + /** A point primitive. + * + * This is just a single vertex in the virtual world, + * <code>aiFace</code> contains just one index for such a primitive. + */ + POINT = 0x1, + + /** A line primitive. + * + * This is a line defined through a start and an end position. + * <code>aiFace</code> contains exactly two indices for such a primitive. + */ + LINE = 0x2, + + /** A triangular primitive. + * + * A triangle consists of three indices. + */ + TRIANGLE = 0x4, + + /** A higher-level polygon with more than 3 edges. + * + * A triangle is a polygon, but in this context, polygon means + * "all polygons that are not triangles". The <code>Triangulate</code> + * post processing step is provided for your convenience, it splits all + * polygons in triangles (which are much easier to handle). + */ + POLYGON = 0x8 + } + + // Note: The AI_PRIMITIVE_TYPE_FOR_N_INDICES(n) macro from the C headers is + // missing since there is probably not much use for it when just reading + // scene files. + + /** + * NOT CURRENTLY IN USE. An AnimMesh is an attachment to an #aiMesh stores + * per-vertex animations for a particular frame. + * + * You may think of an <code>aiAnimMesh</code> as a `patch` for the host + * mesh, which replaces only certain vertex data streams at a particular + * time. + * + * Each mesh stores n attached attached meshes (<code>aiMesh.mAnimMeshes</code>). + * The actual relationship between the time line and anim meshes is + * established by #aiMeshAnim, which references singular mesh attachments + * by their ID and binds them to a time offset. + */ + struct aiAnimMesh { + /** + * Replacement for aiMesh.mVertices. + * + * If this array is non-null, it *must* contain mNumVertices entries. + * The corresponding array in the host mesh must be non-null as well - + * animation meshes may neither add or nor remove vertex components (if + * a replacement array is NULL and the corresponding source array is + * not, the source data is taken instead). + */ + aiVector3D* mVertices; + + /// Replacement for <code>aiMesh.mNormals</code>. + aiVector3D* mNormals; + + /// Replacement for <code>aiMesh.mTangents</code>. + aiVector3D* mTangents; + + /// Replacement for <code>aiMesh.mBitangents</code>. + aiVector3D* mBitangents; + + /// Replacement for <code>aiMesh.mColors</code>. + aiColor4D* mColors[ AI_MAX_NUMBER_OF_COLOR_SETS ]; + + /// Replacement for <code>aiMesh.mTextureCoords</code>. + aiVector3D* mTextureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; + + /** + * The number of vertices in the aiAnimMesh, and thus the length of all + * the member arrays. + * + * This has always the same value as the mNumVertices property in the + * corresponding aiMesh. It is duplicated here merely to make the length + * of the member arrays accessible even if the aiMesh is not known, e.g. + * from language bindings. + */ + uint mNumVertices; + } + + /** + * A mesh represents a geometry or model with a single material. + * + * It usually consists of a number of vertices and a series + * primitives/faces referencing the vertices. In addition there might be a + * series of bones, each of them addressing a number of vertices with a + * certain weight. Vertex data is presented in channels with each channel + * containing a single per-vertex information such as a set of texture + * coords or a normal vector. If a data pointer is non-null, the + * corresponding data stream is present. + * + * A mesh uses only a single material which is referenced by a material ID. + * + * Note: The <code>mPositions</code> member is usually not optional. + * However, vertex positions <em>could</em> be missing if the + * <code>AI_SCENE_FLAGS_INCOMPLETE</code> flag is set in + * <code>aiScene.mFlags</code>. + */ + struct aiMesh { + /** + * Bitwise combination of <code>aiPrimitiveType</code> members. + * + * This specifies which types of primitives are present in the mesh. + * The <code>SortByPrimitiveType</code> post processing step can be used + * to make sure the output meshes consist of one primitive type each. + */ + uint mPrimitiveTypes; + + /** + * The number of vertices in this mesh. + * + * This is also the size of all of the per-vertex data arrays. The + * maximum value for this member is <code>AI_MAX_VERTICES</code>. + */ + uint mNumVertices; + + /** + * The number of primitives (triangles, polygons, lines) in this mesh. + * + * This is also the size of the <code>mFaces</code> array. The maximum + * value for this member is <code>AI_MAX_FACES</code>. + */ + uint mNumFaces; + + /** + * Vertex positions. + * + * This array is always present in a mesh. The array is + * <code>mNumVertices</code> in size. + */ + aiVector3D* mVertices; + + /** + * Vertex normals. + * + * The array contains normalized vectors, null if not present. + * The array is <code>mNumVertices</code> in size. + * + * Normals are undefined for point and line primitives. A mesh + * consisting of points and lines only may not have normal vectors. + * Meshes with mixed primitive types (i.e. lines and triangles) may have + * normals, but the normals for vertices that are only referenced by + * point or line primitives are undefined and set to <code>QNAN</code>. + * + * Note: Normal vectors computed by Assimp are always unit-length. + * However, this needn't apply for normals that have been taken + * directly from the model file. + */ + aiVector3D* mNormals; + + /** + * Vertex tangents. + * + * The tangent of a vertex points in the direction of the positive x + * texture axis. The array contains normalized vectors, null if + * not present. The array is <code>mNumVertices</code> in size. + * + * A mesh consisting of points and lines only may not have normal + * vectors. Meshes with mixed primitive types (i.e. lines and triangles) + * may have normals, but the normals for vertices that are only + * referenced by point or line primitives are undefined and set to + * <code>QNAN</code>. + * + * Note: If the mesh contains tangents, it automatically also contains + * bitangents (the bitangent is just the cross product of tangent and + * normal vectors). + */ + aiVector3D* mTangents; + + /** + * Vertex bitangents. + * + * The bitangent of a vertex points in the direction of the positive Y + * texture axis. The array contains normalized vectors, null if not + * present. The array is <code>mNumVertices</code> in size. + * + * Note: If the mesh contains tangents, it automatically also contains + * bitangents. + */ + aiVector3D* mBitangents; + + /** + * Vertex color sets. + * + * A mesh may contain 0 to <code>AI_MAX_NUMBER_OF_COLOR_SETS</code> + * vertex colors per vertex. null if not present. + * + * Each array is <code>mNumVertices</code> in size if present. + */ + aiColor4D* mColors[ AI_MAX_NUMBER_OF_COLOR_SETS ]; + + /** + * Vertex texture coords, also known as UV channels. + * A mesh may contain 0 to <code>AI_MAX_NUMBER_OF_TEXTURECOORDS</code> + * per vertex. null if not present. + * + * Each array is <code>mNumVertices</code> in size. + */ + aiVector3D* mTextureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; + + /** + * Specifies the number of components for a given UV channel. + * + * Up to three channels are supported (UVW, for accessing volume or cube + * maps). If the value is 2 for a given channel <code>n</code>, the + * component <code>p.z</code> of <code>mTextureCoords[n][p]</code> is set + * to 0. If the value is 1 for a given channel, <code>p.y</code> is set + * to 0, too. If this value is 0, 2 should be assumed. + * + * Note: 4D coords are not supported. + */ + uint mNumUVComponents[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; + + /** + * The faces the mesh is contstructed from. + * + * Each face refers to a number of vertices by their indices. + * This array is always present in a mesh, its size is given + * in <code>mNumFaces</code>. If the + * <code>AI_SCENE_FLAGS_NON_VERBOSE_FORMAT</code> is <em>not</em> set, + * each face references an unique set of vertices. + */ + aiFace* mFaces; + + /** + * The number of bones this mesh contains. + * + * Can be 0, in which case the <code>mBones</code> array is null. + */ + uint mNumBones; + + /** + * The bones of this mesh. + * + * A bone consists of a name by which it can be found in the frame + * hierarchy and a set of vertex weights. + */ + aiBone** mBones; + + /** + * The material used by this mesh. + * + * A mesh does use only a single material. If an imported model uses + * multiple materials, the import splits up the mesh. Use this value as + * index into the scene's material list. + */ + uint mMaterialIndex; + + /** + * Name of the mesh. + * + * Meshes can be named, but this is not a requirement and leaving this + * field empty is totally fine. + * + * There are mainly three uses for mesh names: + * - Some formats name nodes and meshes independently. + * - Importers tend to split meshes up to meet the one-material-per-mesh + * requirement. Assigning the same (dummy) name to each of the result + * meshes aids the caller at recovering the original mesh partitioning. + * - Vertex animations refer to meshes by their names. + */ + aiString mName; + + /// NOT CURRENTLY IN USE. The number of attachment meshes. + uint mNumAnimMeshes; + + /** + * NOT CURRENTLY IN USE. Attachment meshes for this mesh, for vertex- + * based animation. + * + * Attachment meshes carry replacement data for some of the mesh's + * vertex components (usually positions, normals). + */ + aiAnimMesh** mAnimMeshes; + } +} diff --git a/libs/assimp/port/dAssimp/assimp/postprocess.d b/libs/assimp/port/dAssimp/assimp/postprocess.d new file mode 100644 index 0000000..343bb36 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/postprocess.d @@ -0,0 +1,597 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Definitions for import post processing steps. + */ +module assimp.postprocess; + +extern ( C ) { + /** + * Defines the flags for all possible post processing steps. + * + * See: <code>aiImportFile</code>, <code>aiImportFileEx</code> + */ + enum aiPostProcessSteps { + /** + * Calculates the tangents and bitangents for the imported meshes. + * + * Does nothing if a mesh does not have normals. You might want this post + * processing step to be executed if you plan to use tangent space + * calculations such as normal mapping applied to the meshes. There is a + * config setting, <code>AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE</code>, + * which allows you to specify a maximum smoothing angle for the + * algorithm. However, usually you will want to use the default value. + */ + CalcTangentSpace = 0x1, + + /** + * Identifies and joins identical vertex data sets within all imported + * meshes. + * + * After this step is run each mesh does contain only unique vertices + * anymore, so a vertex is possibly used by multiple faces. You usually + * want to use this post processing step. If your application deals with + * indexed geometry, this step is compulsory or you will just waste + * rendering time. <em>If this flag is not specified</em>, no vertices + * are referenced by more than one face and <em>no index buffer is + * required</em> for rendering. + */ + JoinIdenticalVertices = 0x2, + + /** + * Converts all the imported data to a left-handed coordinate space. + * + * By default the data is returned in a right-handed coordinate space + * which for example OpenGL prefers. In this space, +X points to the + * right, +Z points towards the viewer and and +Y points upwards. In the + * DirectX coordinate space +X points to the right, +Y points upwards and + * +Z points away from the viewer. + * + * You will probably want to consider this flag if you use Direct3D for + * rendering. The <code>ConvertToLeftHanded</code> flag supersedes this + * setting and bundles all conversions typically required for D3D-based + * applications. + */ + MakeLeftHanded = 0x4, + + /** + * Triangulates all faces of all meshes. + * + * By default the imported mesh data might contain faces with more than 3 + * indices. For rendering you'll usually want all faces to be triangles. + * This post processing step splits up all higher faces to triangles. + * Line and point primitives are <em>not</em> modified!. + * + * If you want »triangles only« with no other kinds of primitives, + * specify both <code>Triangulate</code> and <code>SortByPType</code> and + * ignore all point and line meshes when you process Assimp's output. + */ + Triangulate = 0x8, + + /** + * Removes some parts of the data structure (animations, materials, light + * sources, cameras, textures, vertex components). + * + * The components to be removed are specified in a separate configuration + * option, <code>AI_CONFIG_PP_RVC_FLAGS</code>. This is quite useful if + * you don't need all parts of the output structure. Especially vertex + * colors are rarely used today. + * + * Calling this step to remove unrequired stuff from the pipeline as + * early as possible results in an increased performance and a better + * optimized output data structure. + * + * This step is also useful if you want to force Assimp to recompute + * normals or tangents since the corresponding steps don't recompute them + * if they have already been loaded from the source asset. + * + * This flag is a poor one, mainly because its purpose is usually + * misunderstood. Consider the following case: a 3d model has been exported + * from a CAD app, it has per-face vertex colors. Because of the vertex + * colors (which are not even used by most apps), + * <code>JoinIdenticalVertices</code> cannot join vertices at the same + * position. By using this step, unneeded components are excluded as + * early as possible thus opening more room for internal optimzations. + */ + RemoveComponent = 0x10, + + /** + * Generates normals for all faces of all meshes. + * + * This is ignored if normals are already there at the time where this + * flag is evaluated. Model importers try to load them from the source + * file, so they are usually already there. Face normals are shared + * between all points of a single face, so a single point can have + * multiple normals, which, in other words, enforces the library to + * duplicate vertices in some cases. <code>JoinIdenticalVertices</code> + * is <em>useless</em> then. + * + * This flag may not be specified together with + * <code>GenSmoothNormals</code>. + */ + GenNormals = 0x20, + + /** + * Generates smooth normals for all vertices in the mesh. + * + * This is ignored if normals are already there at the time where this + * flag is evaluated. Model importers try to load them from the source file, so + * they are usually already there. + * + * There is a configuration option, + * <code>AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE</code> which allows you to + * specify an angle maximum for the normal smoothing algorithm. Normals + * exceeding this limit are not smoothed, resulting in a »hard« seam + * between two faces. Using a decent angle here (e.g. 80°) results in + * very good visual appearance. + */ + GenSmoothNormals = 0x40, + + /** + * Splits large meshes into smaller submeshes. + * + * This is quite useful for realtime rendering where the number of triangles + * which can be maximally processed in a single draw-call is usually limited + * by the video driver/hardware. The maximum vertex buffer is usually limited, + * too. Both requirements can be met with this step: you may specify both a + * triangle and vertex limit for a single mesh. + * + * The split limits can (and should!) be set through the + * <code>AI_CONFIG_PP_SLM_VERTEX_LIMIT</code> and + * <code>AI_CONFIG_PP_SLM_TRIANGLE_LIMIT</code> settings. The default + * values are <code>AI_SLM_DEFAULT_MAX_VERTICES</code> and + * <code>AI_SLM_DEFAULT_MAX_TRIANGLES</code>. + * + * Note that splitting is generally a time-consuming task, but not if + * there's nothing to split. The use of this step is recommended for most + * users. + */ + SplitLargeMeshes = 0x80, + + /** + * Removes the node graph and pre-transforms all vertices with the local + * transformation matrices of their nodes. + * + * The output scene does still contain nodes, however, there is only a + * root node with children, each one referencing only one mesh, each + * mesh referencing one material. For rendering, you can simply render + * all meshes in order, you don't need to pay attention to local + * transformations and the node hierarchy. Animations are removed during + * this step. + * + * This step is intended for applications that have no scenegraph. + * + * The step <em>can</em> cause some problems: if e.g. a mesh of the asset + * contains normals and another, using the same material index, does not, + * they will be brought together, but the first meshes's part of the + * normal list is zeroed. However, these artifacts are rare. + * + * Note: The <code>AI_CONFIG_PP_PTV_NORMALIZE</code> configuration + * property can be set to normalize the scene's spatial dimension + * to the -1...1 range. + */ + PreTransformVertices = 0x100, + + /** + * Limits the number of bones simultaneously affecting a single vertex to + * a maximum value. + * + * If any vertex is affected by more than that number of bones, the least + * important vertex weights are removed and the remaining vertex weights + * are renormalized so that the weights still sum up to 1. + * + * The default bone weight limit is 4 (<code>AI_LMW_MAX_WEIGHTS</code>), + * but you can use the <code>#AI_CONFIG_PP_LBW_MAX_WEIGHTS</code> setting + * to supply your own limit to the post processing step. + * + * If you intend to perform the skinning in hardware, this post processing + * step might be of interest for you. + */ + LimitBoneWeights = 0x200, + + /** + * Validates the imported scene data structure. + * + * This makes sure that all indices are valid, all animations and + * bones are linked correctly, all material references are correct, etc. + * + * It is recommended to capture Assimp's log output if you use this flag, + * so you can easily find ot what's actually wrong if a file fails the + * validation. The validator is quite rude and will find <em>all</em> + * inconsistencies in the data structure. + * + * Plugin developers are recommended to use it to debug their loaders. + * + * There are two types of validation failures: + * <ul> + * <li>Error: There's something wrong with the imported data. Further + * postprocessing is not possible and the data is not usable at all. + * The import fails, see <code>aiGetErrorString()</code> for the + * error message.</li> + * <li>Warning: There are some minor issues (e.g. 1000000 animation + * keyframes with the same time), but further postprocessing and use + * of the data structure is still safe. Warning details are written + * to the log file, <code>AI_SCENE_FLAGS_VALIDATION_WARNING</code> is + * set in <code>aiScene::mFlags</code></li> + * </ul> + * + * This post-processing step is not time-consuming. It's use is not + * compulsory, but recommended. + */ + ValidateDataStructure = 0x400, + + /** + * Reorders triangles for better vertex cache locality. + * + * The step tries to improve the ACMR (average post-transform vertex cache + * miss ratio) for all meshes. The implementation runs in O(n) and is + * roughly based on the 'tipsify' algorithm (see + * <tt>http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf</tt>). + * + * If you intend to render huge models in hardware, this step might + * be of interest for you. The <code>AI_CONFIG_PP_ICL_PTCACHE_SIZE</code> + * config setting can be used to fine-tune the cache optimization. + */ + ImproveCacheLocality = 0x800, + + /** + * Searches for redundant/unreferenced materials and removes them. + * + * This is especially useful in combination with the + * <code>PretransformVertices</code> and <code>OptimizeMeshes</code> + * flags. Both join small meshes with equal characteristics, but they + * can't do their work if two meshes have different materials. Because + * several material settings are always lost during Assimp's import + * filters, (and because many exporters don't check for redundant + * materials), huge models often have materials which are are defined + * several times with exactly the same settings. + * + * Several material settings not contributing to the final appearance of + * a surface are ignored in all comparisons; the material name is one of + * them. So, if you are passing additional information through the + * content pipeline (probably using »magic« material names), don't + * specify this flag. Alternatively take a look at the + * <code>AI_CONFIG_PP_RRM_EXCLUDE_LIST</code> setting. + */ + RemoveRedundantMaterials = 0x1000, + + /** + * This step tries to determine which meshes have normal vectors that are + * acing inwards. + * + * The algorithm is simple but effective: The bounding box of all + * vertices and their normals is compared against the volume of the + * bounding box of all vertices without their normals. This works well + * for most objects, problems might occur with planar surfaces. However, + * the step tries to filter such cases. + * + * The step inverts all in-facing normals. Generally it is recommended to + * enable this step, although the result is not always correct. + */ + FixInfacingNormals = 0x2000, + + /** + * This step splits meshes with more than one primitive type in + * homogeneous submeshes. + * + * The step is executed after the triangulation step. After the step + * returns, just one bit is set in <code>aiMesh.mPrimitiveTypes</code>. + * This is especially useful for real-time rendering where point and line + * primitives are often ignored or rendered separately. + * + * You can use the <code>AI_CONFIG_PP_SBP_REMOVE</code> option to + * specify which primitive types you need. This can be used to easily + * exclude lines and points, which are rarely used, from the import. + */ + SortByPType = 0x8000, + + /** + * This step searches all meshes for degenerated primitives and converts + * them to proper lines or points. + * + * A face is »degenerated« if one or more of its points are identical. + * To have the degenerated stuff not only detected and collapsed but also + * removed, try one of the following procedures: + * + * <b>1.</b> (if you support lines and points for rendering but don't + * want the degenerates) + * <ul> + * <li>Specify the <code>FindDegenerates</code> flag.</li> + * <li>Set the <code>AI_CONFIG_PP_FD_REMOVE</code> option to 1. This will + * cause the step to remove degenerated triangles from the import + * as soon as they're detected. They won't pass any further + * pipeline steps.</li> + * </ul> + * + * <b>2.</b>(if you don't support lines and points at all ...) + * <ul> + * <li>Specify the <code>FindDegenerates</code> flag.</li> + * <li>Specify the <code>SortByPType</code> flag. This moves line and + * point primitives to separate meshes.</li> + * <li>Set the <code>AI_CONFIG_PP_SBP_REMOVE</codet> option to + * <code>aiPrimitiveType_POINTS | aiPrimitiveType_LINES</code> + * to cause SortByPType to reject point and line meshes from the + * scene.</li> + * </ul> + * + * Note: Degenerated polygons are not necessarily bad and that's why + * they're not removed by default. There are several file formats + * which don't support lines or points. Some exporters bypass the + * format specification and write them as degenerated triangle + * instead. + */ + FindDegenerates = 0x10000, + + /** + * This step searches all meshes for invalid data, such as zeroed normal + * vectors or invalid UV coords and removes/fixes them. This is intended + * to get rid of some common exporter errors. + * + * This is especially useful for normals. If they are invalid, and the + * step recognizes this, they will be removed and can later be + * recomputed, e.g. by the <code>GenSmoothNormals</code> step. + * + * The step will also remove meshes that are infinitely small and reduce + * animation tracks consisting of hundreds if redundant keys to a single + * key. The <code>AI_CONFIG_PP_FID_ANIM_ACCURACY</code> config property + * decides the accuracy of the check for duplicate animation tracks. + */ + FindInvalidData = 0x20000, + + /** + * This step converts non-UV mappings (such as spherical or cylindrical + * mapping) to proper texture coordinate channels. + * + * Most applications will support UV mapping only, so you will probably + * want to specify this step in every case. Note tha Assimp is not always + * able to match the original mapping implementation of the 3d app which + * produced a model perfectly. It's always better to let the father app + * compute the UV channels, at least 3ds max, maja, blender, lightwave, + * modo, ... are able to achieve this. + * + * Note: If this step is not requested, you'll need to process the + * <code>AI_MATKEY_MAPPING</code> material property in order to + * display all assets properly. + */ + GenUVCoords = 0x40000, + + /** + * This step applies per-texture UV transformations and bakes them to + * stand-alone vtexture coordinate channelss. + * + * UV transformations are specified per-texture – see the + * <code>AI_MATKEY_UVTRANSFORM</code> material key for more information. + * This step processes all textures with transformed input UV coordinates + * and generates new (pretransformed) UV channel which replace the old + * channel. Most applications won't support UV transformations, so you + * will probably want to specify this step. + * + * Note: UV transformations are usually implemented in realtime apps by + * transforming texture coordinates at vertex shader stage with a 3x3 + * (homogenous) transformation matrix. + */ + TransformUVCoords = 0x80000, + + /** + * This step searches for duplicate meshes and replaces duplicates with + * references to the first mesh. + * + * This step takes a while, don't use it if you have no time. Its main + * purpose is to workaround the limitation that many export file formats + * don't support instanced meshes, so exporters need to duplicate meshes. + * This step removes the duplicates again. Please note that Assimp does + * currently not support per-node material assignment to meshes, which + * means that identical meshes with differnent materials are currently + * <em>not</em> joined, although this is planned for future versions. + */ + FindInstances = 0x100000, + + /** + * A postprocessing step to reduce the number of meshes. + * + * In fact, it will reduce the number of drawcalls. + * + * This is a very effective optimization and is recommended to be used + * together with <code>OptimizeGraph</code>, if possible. The flag is + * fully compatible with both <code>SplitLargeMeshes</code> and + * <code>SortByPType</code>. + */ + OptimizeMeshes = 0x200000, + + /** + * A postprocessing step to optimize the scene hierarchy. + * + * Nodes with no animations, bones, lights or cameras assigned are + * collapsed and joined. + * + * Node names can be lost during this step. If you use special tag nodes + * to pass additional information through your content pipeline, use the + * <code>AI_CONFIG_PP_OG_EXCLUDE_LIST</code> setting to specify a list of + * node names you want to be kept. Nodes matching one of the names in + * this list won't be touched or modified. + * + * Use this flag with caution. Most simple files will be collapsed to a + * single node, complex hierarchies are usually completely lost. That's + * note the right choice for editor environments, but probably a very + * effective optimization if you just want to get the model data, convert + * it to your own format and render it as fast as possible. + * + * This flag is designed to be used with <code>OptimizeMeshes</code> for + * best results. + * + * Note: »Crappy« scenes with thousands of extremely small meshes packed + * in deeply nested nodes exist for almost all file formats. + * <code>OptimizeMeshes</code> in combination with + * <code>OptimizeGraph</code> usually fixes them all and makes them + * renderable. + */ + OptimizeGraph = 0x400000, + + /** This step flips all UV coordinates along the y-axis and adjusts + * material settings and bitangents accordingly. + * + * Output UV coordinate system: + * <pre> 0y|0y ---------- 1x|0y + * | | + * | | + * | | + * 0x|1y ---------- 1x|1y</pre> + * You'll probably want to consider this flag if you use Direct3D for + * rendering. The <code>AI_PROCESS_CONVERT_TO_LEFT_HANDED</code> flag + * supersedes this setting and bundles all conversions typically required + * for D3D-based applications. + */ + FlipUVs = 0x800000, + + /** + * This step adjusts the output face winding order to be clockwise. + * + * The default face winding order is counter clockwise. + * + * Output face order: + * <pre> x2 + * + * x0 + * x1</pre> + */ + FlipWindingOrder = 0x1000000 + } + + /** + * Abbrevation for convenience. + */ + alias aiPostProcessSteps aiProcess; + + /** + * Shortcut flag for Direct3D-based applications. + * + * Combines the <code>MakeLeftHanded</code>, <code>FlipUVs</code> and + * <code>FlipWindingOrder</code> flags. The output data matches Direct3D's + * conventions: left-handed geometry, upper-left origin for UV coordinates + * and clockwise face order, suitable for CCW culling. + */ + const aiPostProcessSteps AI_PROCESS_CONVERT_TO_LEFT_HANDED = + aiProcess.MakeLeftHanded | + aiProcess.FlipUVs | + aiProcess.FlipWindingOrder; + + /** + * Default postprocess configuration optimizing the data for real-time rendering. + * + * Applications would want to use this preset to load models on end-user + * PCs, maybe for direct use in game. + * + * If you're using DirectX, don't forget to combine this value with + * the <code>ConvertToLeftHanded</code> step. If you don't support UV + * transformations in your application, apply the + * <code>TransformUVCoords</code> step, too. + * + * Note: Please take the time to read the doc for the steps enabled by this + * preset. Some of them offer further configurable properties, some of + * them might not be of use for you so it might be better to not specify + * them. + */ + const aiPostProcessSteps AI_PROCESS_PRESET_TARGET_REALTIME_FAST = + aiProcess.CalcTangentSpace | + aiProcess.GenNormals | + aiProcess.JoinIdenticalVertices | + aiProcess.Triangulate | + aiProcess.GenUVCoords | + aiProcess.SortByPType; + + /** + * Default postprocess configuration optimizing the data for real-time + * rendering. + * + * Unlike <code>AI_PROCESS_PRESET_TARGET_REALTIME_FAST</code>, this + * configuration performs some extra optimizations to improve rendering + * speed and to minimize memory usage. It could be a good choice for a + * level editor environment where import speed is not so important. + * + * If you're using DirectX, don't forget to combine this value with + * the <code>ConvertToLeftHanded</code> step. If you don't support UV + * transformations in your application, apply the + * <code>TransformUVCoords</code> step, too. + * + * Note: Please take the time to read the doc for the steps enabled by this + * preset. Some of them offer further configurable properties, some of + * them might not be of use for you so it might be better to not specify + * them. + */ + const aiPostProcessSteps AI_PROCESS_PRESET_TARGET_REALTIME_QUALITY = + aiProcess.CalcTangentSpace | + aiProcess.GenSmoothNormals | + aiProcess.JoinIdenticalVertices | + aiProcess.ImproveCacheLocality | + aiProcess.LimitBoneWeights | + aiProcess.RemoveRedundantMaterials | + aiProcess.SplitLargeMeshes | + aiProcess.Triangulate | + aiProcess.GenUVCoords | + aiProcess.SortByPType | + aiProcess.FindDegenerates | + aiProcess.FindInvalidData; + + /** + * Default postprocess configuration optimizing the data for real-time + * rendering. + * + * This preset enables almost every optimization step to achieve perfectly + * optimized data. It's your choice for level editor environments where + * import speed is not important. + * + * If you're using DirectX, don't forget to combine this value with + * the <code>ConvertToLeftHanded</code> step. If you don't support UV + * transformations in your application, apply the + * <code>TransformUVCoords</code> step, too. + * + * Note: Please take the time to read the doc for the steps enabled by this + * preset. Some of them offer further configurable properties, some of + * them might not be of use for you so it might be better to not specify + * them. + */ + const aiPostProcessSteps AI_PROCESS_PRESET_TARGET_REALTIME_MAX_QUALITY = + AI_PROCESS_PRESET_TARGET_REALTIME_QUALITY | + aiProcess.FindInstances | + aiProcess.ValidateDataStructure | + aiProcess.OptimizeMeshes; +} diff --git a/libs/assimp/port/dAssimp/assimp/scene.d b/libs/assimp/port/dAssimp/assimp/scene.d new file mode 100644 index 0000000..deee75a --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/scene.d @@ -0,0 +1,306 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Contains the data structures which store the hierarchy fo the imported data. + */ +module assimp.scene; + +import assimp.animation; +import assimp.camera; +import assimp.light; +import assimp.math; +import assimp.mesh; +import assimp.material; +import assimp.texture; +import assimp.types; + +extern ( C ) { + /** + * A node in the imported hierarchy. + * + * Each node has name, a parent node (except for the root node), a + * transformation relative to its parent and possibly several child nodes. + * Simple file formats don't support hierarchical structures, for these + * formats the imported scene does consist of only a single root node with + * no childs. + */ + struct aiNode { + /** + * The name of the node. + * + * The name might be empty (length of zero) but all nodes which need to + * be accessed afterwards by bones or animations are usually named. + * Multiple nodes may have the same name, but nodes which are accessed + * by bones (see <code>aiBone</code> and <code>aiMesh.mBones</code>) + * <em>must</em> be unique. + * + * Cameras and lights are assigned to a specific node name – if there are + * multiple nodes with this name, they are assigned to each of them. + * + * There are no limitations regarding the characters contained in this + * string. You should be able to handle stuff like whitespace, tabs, + * linefeeds, quotation marks, ampersands, … + */ + aiString mName; + + /** + * The transformation relative to the node's parent. + */ + aiMatrix4x4 mTransformation; + + /** + * Parent node. + * + * null if this node is the root node. + */ + aiNode* mParent; + + /** + * The number of child nodes of this node. + */ + uint mNumChildren; + + /** + * The child nodes of this node. + * + * null if <code>mNumChildren</code> is 0. + */ + aiNode** mChildren; + + /** + * The number of meshes of this node. + */ + int mNumMeshes; + + /** + * The meshes of this node. + * + * Each entry is an index for <code>aiScene.mMeshes</code>. + */ + uint* mMeshes; + } + + /** + * Flags which are combinated in <code>aiScene.mFlags</code> to store + * auxiliary information about the imported scene. + */ + enum aiSceneFlags : uint { + /** + * Specifies that the scene data structure that was imported is not + * complete. + * + * This flag bypasses some internal validations and allows the import of + * animation skeletons, material libraries or camera animation paths + * using Assimp. Most applications won't support such data. + */ + INCOMPLETE = 0x1, + + /** + * This flag is set by the validation post-processing step + * (<code>aiProcess.ValidateDS</code>) if the validation was successful. + * + * In a validated scene you can be sure that any cross references in the + * data structure (e.g. vertex indices) are valid. + */ + VALIDATED = 0x2, + + /** + * This flag is set by the validation post-processing step + * (<code>aiProcess.ValidateDS</code>) if the validation is successful + * but some issues have been found. + * + * This can for example mean that a texture that does not exist is + * referenced by a material or that the bone weights for a vertex don't + * sum to 1. In most cases you should still be able to use the import. + * + * This flag could be useful for applications which don't capture + * Assimp's log output. + */ + VALIDATION_WARNING = 0x4, + + /** + * This flag is currently only set by the + * <code>aiProcess.JoinIdenticalVertices</code> post-processing step. It + * indicates that the vertices of the output meshes aren't in the + * internal verbose format anymore. In the verbose format all vertices + * are unique, no vertex is ever referenced by more than one face. + */ + NON_VERBOSE_FORMAT = 0x8, + + /** + * Denotes pure height-map terrain data. Pure terrains usually consist of + * quads, sometimes triangles, in a regular grid. The x,y coordinates of + * all vertex positions refer to the x,y coordinates on the terrain + * height map, the z-axis stores the elevation at a specific point. + * + * TER (Terragen) and HMP (3D Game Studio) are height map formats. + * + * Note: Assimp is probably not the best choice for loading <em>huge</em> + * terrains – fully triangulated data takes extremely much storage + * space and should be avoided as long as possible (typically you will + * perform the triangulation when you actually need to render it). + */ + FLAGS_TERRAIN = 0x10 + } + + /** + * The root structure of the imported data. + * + * Everything that was imported from the given file can be accessed from here. + * Objects of this class are generally maintained and owned by Assimp, not + * by the caller. You shouldn't want to instance it, nor should you ever try to + * delete a given scene on your own. + */ + struct aiScene { + /** + * Any combination of the <code>aiSceneFlags</code>. By default, this + * value is 0, no flags are set. + * + * Most applications will want to reject all scenes with the + * <code>aiSceneFlags.INCOMPLETE</code> bit set. + */ + uint mFlags; + + /** + * The root node of the hierarchy. + * + * There will always be at least the root node if the import was + * successful (and no special flags have been set). Presence of further + * nodes depends on the format and contents of the imported file. + */ + aiNode* mRootNode; + + /** + * The number of meshes in the scene. + */ + uint mNumMeshes; + + /** + * The array of meshes. + * + * Use the indices given in the <code>aiNode</code> structure to access + * this array. The array is <code>mNumMeshes</code> in size. + * + * If the <code>aiSceneFlags.INCOMPLETE</code> flag is not set, there + * will always be at least one mesh. + */ + aiMesh** mMeshes; + + /** + * The number of materials in the scene. + */ + uint mNumMaterials; + + /** + * The array of meshes. + * + * Use the indices given in the <code>aiMesh</code> structure to access + * this array. The array is <code>mNumMaterials</code> in size. + * + * If the <code>aiSceneFlags.INCOMPLETE</code> flag is not set, there + * will always be at least one material. + */ + aiMaterial** mMaterials; + + /** + * The number of animations in the scene. + */ + uint mNumAnimations; + + /** + * The array of animations. + * + * All animations imported from the given file are listed here. The array + * is <code>mNumAnimations</code> in size. + */ + aiAnimation** mAnimations; + + /** + * The number of textures embedded into the file. + */ + uint mNumTextures; + + /** + * The array of embedded textures. + * + * Not many file formats embed their textures into the file. An example + * is Quake's <code>MDL</code> format (which is also used by some + * GameStudio versions). + */ + aiTexture** mTextures; + + /** + * The number of light sources in the scene. + * + * Light sources are fully optional, in most cases this attribute will be + * 0. + */ + uint mNumLights; + + /** + * The array of light sources. + * + * All light sources imported from the given file are listed here. The + * array is <code>mNumLights</code> in size. + */ + aiLight** mLights; + + /** + * The number of cameras in the scene. + * + * Cameras are fully optional, in most cases this attribute + * will be 0. + */ + uint mNumCameras; + + /** + * The array of cameras. + * + * All cameras imported from the given file are listed here. The array is + * <code>mNumCameras</code> in size. + * + * The first camera in the array (if existing) is the default camera view + * at the scene. + */ + aiCamera** mCameras; + } +} diff --git a/libs/assimp/port/dAssimp/assimp/texture.d b/libs/assimp/port/dAssimp/assimp/texture.d new file mode 100644 index 0000000..83453b9 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/texture.d @@ -0,0 +1,122 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Contains helper structures to handle textures in Assimp. + * + * Used for file formats which embed their textures into the model file. + * Supported are both normal textures, which are stored as uncompressed pixels, + * and "compressed" textures, which are stored in a file format such as PNG or + * TGA. + */ +module assimp.texture; + +extern ( C ) { + /** + * Helper structure to represent a texel in a ARGB8888 format. + * + * Used by aiTexture. + */ + struct aiTexel { + align ( 1 ): + ubyte b, g, r, a; + } + + /** + * Helper structure to describe an embedded texture. + * + * Usually textures are contained in external files but some file formats + * embed them directly in the model file. There are two types of + * embedded textures: + * + * <em>1. Uncompressed textures</em>: The color data is given in an + * uncompressed format. + * + * <em>2. Compressed textures</em> stored in a file format like PNG or JPEG. + * The raw file bytes are given so the application must utilize an image + * decoder (e.g. DevIL) to get access to the actual color data. + */ + struct aiTexture { + /** + * Width of the texture, in pixels. + * + * If <code>mHeight</code> is zero the texture is compressed in a format + * like JPEG. In this case, this value specifies the size of the memory + * area <code>pcData</code> is pointing to, in bytes. + */ + uint mWidth; + + /** + * Height of the texture, in pixels. + * + * If this value is zero, <code>pcData</code> points to an compressed + * texture in any format (e.g. JPEG). + */ + uint mHeight; + + /** + * A hint from the loader to make it easier for applications to determine + * the type of embedded compressed textures. + * + * If <code>mHeight</code> is not 0, this member is undefined. Otherwise + * it is set set to '\0\0\0\0' if the loader has no additional + * information about the texture file format used, or the file extension + * of the format without a trailing dot. If there are multiple file + * extensions for a format, the shortest extension is chosen (JPEG maps + * to 'jpg', not to 'jpeg'). E.g. 'dds\0', 'pcx\0', 'jpg\0'. All + * characters are lower-case. The fourth byte will always be '\0'. + */ + char achFormatHint[4]; + + /** + * Data of the texture. + * + * Points to an array of <code>mWidth * mHeight</code> + * <code>aiTexel</code>s. The format of the texture data is always + * ARGB8888 to make the implementation for user of the library as easy as + * possible. + * + * If <code>mHeight</code> is 0, this is a pointer to a memory buffer of + * size <code>mWidth</code> containing the compressed texture data. + */ + aiTexel* pcData; + } +} diff --git a/libs/assimp/port/dAssimp/assimp/types.d b/libs/assimp/port/dAssimp/assimp/types.d new file mode 100644 index 0000000..5aa4d54 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/types.d @@ -0,0 +1,249 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Contains miscellaneous types used in Assimp's C API. + */ +module assimp.types; + +extern ( C ) { + /** + * Our own C boolean type. + */ + enum aiBool : int { + FALSE = 0, + TRUE = 1 + } + + /** + * Type definition for log stream callback function pointers. + */ + alias void function( char* message, char* user ) aiLogStreamCallback; + + /** + * Represents a log stream. A log stream receives all log messages and + * streams them somewhere. + * + * See: <code>aiGetPredefinedLogStream</code>, + * <code>aiAttachLogStream</code> and <code>aiDetachLogStream</code>. + */ + struct aiLogStream { + /** + * Callback function to be called when a new message arrives. + */ + aiLogStreamCallback callback; + + /** + * User data to be passed to the callback. + */ + char* user; + } + + /** + * Maximum dimension for <code>aiString</code>s. + * + * Assimp strings are zero terminated. + */ + const size_t MAXLEN = 1024; + + /** + * Represents an UTF-8 string, zero byte terminated. + * + * The length of such a string is limited to <code>MAXLEN</code> bytes + * (excluding the terminal \0). + * + * The character set of an aiString is explicitly defined to be UTF-8. This + * Unicode transformation was chosen in the belief that most strings in 3d + * model files are limited to ASCII characters, thus the character set + * needed to be ASCII compatible. + * + * Most text file loaders provide proper Unicode input file handling, + * special unicode characters are correctly transcoded to UTF-8 and are kept + * throughout the libraries' import pipeline. + * + * For most applications, it will be absolutely sufficient to interpret the + * aiString as ASCII data and work with it as one would work with a plain + * char[]. + * + * To access an aiString from D you might want to use something like the + * following piece of code: + * --- + * char[] importAiString( aiString* s ) { + * return s.data[ 0 .. s.length ]; + * } + * --- + */ + struct aiString { + /** + * Length of the string (excluding the terminal \0). + * + * This is <em>not</em> the logical length of strings containing UTF-8 + * multibyte sequences, but the number of bytes from the beginning of the + * string to its end. + */ + size_t length; + + /** + * String buffer. + * + * Size limit is <code>MAXLEN</code>. + */ + char data[ MAXLEN ]; + } + + /** + * Standard return type for some library functions. + */ + enum aiReturn : uint { + /** + * Indicates that a function was successful. + */ + SUCCESS = 0x0, + + /** + * Indicates that a function failed. + */ + FAILURE = -0x1, + + /** + * Indicates that not enough memory was available to perform the + * requested operation. + */ + OUTOFMEMORY = -0x3 + } + + /** + * Seek origins (for the virtual file system API). + */ + enum aiOrigin : uint { + /** + * Beginning of the file. + */ + SET = 0x0, + + /** + * Current position of the file pointer. + */ + CUR = 0x1, + + /** + * End of the file. + * + * Offsets must be negative. + */ + END = 0x2 + } + + /** + * Enumerates predefined log streaming destinations. + * + * Logging to these streams can be enabled with a single call to + * <code>aiAttachPredefinedLogStream()</code>. + */ + enum aiDefaultLogStream :uint { + /** + * Stream the log to a file. + */ + FILE = 0x1, + + /** + * Stream the log to standard output. + */ + STDOUT = 0x2, + + /** + * Stream the log to standard error. + */ + STDERR = 0x4, + + /** + * MSVC only: Stream the log the the debugger (this relies on + * <code>OutputDebugString</code> from the Win32 SDK). + */ + DEBUGGER = 0x8 + } + + /** + * Stores the memory requirements for different components (e.g. meshes, + * materials, animations) of an import. All sizes are in bytes. + */ + struct aiMemoryInfo { + /** + * Storage allocated for texture data. + */ + uint textures; + + /** + * Storage allocated for material data. + */ + uint materials; + + /** + * Storage allocated for mesh data. + */ + uint meshes; + + /** + * Storage allocated for node data. + */ + uint nodes; + + /** + * Storage allocated for animation data. + */ + uint animations; + + /** + * Storage allocated for camera data. + */ + uint cameras; + + /** + * Storage allocated for light data. + */ + uint lights; + + /** + * Total storage allocated for the full import. + */ + uint total; + } +} diff --git a/libs/assimp/port/dAssimp/assimp/versionInfo.d b/libs/assimp/port/dAssimp/assimp/versionInfo.d new file mode 100644 index 0000000..5a7e9b9 --- /dev/null +++ b/libs/assimp/port/dAssimp/assimp/versionInfo.d @@ -0,0 +1,72 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, ASSIMP Development 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 Development 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. +--------------------------------------------------------------------------- +*/ + +/** + * Flags returned by <code>aiGetCompileFlags()</code>. + */ +module assimp.versionInfo; + +extern ( C ) { + /** + * Assimp was compiled as a shared object (Windows: DLL). + */ + const uint ASSIMP_CFLAGS_SHARED = 0x1; + + /** + * Assimp was compiled against STLport. + */ + const uint ASSIMP_CFLAGS_STLPORT = 0x2; + + /** + * Assimp was compiled as a debug build. + */ + const uint ASSIMP_CFLAGS_DEBUG = 0x4; + + /** + * Assimp was compiled with ASSIMP_BUILD_BOOST_WORKAROUND defined. + */ + const uint ASSIMP_CFLAGS_NOBOOST = 0x8; + + /** + * Assimp was compiled with ASSIMP_BUILD_SINGLETHREADED defined. + */ + const uint ASSIMP_CFLAGS_SINGLETHREADED = 0x10; +} diff --git a/libs/assimp/port/iOS/IPHONEOS_ARM64E_TOOLCHAIN.cmake b/libs/assimp/port/iOS/IPHONEOS_ARM64E_TOOLCHAIN.cmake new file mode 100644 index 0000000..0cf2b6b --- /dev/null +++ b/libs/assimp/port/iOS/IPHONEOS_ARM64E_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "arm64e") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneOS) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file diff --git a/libs/assimp/port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake b/libs/assimp/port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake new file mode 100644 index 0000000..0f476f1 --- /dev/null +++ b/libs/assimp/port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "arm64") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneOS) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file diff --git a/libs/assimp/port/iOS/IPHONEOS_ARMV6_TOOLCHAIN.cmake b/libs/assimp/port/iOS/IPHONEOS_ARMV6_TOOLCHAIN.cmake new file mode 100644 index 0000000..2f5d969 --- /dev/null +++ b/libs/assimp/port/iOS/IPHONEOS_ARMV6_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "armv6") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneOS) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file diff --git a/libs/assimp/port/iOS/IPHONEOS_ARMV7S_TOOLCHAIN.cmake b/libs/assimp/port/iOS/IPHONEOS_ARMV7S_TOOLCHAIN.cmake new file mode 100644 index 0000000..325d483 --- /dev/null +++ b/libs/assimp/port/iOS/IPHONEOS_ARMV7S_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "armv7s") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneOS) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file diff --git a/libs/assimp/port/iOS/IPHONEOS_ARMV7_TOOLCHAIN.cmake b/libs/assimp/port/iOS/IPHONEOS_ARMV7_TOOLCHAIN.cmake new file mode 100644 index 0000000..73087e0 --- /dev/null +++ b/libs/assimp/port/iOS/IPHONEOS_ARMV7_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "armv7") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneOS) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file diff --git a/libs/assimp/port/iOS/IPHONEOS_I386_TOOLCHAIN.cmake b/libs/assimp/port/iOS/IPHONEOS_I386_TOOLCHAIN.cmake new file mode 100644 index 0000000..dc35d37 --- /dev/null +++ b/libs/assimp/port/iOS/IPHONEOS_I386_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "i386") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneSimulator) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file diff --git a/libs/assimp/port/iOS/IPHONEOS_X86_64_TOOLCHAIN.cmake b/libs/assimp/port/iOS/IPHONEOS_X86_64_TOOLCHAIN.cmake new file mode 100644 index 0000000..a9ed2b8 --- /dev/null +++ b/libs/assimp/port/iOS/IPHONEOS_X86_64_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "x86_64") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneSimulator) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file diff --git a/libs/assimp/port/iOS/README.md b/libs/assimp/port/iOS/README.md new file mode 100644 index 0000000..ca5632a --- /dev/null +++ b/libs/assimp/port/iOS/README.md @@ -0,0 +1,39 @@ +# assimp for iOS +(deployment target 6.0+, 32/64bit) + +Builds assimp libraries for several iOS CPU architectures at once, and outputs a fat binary from the result. + +Run the **build.sh** script from the ```./port/iOS/``` directory. See **./build.sh --help** for information about command line options. + +```bash +shadeds-Mac:iOS arul$ ./build.sh --help +[!] ./build.sh - assimp iOS build script + - don't build fat library (--no-fat) + - supported architectures(--archs): armv7, armv7s, arm64, i386, x86_64 + - supported C++ STD libs.(--stdlib): libc++, libstdc++ +``` +Example: +```bash +cd ./port/iOS/ +./build.sh --stdlib=libc++ --archs="armv7 arm64 i386" +``` +Supported architectures/devices: + +### Simulator +- i386 +- x86_64 + +### Device +- ~~ARMv6 (dropped after iOS 6.0)~~ +- ARMv7 +- ARMv7-s +- ARM64 + +### Building with older iOS SDK versions +The script should work out of the box for the iOS 8.x SDKs and probably newer releases as well. +If you are using SDK version 7.x or older, you need to specify the exact SDK version inside **build.sh**, for example: +``` +IOS_SDK_VERSION=7.1 +``` +### Optimization +By default, no compiler optimizations are specified inside the build script. For an optimized build, add the corresponding flags to the CFLAGS definition inside **build.sh**. diff --git a/libs/assimp/port/iOS/build.sh b/libs/assimp/port/iOS/build.sh new file mode 100755 index 0000000..335b450 --- /dev/null +++ b/libs/assimp/port/iOS/build.sh @@ -0,0 +1,205 @@ +#!/bin/bash + +# +# Written and maintained by the.arul@gmail.com (2014) +# + +BUILD_DIR="./lib/iOS" + +################################### +# SDK Version +################################### +IOS_SDK_VERSION=$(xcodebuild -version -sdk iphoneos | grep SDKVersion | cut -f2 -d ':' | tr -d '[[:space:]]') +################################### + +################################### +# BUILD Configuration +################################### + +BUILD_SHARED_LIBS=OFF +BUILD_TYPE=Release + +################################################ +# Minimum iOS deployment target version +################################################ +MIN_IOS_VERSION="10.0" + +IOS_SDK_TARGET=$MIN_IOS_VERSION +XCODE_ROOT_DIR=$(xcode-select --print-path) +TOOLCHAIN=$XCODE_ROOT_DIR/Toolchains/XcodeDefault.xctoolchain + +CMAKE_C_COMPILER=$(xcrun -find cc) +CMAKE_CXX_COMPILER=$(xcrun -find c++) + +BUILD_ARCHS_DEVICE="arm64e arm64 armv7s armv7" +BUILD_ARCHS_SIMULATOR="x86_64 i386" +BUILD_ARCHS_ALL=($BUILD_ARCHS_DEVICE $BUILD_ARCHS_SIMULATOR) + +CPP_DEV_TARGET_LIST=(miphoneos-version-min mios-simulator-version-min) +CPP_DEV_TARGET= +CPP_STD_LIB_LIST=(libc++ libstdc++) +CPP_STD_LIB= +CPP_STD_LIST=(c++11 c++14) +CPP_STD=c++11 + +function join { local IFS="$1"; shift; echo "$*"; } + +build_arch() +{ + IOS_SDK_DEVICE=iPhoneOS + CPP_DEV_TARGET=${CPP_DEV_TARGET_LIST[0]} + + if [[ "$BUILD_ARCHS_SIMULATOR" =~ "$1" ]] + then + echo '[!] Target SDK set to SIMULATOR.' + IOS_SDK_DEVICE=iPhoneSimulator + CPP_DEV_TARGET=${CPP_DEV_TARGET_LIST[1]} + else + echo '[!] Target SDK set to DEVICE.' + fi + + unset DEVROOT SDKROOT CFLAGS LDFLAGS CPPFLAGS CXXFLAGS CMAKE_CLI_INPUT + + export CC="$(xcrun -sdk iphoneos -find clang)" + export CPP="$CC -E" + export DEVROOT=$XCODE_ROOT_DIR/Platforms/$IOS_SDK_DEVICE.platform/Developer + export SDKROOT=$DEVROOT/SDKs/$IOS_SDK_DEVICE$IOS_SDK_VERSION.sdk + export CFLAGS="-arch $1 -pipe -no-cpp-precomp -stdlib=$CPP_STD_LIB -isysroot $SDKROOT -I$SDKROOT/usr/include/ -miphoneos-version-min=$IOS_SDK_TARGET" + if [[ "$BUILD_TYPE" =~ "Debug" ]]; then + export CFLAGS="$CFLAGS -Og" + else + export CFLAGS="$CFLAGS -O3" + fi + export LDFLAGS="-arch $1 -isysroot $SDKROOT -L$SDKROOT/usr/lib/" + export CPPFLAGS="$CFLAGS" + export CXXFLAGS="$CFLAGS -std=$CPP_STD" + + rm CMakeCache.txt + + CMAKE_CLI_INPUT="-DCMAKE_C_COMPILER=$CMAKE_C_COMPILER -DCMAKE_CXX_COMPILER=$CMAKE_CXX_COMPILER -DCMAKE_TOOLCHAIN_FILE=./port/iOS/IPHONEOS_$(echo $1 | tr '[:lower:]' '[:upper:]')_TOOLCHAIN.cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DENABLE_BOOST_WORKAROUND=ON -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS" + + echo "[!] Running CMake with -G 'Unix Makefiles' $CMAKE_CLI_INPUT" + + cmake -G 'Unix Makefiles' ${CMAKE_CLI_INPUT} + + echo "[!] Building $1 library" + + xcrun -run make clean + xcrun -run make assimp -j 8 -l + + if [[ "$BUILD_SHARED_LIBS" =~ "ON" ]]; then + echo "[!] Moving built dynamic libraries into: $BUILD_DIR/$1/" + mv ./lib/*.dylib $BUILD_DIR/$1/ + fi + + echo "[!] Moving built static libraries into: $BUILD_DIR/$1/" + mv ./lib/*.a $BUILD_DIR/$1/ +} + +echo "[!] $0 - assimp iOS build script" + +CPP_STD_LIB=${CPP_STD_LIB_LIST[0]} +CPP_STD=${CPP_STD_LIST[0]} +DEPLOY_ARCHS=${BUILD_ARCHS_ALL[*]} +DEPLOY_FAT=1 + +for i in "$@"; do + case $i in + -s=*|--std=*) + CPP_STD=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` + echo "[!] Selecting c++ standard: $CPP_STD" + ;; + -l=*|--stdlib=*) + CPP_STD_LIB=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` + echo "[!] Selecting c++ std lib: $CPP_STD_LIB" + ;; + -a=*|--archs=*) + DEPLOY_ARCHS=`echo $i | sed 's/[-a-zA-Z0-9]*=//'` + echo "[!] Selecting architectures: $DEPLOY_ARCHS" + ;; + --debug) + BUILD_TYPE=Debug + echo "[!] Selecting build type: Debug" + ;; + --shared-lib) + BUILD_SHARED_LIBS=ON + echo "[!] Will generate dynamic libraries" + ;; + -n|--no-fat) + DEPLOY_FAT=0 + echo "[!] Fat binary will not be created." + ;; + -h|--help) + echo " - don't build fat library (--no-fat)." + echo " - Include debug information and symbols, no compiler optimizations (--debug)." + echo " - generate dynamic libraries rather than static ones (--shared-lib)." + echo " - supported architectures (--archs): $(echo $(join , ${BUILD_ARCHS_ALL[*]}) | sed 's/,/, /g')" + echo " - supported C++ STD libs (--stdlib): $(echo $(join , ${CPP_STD_LIB_LIST[*]}) | sed 's/,/, /g')" + echo " - supported C++ standards (--std): $(echo $(join , ${CPP_STD_LIST[*]}) | sed 's/,/, /g')" + exit + ;; + *) + ;; + esac +done + +cd ../../ +rm -rf $BUILD_DIR + +for ARCH_TARGET in $DEPLOY_ARCHS; do + echo "Creating folder: $BUILD_DIR/$ARCH_TARGET" + mkdir -p $BUILD_DIR/$ARCH_TARGET + echo "Building for arc: $ARCH_TARGET" + build_arch $ARCH_TARGET + #rm ./lib/libassimp.a +done + + +make_fat_static_or_shared_binary() +{ + LIB_NAME=$1 + LIPO_ARGS='' + for ARCH_TARGET in $DEPLOY_ARCHS; do + if [[ "$BUILD_SHARED_LIBS" =~ "ON" ]]; then + LIPO_ARGS="$LIPO_ARGS-arch $ARCH_TARGET $BUILD_DIR/$ARCH_TARGET/$LIB_NAME.dylib " + else + LIPO_ARGS="$LIPO_ARGS-arch $ARCH_TARGET $BUILD_DIR/$ARCH_TARGET/$LIB_NAME.a " + fi + done + if [[ "$BUILD_SHARED_LIBS" =~ "ON" ]]; then + LIPO_ARGS="$LIPO_ARGS -create -output $BUILD_DIR/$LIB_NAME-fat.dylib" + else + LIPO_ARGS="$LIPO_ARGS -create -output $BUILD_DIR/$LIB_NAME-fat.a" + fi + lipo $LIPO_ARGS +} + +make_fat_static_binary() +{ + LIB_NAME=$1 + LIPO_ARGS='' + for ARCH_TARGET in $DEPLOY_ARCHS; do + LIPO_ARGS="$LIPO_ARGS-arch $ARCH_TARGET $BUILD_DIR/$ARCH_TARGET/$LIB_NAME.a " + done + LIPO_ARGS="$LIPO_ARGS -create -output $BUILD_DIR/$LIB_NAME-fat.a" + lipo $LIPO_ARGS +} + +if [[ "$DEPLOY_FAT" -eq 1 ]]; then + echo '[+] Creating fat binaries ...' + + if [[ "$BUILD_TYPE" =~ "Debug" ]]; then + make_fat_static_or_shared_binary 'libassimpd' + make_fat_static_binary 'libIrrXMLd' + make_fat_static_binary 'libzlibstaticd' + else + make_fat_static_or_shared_binary 'libassimp' + make_fat_static_binary 'libIrrXML' + make_fat_static_binary 'libzlibstatic' + fi + + echo "[!] Done! The fat binaries can be found at $BUILD_DIR" +fi + + + diff --git a/libs/assimp/port/jassimp/README b/libs/assimp/port/jassimp/README new file mode 100644 index 0000000..a642f75 --- /dev/null +++ b/libs/assimp/port/jassimp/README @@ -0,0 +1,56 @@ +jassimp +------- + +Java binding for assimp. + +The class model used by jassimp is not a one-to-one mapping of assimps class/ +structure model (due to performance considerations). Please read the javadoc +descriptions of AiMesh and AiWrapperProvider. + +The jassimp.lwjgl package contains a LWJGL specific wrapper provider and some +application examples using this wrapper + + + +How To Build +------------ + + I) native library, for example by issuing this command in jassimp-native/src: + + $ gcc jassimp.cpp -I/usr/lib/jvm/default/include/ \ + -I/usr/lib/jvm/default/include/linux -lassimp -shared -fPIC -o libjassimp.so + + libjassimp.so is required at runtime and must be located in java.library.path. + +II) Java binding + The java library is built using ant. Executing "ant" in the port/jassimp + directory should be sufficient to build the library including docs. You + still need to build the native library separately, see above + + The java build is configured to create java 1.6 classes + + + +Limitations +----------- + +Not all data imports have been tested yet, especially the countless texture +parameters. If you find bugs please report them. + +jassimp supports most of assimps features. Current limitations are +* only importing scenes is supported. There are some methods that allow a + modification of the returned objects, but these should be considered as + work in progress. Full blown export support is planned for a future release +* no support for mesh animations +* no support for embedded textures +* no support for importer configurations +* some texture related material properties are not exposed via the API but only + accessible by traversing the list of properties. However this limitation is + also present in the c-API ... + + +License +------- + +The license for jassimp is the same as the main Assimp license. + diff --git a/libs/assimp/port/jassimp/build.xml b/libs/assimp/port/jassimp/build.xml new file mode 100644 index 0000000..1352e3f --- /dev/null +++ b/libs/assimp/port/jassimp/build.xml @@ -0,0 +1,54 @@ +<project name="jassimp" basedir="." default="all"> + <property name="native-src.dir" value="jassimp-native/src" /> + <property name="src.dir" value="jassimp/src" /> + <property name="jassimp.lwjgl-src.dir" value="jassimp.lwjgl/src" /> + <property name="build.dir" value="jassimp/bin" /> + <property name="dist.dir" value="dist" /> + <property name="doc.dir" value="doc" /> + <property environment="env"/> + <property name="ndk.dir" value="${env.NDK_HOME}" /> + <property name="my.dir" value="${env.PWD}" /> + + <path id="classpath"> + </path> + + <target name="compile"> + <delete dir="${build.dir}" /> + <mkdir dir="${build.dir}" /> + <javac classpathref="classpath" destdir="${build.dir}" srcdir="${src.dir}" + source="1.6" target="1.6" includeantruntime="false"> + </javac> + </target> + + <target name="jni_header"> + <mkdir dir="${native-src.dir}" /> + <javah outputfile="${native-src.dir}/jassimp.h" force="yes"> + <classpath> + <pathelement path="${build.dir}" /> + </classpath> + <class name="jassimp.Jassimp" /> + </javah> + </target> + + <target name="ndk-jni" depends="package"> + <exec executable="${ndk.dir}/ndk-build"> + <arg line="all NDK_PROJECT_PATH=${my.dir}/workspaces/Android-NDK"/> + </exec> + </target> + + <target name="package" depends="compile"> + <jar destfile="${dist.dir}/jassimp.jar" basedir="${build.dir}"> + </jar> + </target> + + + <target name="doc"> + <delete dir="${doc.dir}" /> + <javadoc access="public" author="false" destdir="${doc.dir}" + sourcepath="${src.dir}"> + </javadoc> + </target> + + <target name="all" depends="package, doc"> + </target> +</project> diff --git a/libs/assimp/port/jassimp/jassimp-native/Android.mk b/libs/assimp/port/jassimp/jassimp-native/Android.mk new file mode 100644 index 0000000..94b233b --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp-native/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := jassimp +LOCAL_SRC_FILES := src/jassimp.cpp + +LOCAL_CFLAGS += -DJNI_LOG + +#LOCAL_STATIC_LIBRARIES := assimp_static +LOCAL_SHARED_LIBRARIES := assimp +LOCAL_LDLIBS := -llog + +include $(BUILD_SHARED_LIBRARY) diff --git a/libs/assimp/port/jassimp/jassimp-native/src/jassimp.cpp b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.cpp new file mode 100644 index 0000000..6661ce9 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.cpp @@ -0,0 +1,1995 @@ +#include "jassimp.h" + +#include <assimp/Importer.hpp> +#include <assimp/ProgressHandler.hpp> +#include <assimp/scene.h> +#include <assimp/IOStream.hpp> +#include <assimp/IOSystem.hpp> + + +#ifdef JNI_LOG +#ifdef ANDROID +#include <android/log.h> +#define lprintf(...) __android_log_print(ANDROID_LOG_VERBOSE, __func__, __VA_ARGS__) +#else +#define lprintf(...) printf (__VA_ARGS__) +#endif /* ANDROID */ +#else +#define lprintf +#endif + +static std::string gLastErrorString; + +// Automatically deletes a local ref when it goes out of scope +class SmartLocalRef { +private: + JNIEnv* mJniEnv; + jobject& mJavaObj; + SmartLocalRef(const SmartLocalRef&); // non construction-copyable + SmartLocalRef& operator=(const SmartLocalRef&); // non copyable + +public: + template<class T> SmartLocalRef(JNIEnv* env, T& object) + : mJniEnv(env) + , mJavaObj((jobject&)object) + { + }; + + ~SmartLocalRef() { + if (mJavaObj != NULL) { + mJniEnv->DeleteLocalRef(mJavaObj); + } + } +}; + +static bool createInstance(JNIEnv *env, const char* className, jobject& newInstance) +{ + jclass clazz = env->FindClass(className); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", className); + return false; + } + + jmethodID ctr_id = env->GetMethodID(clazz, "<init>", "()V"); + + if (NULL == ctr_id) + { + lprintf("could not find no-arg constructor for class %s\n", className); + return false; + } + + newInstance = env->NewObject(clazz, ctr_id); + + if (NULL == newInstance) + { + lprintf("error calling no-arg constructor for class %s\n", className); + return false; + } + + return true; +} + + +static bool createInstance(JNIEnv *env, const char* className, const char* signature,/* const*/ jvalue* params, jobject& newInstance) +{ + jclass clazz = env->FindClass(className); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", className); + return false; + } + + jmethodID ctr_id = env->GetMethodID(clazz, "<init>", signature); + + if (NULL == ctr_id) + { + lprintf("could not find no-arg constructor for class %s\n", className); + return false; + } + + newInstance = env->NewObjectA(clazz, ctr_id, params); + + if (NULL == newInstance) + { + lprintf("error calling constructor for class %s, signature %s\n", className, signature); + return false; + } + + return true; +} + + +static bool getField(JNIEnv *env, jobject object, const char* fieldName, const char* signature, jobject& field) +{ + jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not get class for object\n"); + return false; + } + + jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature); + + if (NULL == fieldId) + { + lprintf("could not get field %s with signature %s\n", fieldName, signature); + return false; + } + + field = env->GetObjectField(object, fieldId); + + return true; +} + + +static bool setIntField(JNIEnv *env, jobject object, const char* fieldName, jint value) +{ + jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not get class for object\n"); + return false; + } + + jfieldID fieldId = env->GetFieldID(clazz, fieldName, "I"); + + if (NULL == fieldId) + { + lprintf("could not get field %s with signature I\n", fieldName); + return false; + } + + env->SetIntField(object, fieldId, value); + + return true; +} + + +static bool setFloatField(JNIEnv *env, jobject object, const char* fieldName, jfloat value) +{ + jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not get class for object\n"); + return false; + } + + jfieldID fieldId = env->GetFieldID(clazz, fieldName, "F"); + + if (NULL == fieldId) + { + lprintf("could not get field %s with signature F\n", fieldName); + return false; + } + + env->SetFloatField(object, fieldId, value); + + return true; +} + + +static bool setObjectField(JNIEnv *env, jobject object, const char* fieldName, const char* signature, jobject value) +{ + jclass clazz = env->GetObjectClass(object); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not get class for object\n"); + return false; + } + + jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature); + + if (NULL == fieldId) + { + lprintf("could not get field %s with signature %s\n", fieldName, signature); + return false; + } + + env->SetObjectField(object, fieldId, value); + + return true; +} + + +static bool getStaticField(JNIEnv *env, const char* className, const char* fieldName, const char* signature, jobject& field) +{ + jclass clazz = env->FindClass(className); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", className); + return false; + } + + jfieldID fieldId = env->GetStaticFieldID(clazz, fieldName, signature); + + if (NULL == fieldId) + { + lprintf("could not get field %s with signature %s\n", fieldName, signature); + return false; + } + + field = env->GetStaticObjectField(clazz, fieldId); + + return true; +} + + +static bool call(JNIEnv *env, jobject object, const char* typeName, const char* methodName, + const char* signature,/* const*/ jvalue* params) +{ + jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", typeName); + return false; + } + + jmethodID mid = env->GetMethodID(clazz, methodName, signature); + + if (NULL == mid) + { + lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName); + return false; + } + + jboolean jReturnValue = env->CallBooleanMethodA(object, mid, params); + + return (bool)jReturnValue; +} +static bool callv(JNIEnv *env, jobject object, const char* typeName, + const char* methodName, const char* signature,/* const*/ jvalue* params) { + jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) { + lprintf("could not find class %s\n", typeName); + return false; + } + + jmethodID mid = env->GetMethodID(clazz, methodName, signature); + + if (NULL == mid) { + lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName); + return false; + } + + env->CallVoidMethodA(object, mid, params); + + return true; +} + +static jobject callo(JNIEnv *env, jobject object, const char* typeName, const char* methodName, + const char* signature,/* const*/ jvalue* params) +{ + jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", typeName); + return NULL; + } + + jmethodID mid = env->GetMethodID(clazz, methodName, signature); + + if (NULL == mid) + { + lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName); + return NULL; + } + + jobject jReturnValue = env->CallObjectMethodA(object, mid, params); + + return jReturnValue; +} + +static int calli(JNIEnv *env, jobject object, const char* typeName, const char* methodName, + const char* signature) +{ + jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", typeName); + return false; + } + + jmethodID mid = env->GetMethodID(clazz, methodName, signature); + + if (NULL == mid) + { + lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName); + return false; + } + + jint jReturnValue = env->CallIntMethod(object, mid); + + return (int) jReturnValue; +} + +static int callc(JNIEnv *env, jobject object, const char* typeName, const char* methodName, + const char* signature) +{ + jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", typeName); + return false; + } + + jmethodID mid = env->GetMethodID(clazz, methodName, signature); + + if (NULL == mid) + { + lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName); + return false; + } + + jint jReturnValue = env->CallCharMethod(object, mid); + + return (int) jReturnValue; +} + + +static bool callStaticObject(JNIEnv *env, const char* typeName, const char* methodName, + const char* signature,/* const*/ jvalue* params, jobject& returnValue) +{ + jclass clazz = env->FindClass(typeName); + SmartLocalRef clazzRef(env, clazz); + + if (NULL == clazz) + { + lprintf("could not find class %s\n", typeName); + return false; + } + + jmethodID mid = env->GetStaticMethodID(clazz, methodName, signature); + + if (NULL == mid) + { + lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName); + return false; + } + + returnValue = env->CallStaticObjectMethodA(clazz, mid, params); + + return true; +} + + +static bool copyBuffer(JNIEnv *env, jobject jMesh, const char* jBufferName, void* cData, size_t size) +{ + jobject jBuffer = NULL; + SmartLocalRef bufferRef(env, jBuffer); + + if (!getField(env, jMesh, jBufferName, "Ljava/nio/ByteBuffer;", jBuffer)) + { + return false; + } + + if (env->GetDirectBufferCapacity(jBuffer) != size) + { + lprintf("invalid direct buffer, expected %u, got %llu\n", size, env->GetDirectBufferCapacity(jBuffer)); + return false; + } + + void* jBufferPtr = env->GetDirectBufferAddress(jBuffer); + + if (NULL == jBufferPtr) + { + lprintf("could not access direct buffer\n"); + return false; + } + + memcpy(jBufferPtr, cData, size); + + return true; +} + + +static bool copyBufferArray(JNIEnv *env, jobject jMesh, const char* jBufferName, int index, void* cData, size_t size) +{ + jobject jBufferArray = NULL; + SmartLocalRef bufferArrayRef(env, jBufferArray); + + if (!getField(env, jMesh, jBufferName, "[Ljava/nio/ByteBuffer;", jBufferArray)) + { + return false; + } + + jobject jBuffer = env->GetObjectArrayElement((jobjectArray) jBufferArray, index); + SmartLocalRef bufferRef(env, jBuffer); + + if (env->GetDirectBufferCapacity(jBuffer) != size) + { + lprintf("invalid direct buffer, expected %u, got %llu\n", size, env->GetDirectBufferCapacity(jBuffer)); + return false; + } + + void* jBufferPtr = env->GetDirectBufferAddress(jBuffer); + + if (NULL == jBufferPtr) + { + lprintf("could not access direct buffer\n"); + return false; + } + + memcpy(jBufferPtr, cData, size); + + return true; +} + +class JavaIOStream : public Assimp::IOStream +{ +private: + size_t pos; + size_t size; + char* buffer; + jobject jIOStream; + + +public: + JavaIOStream(size_t size, char* buffer, jobject jIOStream) : + pos(0), + size(size), + buffer(buffer), + jIOStream(jIOStream) + {}; + + + ~JavaIOStream(void) + { + free(buffer); + }; + + size_t Read(void* pvBuffer, size_t pSize, size_t pCount) + { + const size_t cnt = std::min(pCount,(size - pos)/pSize); + const size_t ofs = pSize*cnt; + + memcpy(pvBuffer, buffer + pos, ofs); + pos += ofs; + + return cnt; + }; + size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) + { + return 0; + }; + + aiReturn Seek(size_t pOffset, aiOrigin pOrigin) + { + if (aiOrigin_SET == pOrigin) { + if (pOffset >= size) { + return AI_FAILURE; + } + pos = pOffset; + } + else if (aiOrigin_END == pOrigin) { + if (pOffset >= size) { + return AI_FAILURE; + } + pos = size-pOffset; + } + else { + if (pOffset + pos >= size) { + return AI_FAILURE; + } + pos += pOffset; + } + return AI_SUCCESS; + }; + + size_t Tell(void) const + { + return pos; + }; + + size_t FileSize() const + { + return size; + }; + + void Flush() {}; + + + jobject javaObject() + { + return jIOStream; + }; + + +}; + + +class JavaIOSystem : public Assimp::IOSystem { + private: + JNIEnv* mJniEnv; + jobject& mJavaIOSystem; + + public: + JavaIOSystem(JNIEnv* env, jobject& javaIOSystem) : + mJniEnv(env), + mJavaIOSystem(javaIOSystem) + {}; + + bool Exists( const char* pFile) const + { + jvalue params[1]; + params[0].l = mJniEnv->NewStringUTF(pFile); + return call(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "exists", "(Ljava/lang/String;)Z", params); + + }; + char getOsSeparator() const + { + return (char) callc(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "getOsSeparator", "()C"); + }; + + Assimp::IOStream* Open(const char* pFile,const char* pMode = "rb") + { + jvalue params[2]; + params[0].l = mJniEnv->NewStringUTF(pFile); + params[1].l = mJniEnv->NewStringUTF(pMode); + + + jobject jStream = callo(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "open", "(Ljava/lang/String;Ljava/lang/String;)Ljassimp/AiIOStream;", params); + if(NULL == jStream) + { + lprintf("NULL object from AiIOSystem.open\n"); + return NULL; + } + + size_t size = calli(mJniEnv, jStream, "jassimp/AiIOStream", "getFileSize", "()I"); + lprintf("Model file size is %d\n", size); + + char* buffer = (char*)malloc(size); + jobject javaBuffer = mJniEnv->NewDirectByteBuffer(buffer, size); + + jvalue readParams[1]; + readParams[0].l = javaBuffer; + if(call(mJniEnv, jStream, "jassimp/AiIOStream", "read", "(Ljava/nio/ByteBuffer;)Z", readParams)) + { + return new JavaIOStream(size, buffer, jStream); + } + else + { + lprintf("Read failure on AiIOStream.read"); + free(buffer); + return NULL; + } + + }; + void Close( Assimp::IOStream* pFile) + { + + jvalue params[1]; + params[0].l = ((JavaIOStream*) pFile)->javaObject(); + callv(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "close", "(Ljassimp/AiIOStream;)V", params); + delete pFile; + }; + + + +}; + +class JavaProgressHandler : public Assimp::ProgressHandler { + private: + JNIEnv* mJniEnv; + jobject& mJavaProgressHandler; + + public: + JavaProgressHandler(JNIEnv* env, jobject& javaProgressHandler) : + mJniEnv(env), + mJavaProgressHandler(javaProgressHandler) + {}; + + bool Update(float percentage) + { + jvalue params[1]; + params[0].f = percentage; + return call(mJniEnv, mJavaProgressHandler, "jassimp/AiProgressHandler", "update", "(F)Z", params); + } +}; + +static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) +{ + for (unsigned int meshNr = 0; meshNr < cScene->mNumMeshes; meshNr++) + { + const aiMesh *cMesh = cScene->mMeshes[meshNr]; + + lprintf("converting mesh %s ...\n", cMesh->mName.C_Str()); + + /* create mesh */ + jobject jMesh = NULL; + SmartLocalRef refMesh(env, jMesh); + + if (!createInstance(env, "jassimp/AiMesh", jMesh)) + { + return false; + } + + + /* add mesh to m_meshes java.util.List */ + jobject jMeshes = NULL; + SmartLocalRef refMeshes(env, jMeshes); + + if (!getField(env, jScene, "m_meshes", "Ljava/util/List;", jMeshes)) + { + return false; + } + + jvalue addParams[1]; + addParams[0].l = jMesh; + if (!call(env, jMeshes, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams)) + { + return false; + } + + + /* set general mesh data in java */ + jvalue setTypesParams[1]; + setTypesParams[0].i = cMesh->mPrimitiveTypes; + if (!callv(env, jMesh, "jassimp/AiMesh", "setPrimitiveTypes", "(I)V", setTypesParams)) + { + return false; + } + + + if (!setIntField(env, jMesh, "m_materialIndex", cMesh->mMaterialIndex)) + { + return false; + } + + jstring nameString = env->NewStringUTF(cMesh->mName.C_Str()); + SmartLocalRef refNameString(env, nameString); + if (!setObjectField(env, jMesh, "m_name", "Ljava/lang/String;", nameString)) + { + return false; + } + + + /* determine face buffer size */ + bool isPureTriangle = cMesh->mPrimitiveTypes == aiPrimitiveType_TRIANGLE; + size_t faceBufferSize; + if (isPureTriangle) + { + faceBufferSize = cMesh->mNumFaces * 3 * sizeof(unsigned int); + } + else + { + int numVertexReferences = 0; + for (unsigned int face = 0; face < cMesh->mNumFaces; face++) + { + numVertexReferences += cMesh->mFaces[face].mNumIndices; + } + + faceBufferSize = numVertexReferences * sizeof(unsigned int); + } + + + /* allocate buffers - we do this from java so they can be garbage collected */ + jvalue allocateBuffersParams[4]; + allocateBuffersParams[0].i = cMesh->mNumVertices; + allocateBuffersParams[1].i = cMesh->mNumFaces; + allocateBuffersParams[2].z = isPureTriangle; + allocateBuffersParams[3].i = (jint) faceBufferSize; + if (!callv(env, jMesh, "jassimp/AiMesh", "allocateBuffers", "(IIZI)V", allocateBuffersParams)) + { + return false; + } + + + if (cMesh->mNumVertices > 0) + { + /* push vertex data to java */ + if (!copyBuffer(env, jMesh, "m_vertices", cMesh->mVertices, cMesh->mNumVertices * sizeof(aiVector3D))) + { + lprintf("could not copy vertex data\n"); + return false; + } + + lprintf(" with %u vertices\n", cMesh->mNumVertices); + } + + + /* push face data to java */ + if (cMesh->mNumFaces > 0) + { + if (isPureTriangle) + { + char* faceBuffer = (char*) malloc(faceBufferSize); + + size_t faceDataSize = 3 * sizeof(unsigned int); + for (unsigned int face = 0; face < cMesh->mNumFaces; face++) + { + memcpy(faceBuffer + face * faceDataSize, cMesh->mFaces[face].mIndices, faceDataSize); + } + + bool res = copyBuffer(env, jMesh, "m_faces", faceBuffer, faceBufferSize); + + free(faceBuffer); + + if (!res) + { + lprintf("could not copy face data\n"); + return false; + } + } + else + { + char* faceBuffer = (char*) malloc(faceBufferSize); + char* offsetBuffer = (char*) malloc(cMesh->mNumFaces * sizeof(unsigned int)); + + size_t faceBufferPos = 0; + for (unsigned int face = 0; face < cMesh->mNumFaces; face++) + { + size_t faceBufferOffset = faceBufferPos / sizeof(unsigned int); + memcpy(offsetBuffer + face * sizeof(unsigned int), &faceBufferOffset, sizeof(unsigned int)); + + size_t faceDataSize = cMesh->mFaces[face].mNumIndices * sizeof(unsigned int); + memcpy(faceBuffer + faceBufferPos, cMesh->mFaces[face].mIndices, faceDataSize); + faceBufferPos += faceDataSize; + } + + if (faceBufferPos != faceBufferSize) + { + /* this should really not happen */ + lprintf("faceBufferPos %u, faceBufferSize %u\n", faceBufferPos, faceBufferSize); + env->FatalError("error copying face data"); + exit(-1); + } + + + bool res = copyBuffer(env, jMesh, "m_faces", faceBuffer, faceBufferSize); + res &= copyBuffer(env, jMesh, "m_faceOffsets", offsetBuffer, cMesh->mNumFaces * sizeof(unsigned int)); + + free(faceBuffer); + free(offsetBuffer); + + if (!res) + { + lprintf("could not copy face data\n"); + return false; + } + } + + lprintf(" with %u faces\n", cMesh->mNumFaces); + } + + + /* push normals to java */ + if (cMesh->HasNormals()) + { + jvalue allocateDataChannelParams[2]; + allocateDataChannelParams[0].i = 0; + allocateDataChannelParams[1].i = 0; + if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams)) + { + lprintf("could not allocate normal data channel\n"); + return false; + } + if (!copyBuffer(env, jMesh, "m_normals", cMesh->mNormals, cMesh->mNumVertices * 3 * sizeof(float))) + { + lprintf("could not copy normal data\n"); + return false; + } + + lprintf(" with normals\n"); + } + + + /* push tangents to java */ + if (cMesh->mTangents != NULL) + { + jvalue allocateDataChannelParams[2]; + allocateDataChannelParams[0].i = 1; + allocateDataChannelParams[1].i = 0; + if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams)) + { + lprintf("could not allocate tangents data channel\n"); + return false; + } + if (!copyBuffer(env, jMesh, "m_tangents", cMesh->mTangents, cMesh->mNumVertices * 3 * sizeof(float))) + { + lprintf("could not copy tangents data\n"); + return false; + } + + lprintf(" with tangents\n"); + } + + + /* push bitangents to java */ + if (cMesh->mBitangents != NULL) + { + jvalue allocateDataChannelParams[2]; + allocateDataChannelParams[0].i = 2; + allocateDataChannelParams[1].i = 0; + if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams)) + { + lprintf("could not allocate bitangents data channel\n"); + return false; + } + if (!copyBuffer(env, jMesh, "m_bitangents", cMesh->mBitangents, cMesh->mNumVertices * 3 * sizeof(float))) + { + lprintf("could not copy bitangents data\n"); + return false; + } + + lprintf(" with bitangents\n"); + } + + + /* push color sets to java */ + for (int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; c++) + { + if (cMesh->mColors[c] != NULL) + { + jvalue allocateDataChannelParams[2]; + allocateDataChannelParams[0].i = 3; + allocateDataChannelParams[1].i = c; + if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams)) + { + lprintf("could not allocate colorset data channel\n"); + return false; + } + if (!copyBufferArray(env, jMesh, "m_colorsets", c, cMesh->mColors[c], cMesh->mNumVertices * 4 * sizeof(float))) + { + lprintf("could not copy colorset data\n"); + return false; + } + + lprintf(" with colorset[%d]\n", c); + } + } + + + /* push tex coords to java */ + for (int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; c++) + { + if (cMesh->mTextureCoords[c] != NULL) + { + jvalue allocateDataChannelParams[2]; + + switch (cMesh->mNumUVComponents[c]) + { + case 1: + allocateDataChannelParams[0].i = 4; + break; + case 2: + allocateDataChannelParams[0].i = 5; + break; + case 3: + allocateDataChannelParams[0].i = 6; + break; + default: + return false; + } + + allocateDataChannelParams[1].i = c; + if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams)) + { + lprintf("could not allocate texture coordinates data channel\n"); + return false; + } + + /* gather data */ + size_t coordBufferSize = cMesh->mNumVertices * cMesh->mNumUVComponents[c] * sizeof(float); + char* coordBuffer = (char*) malloc(coordBufferSize); + size_t coordBufferOffset = 0; + + for (unsigned int v = 0; v < cMesh->mNumVertices; v++) + { + memcpy(coordBuffer + coordBufferOffset, &cMesh->mTextureCoords[c][v], cMesh->mNumUVComponents[c] * sizeof(float)); + coordBufferOffset += cMesh->mNumUVComponents[c] * sizeof(float); + } + + if (coordBufferOffset != coordBufferSize) + { + /* this should really not happen */ + lprintf("coordBufferPos %u, coordBufferSize %u\n", coordBufferOffset, coordBufferSize); + env->FatalError("error copying coord data"); + exit(-1); + } + + bool res = copyBufferArray(env, jMesh, "m_texcoords", c, coordBuffer, coordBufferSize); + + free(coordBuffer); + + if (!res) + { + lprintf("could not copy texture coordinates data\n"); + return false; + } + + lprintf(" with %uD texcoord[%d]\n", cMesh->mNumUVComponents[c], c); + } + } + + + for (unsigned int b = 0; b < cMesh->mNumBones; b++) + { + aiBone *cBone = cMesh->mBones[b]; + + jobject jBone; + SmartLocalRef refBone(env, jBone); + if (!createInstance(env, "jassimp/AiBone", jBone)) + { + return false; + } + + /* add bone to bone list */ + jobject jBones = NULL; + SmartLocalRef refBones(env, jBones); + if (!getField(env, jMesh, "m_bones", "Ljava/util/List;", jBones)) + { + return false; + } + + jvalue addParams[1]; + addParams[0].l = jBone; + if (!call(env, jBones, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams)) + { + return false; + } + + /* set bone data */ + jstring boneNameString = env->NewStringUTF(cBone->mName.C_Str()); + SmartLocalRef refNameString(env, boneNameString); + if (!setObjectField(env, jBone, "m_name", "Ljava/lang/String;", boneNameString)) + { + return false; + } + + /* add bone weights */ + for (unsigned int w = 0; w < cBone->mNumWeights; w++) + { + jobject jBoneWeight; + SmartLocalRef refBoneWeight(env, jBoneWeight); + if (!createInstance(env, "jassimp/AiBoneWeight", jBoneWeight)) + { + return false; + } + + /* add boneweight to bone list */ + jobject jBoneWeights = NULL; + SmartLocalRef refBoneWeights(env, jBoneWeights); + if (!getField(env, jBone, "m_boneWeights", "Ljava/util/List;", jBoneWeights)) + { + return false; + } + + /* copy offset matrix */ + jfloatArray jMatrixArr = env->NewFloatArray(16); + SmartLocalRef refMatrixArr(env, jMatrixArr); + env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cBone->mOffsetMatrix); + + jvalue wrapParams[1]; + wrapParams[0].l = jMatrixArr; + jobject jMatrix; + SmartLocalRef refMatrix(env, jMatrix); + + if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapParams, jMatrix)) + { + return false; + } + + if (!setObjectField(env, jBone, "m_offsetMatrix", "Ljava/lang/Object;", jMatrix)) + { + return false; + } + + + jvalue addBwParams[1]; + addBwParams[0].l = jBoneWeight; + if (!call(env, jBoneWeights, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addBwParams)) + { + return false; + } + + + if (!setIntField(env, jBoneWeight, "m_vertexId", cBone->mWeights[w].mVertexId)) + { + return false; + } + + if (!setFloatField(env, jBoneWeight, "m_weight", cBone->mWeights[w].mWeight)) + { + return false; + } + } + } + } + + return true; +} + +static bool loadMetadata(JNIEnv *env, const aiNode* cNode, jobject& jNode) +{ + aiMetadata *cMetadata = cNode->mMetaData; + + for(unsigned i = 0; i<cMetadata->mNumProperties; i++) { + + aiString& metaDataKey = cMetadata->mKeys[i]; + void* cData = cMetadata->mValues[i].mData; + aiMetadataType cMetadataType = cMetadata->mValues[i].mType; + + jobject jAiMetadataEntry = NULL; + SmartLocalRef refMetadataEntry(env, jAiMetadataEntry); + + if(!createInstance(env, "jassimp/AiMetadataEntry", jAiMetadataEntry)) { + return false; + } + + jobject jAiMetadataTypeEnumValue = NULL; + SmartLocalRef refMetadataTypeEnumValue(env, jAiMetadataTypeEnumValue); + + jobject jMetadataData = NULL; + SmartLocalRef refMetadataData(env, jMetadataData); + + bool getMetadataTypeSuccess = false; + bool getMetadataDataSuccess = false; + + jvalue boxingMethodArgument[1]; + + jboolean exceptionThrown; + + switch (cMetadataType) { + + case AI_BOOL: { + getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_BOOL", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue); + boxingMethodArgument[0].z = (jboolean) *static_cast<bool*>(cData); + getMetadataDataSuccess = callStaticObject(env, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", boxingMethodArgument, jMetadataData); + break; + } + case AI_INT32: { + getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_INT32", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue); + boxingMethodArgument[0].i = (jint) *static_cast<int32_t*>(cData); + getMetadataDataSuccess = callStaticObject(env, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", boxingMethodArgument, jMetadataData); + break; + } + case AI_UINT64: { + getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_UINT64", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue); + boxingMethodArgument[0].j = (jlong) *static_cast<uint64_t*>(cData); + getMetadataDataSuccess = callStaticObject(env, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", boxingMethodArgument, jMetadataData); + break; + } + case AI_FLOAT: { + getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_FLOAT", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue); + boxingMethodArgument[0].f = (jfloat) *static_cast<float*>(cData); + getMetadataDataSuccess = callStaticObject(env, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", boxingMethodArgument, jMetadataData); + break; + } + case AI_DOUBLE: { + getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_DOUBLE", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue); + boxingMethodArgument[0].d = (jdouble) *static_cast<double*>(cData); + getMetadataDataSuccess = callStaticObject(env, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", boxingMethodArgument, jMetadataData); + break; + } + case AI_AISTRING: { + getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_AISTRING", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue); + jMetadataData = env->NewStringUTF(static_cast<aiString*>(cData)->C_Str()); + getMetadataDataSuccess = (jMetadataData != NULL); + break; + } + case AI_AIVECTOR3D: { + getMetadataTypeSuccess = getStaticField(env, "jassimp/AiMetadataEntry$AiMetadataType", "AI_AIVECTOR3D", + "Ljassimp/AiMetadataEntry$AiMetadataType;", + jAiMetadataTypeEnumValue); + jvalue wrapVec3Args[3]; + aiVector3D *vector3D = static_cast<aiVector3D *>(cData); + wrapVec3Args[0].f = vector3D->x; + wrapVec3Args[1].f = vector3D->y; + wrapVec3Args[2].f = vector3D->z; + getMetadataDataSuccess = callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", + wrapVec3Args, jMetadataData); + break; + } + default: { + getMetadataTypeSuccess = false; + getMetadataDataSuccess = false; + break; + } + } + + exceptionThrown = env->ExceptionCheck(); + + if(!getMetadataTypeSuccess || !getMetadataDataSuccess) { + if(exceptionThrown) + { + env->ExceptionDescribe(); + } + + return false; + } + + if(!setObjectField(env, jAiMetadataEntry, "mType", "Ljassimp/AiMetadataEntry$AiMetadataType;", jAiMetadataTypeEnumValue)) { + exceptionThrown = env->ExceptionCheck(); + + if(exceptionThrown) + { + env->ExceptionDescribe(); + } + + return false; + } + + if(!setObjectField(env, jAiMetadataEntry, "mData", "Ljava/lang/Object;", jMetadataData)) { + exceptionThrown = env->ExceptionCheck(); + + if(exceptionThrown) + { + env->ExceptionDescribe(); + } + + return false; + } + + jobject jNodeMetadata = NULL; + SmartLocalRef refMetadata(env, jNodeMetadata); + + if(!getField(env, jNode, "m_metaData", "Ljava/util/Map;", jNodeMetadata)) { + exceptionThrown = env->ExceptionCheck(); + + if(exceptionThrown) + { + env->ExceptionDescribe(); + } + + return false; + } + + jclass hashMapClass = env->FindClass("java/util/HashMap"); + jmethodID jHashMapPutMethod = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + jstring jKey = env->NewStringUTF(metaDataKey.C_Str()); + SmartLocalRef keyRef(env, jKey); + + // Only check exception instead of result here because maps will return + // null on success if they did not overwrite an existing mapping for the given key. + env->CallObjectMethod(jNodeMetadata, jHashMapPutMethod, jKey, jAiMetadataEntry); + + exceptionThrown = env->ExceptionCheck(); + + if(exceptionThrown) { + env->ExceptionDescribe(); + return false; + } + + } + + return true; +} + +static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobject* loadedNode = NULL) +{ + lprintf(" converting node %s ...\n", cNode->mName.C_Str()); + + /* wrap matrix */ + jfloatArray jMatrixArr = env->NewFloatArray(16); + SmartLocalRef refMatrixArr(env, jMatrixArr); + env->SetFloatArrayRegion(jMatrixArr, 0, 16, (jfloat*) &cNode->mTransformation); + + jvalue wrapMatParams[1]; + wrapMatParams[0].l = jMatrixArr; + jobject jMatrix; + SmartLocalRef refMatrix(env, jMatrix); + + if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapMatParams, jMatrix)) + { + return false; + } + + + /* create mesh references array */ + jintArray jMeshrefArr = env->NewIntArray(cNode->mNumMeshes); + SmartLocalRef refMeshrefArr(env, jMeshrefArr); + + jint *temp = (jint*) malloc(sizeof(jint) * cNode->mNumMeshes); + + for (unsigned int i = 0; i < cNode->mNumMeshes; i++) + { + temp[i] = cNode->mMeshes[i]; + } + env->SetIntArrayRegion(jMeshrefArr, 0, cNode->mNumMeshes, (jint*) temp); + + free(temp); + + + /* convert name */ + jstring jNodeName = env->NewStringUTF(cNode->mName.C_Str()); + SmartLocalRef refNodeName(env, jNodeName); + + /* wrap scene node */ + jvalue wrapNodeParams[4]; + wrapNodeParams[0].l = parent; + wrapNodeParams[1].l = jMatrix; + wrapNodeParams[2].l = jMeshrefArr; + wrapNodeParams[3].l = jNodeName; + jobject jNode; + if (!callStaticObject(env, "jassimp/Jassimp", "wrapSceneNode", + "(Ljava/lang/Object;Ljava/lang/Object;[ILjava/lang/String;)Ljava/lang/Object;", wrapNodeParams, jNode)) + { + return false; + } + + + /* and recurse */ + for (unsigned int c = 0; c < cNode->mNumChildren; c++) + { + if (!loadSceneNode(env, cNode->mChildren[c], jNode)) + { + return false; + } + } + + if (NULL != loadedNode) + { + if(cNode->mMetaData) { + if(!loadMetadata(env, cNode, jNode)) + { + return false; + } + } + + *loadedNode = jNode; + } else { + env->DeleteLocalRef(jNode); + } + + return true; +} + + +static bool loadSceneGraph(JNIEnv *env, const aiScene* cScene, jobject& jScene) +{ + lprintf("converting scene graph ...\n"); + + if (NULL != cScene->mRootNode) + { + jobject jRoot; + SmartLocalRef refRoot(env, jRoot); + + if (!loadSceneNode(env, cScene->mRootNode, NULL, &jRoot)) + { + return false; + } + + if (!setObjectField(env, jScene, "m_sceneRoot", "Ljava/lang/Object;", jRoot)) + { + return false; + } + } + + lprintf("converting scene graph finished\n"); + + return true; +} + + +static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene) +{ + for (unsigned int m = 0; m < cScene->mNumMaterials; m++) + { + const aiMaterial* cMaterial = cScene->mMaterials[m]; + + lprintf("converting material %d ...\n", m); + + jobject jMaterial = NULL; + SmartLocalRef refMaterial(env, jMaterial); + + if (!createInstance(env, "jassimp/AiMaterial", jMaterial)) + { + return false; + } + + /* add material to m_materials java.util.List */ + jobject jMaterials = NULL; + SmartLocalRef refMaterials(env, jMaterials); + + if (!getField(env, jScene, "m_materials", "Ljava/util/List;", jMaterials)) + { + return false; + } + + jvalue addMatParams[1]; + addMatParams[0].l = jMaterial; + if (!call(env, jMaterials, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addMatParams)) + { + return false; + } + + /* set texture numbers */ + for (int ttInd = aiTextureType_DIFFUSE; ttInd < aiTextureType_UNKNOWN; ttInd++) + { + aiTextureType tt = static_cast<aiTextureType>(ttInd); + + unsigned int num = cMaterial->GetTextureCount(tt); + + lprintf(" found %d textures of type %d ...\n", num, ttInd); + + jvalue setNumberParams[2]; + setNumberParams[0].i = ttInd; + setNumberParams[1].i = num; + + if (!callv(env, jMaterial, "jassimp/AiMaterial", "setTextureNumber", "(II)V", setNumberParams)) + { + return false; + } + } + + + for (unsigned int p = 0; p < cMaterial->mNumProperties; p++) + { + //printf("%s - %u - %u\n", cScene->mMaterials[m]->mProperties[p]->mKey.C_Str(), + // cScene->mMaterials[m]->mProperties[p]->mSemantic, + // cScene->mMaterials[m]->mProperties[p]->mDataLength); + + const aiMaterialProperty* cProperty = cMaterial->mProperties[p]; + + lprintf(" converting property %s ...\n", cProperty->mKey.C_Str()); + + jobject jProperty = NULL; + SmartLocalRef refProperty(env, jProperty); + + jvalue constructorParams[5]; + jstring keyString = env->NewStringUTF(cProperty->mKey.C_Str()); + SmartLocalRef refKeyString(env, keyString); + constructorParams[0].l = keyString; + constructorParams[1].i = cProperty->mSemantic; + constructorParams[2].i = cProperty->mIndex; + constructorParams[3].i = cProperty->mType; + + + /* special case conversion for color3 */ + if (NULL != strstr(cProperty->mKey.C_Str(), "clr") && + cProperty->mType == aiPTI_Float && + cProperty->mDataLength == 3 * sizeof(float)) + { + jobject jData = NULL; + SmartLocalRef refData(env, jData); + + /* wrap color */ + jvalue wrapColorParams[3]; + wrapColorParams[0].f = ((float*) cProperty->mData)[0]; + wrapColorParams[1].f = ((float*) cProperty->mData)[1]; + wrapColorParams[2].f = ((float*) cProperty->mData)[2]; + if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jData)) + { + return false; + } + + constructorParams[4].l = jData; + if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V", + constructorParams, jProperty)) + { + return false; + } + } + /* special case conversion for color4 */ + else if (NULL != strstr(cProperty->mKey.C_Str(), "clr") && + cProperty->mType == aiPTI_Float && + cProperty->mDataLength == 4 * sizeof(float)) + { + jobject jData = NULL; + SmartLocalRef refData(env, jData); + + /* wrap color */ + jvalue wrapColorParams[4]; + wrapColorParams[0].f = ((float*) cProperty->mData)[0]; + wrapColorParams[1].f = ((float*) cProperty->mData)[1]; + wrapColorParams[2].f = ((float*) cProperty->mData)[2]; + wrapColorParams[3].f = ((float*) cProperty->mData)[3]; + if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor4", "(FFFF)Ljava/lang/Object;", wrapColorParams, jData)) + { + return false; + } + + constructorParams[4].l = jData; + if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V", + constructorParams, jProperty)) + { + return false; + } + } + else if (cProperty->mType == aiPTI_Float && cProperty->mDataLength == sizeof(float)) + { + jobject jData = NULL; + SmartLocalRef refData(env, jData); + + jvalue newFloatParams[1]; + newFloatParams[0].f = ((float*) cProperty->mData)[0]; + if (!createInstance(env, "java/lang/Float", "(F)V", newFloatParams, jData)) + { + return false; + } + + constructorParams[4].l = jData; + if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V", + constructorParams, jProperty)) + { + return false; + } + } + else if (cProperty->mType == aiPTI_Integer && cProperty->mDataLength == sizeof(int)) + { + jobject jData = NULL; + SmartLocalRef refData(env, jData); + + jvalue newIntParams[1]; + newIntParams[0].i = ((int*) cProperty->mData)[0]; + if (!createInstance(env, "java/lang/Integer", "(I)V", newIntParams, jData)) + { + return false; + } + + constructorParams[4].l = jData; + if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V", + constructorParams, jProperty)) + { + return false; + } + } + else if (cProperty->mType == aiPTI_String) + { + /* skip length prefix */ + jobject jData = env->NewStringUTF(cProperty->mData + 4); + SmartLocalRef refData(env, jData); + + constructorParams[4].l = jData; + if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIILjava/lang/Object;)V", + constructorParams, jProperty)) + { + return false; + } + } + else + { + constructorParams[4].i = cProperty->mDataLength; + + /* generic copy code, uses dump ByteBuffer on java side */ + if (!createInstance(env, "jassimp/AiMaterial$Property", "(Ljava/lang/String;IIII)V", constructorParams, jProperty)) + { + return false; + } + + jobject jBuffer = NULL; + SmartLocalRef refBuffer(env, jBuffer); + if (!getField(env, jProperty, "m_data", "Ljava/lang/Object;", jBuffer)) + { + return false; + } + + if (env->GetDirectBufferCapacity(jBuffer) != cProperty->mDataLength) + { + lprintf("invalid direct buffer\n"); + return false; + } + + void* jBufferPtr = env->GetDirectBufferAddress(jBuffer); + + if (NULL == jBufferPtr) + { + lprintf("could not access direct buffer\n"); + return false; + } + + memcpy(jBufferPtr, cProperty->mData, cProperty->mDataLength); + } + + + /* add property */ + jobject jProperties = NULL; + SmartLocalRef refProperties(env, jProperties); + if (!getField(env, jMaterial, "m_properties", "Ljava/util/List;", jProperties)) + { + return false; + } + + jvalue addPropParams[1]; + addPropParams[0].l = jProperty; + if (!call(env, jProperties, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addPropParams)) + { + return false; + } + } + } + + lprintf("materials finished\n"); + + return true; +} + + +static bool loadAnimations(JNIEnv *env, const aiScene* cScene, jobject& jScene) +{ + lprintf("converting %d animations ...\n", cScene->mNumAnimations); + + for (unsigned int a = 0; a < cScene->mNumAnimations; a++) + { + const aiAnimation *cAnimation = cScene->mAnimations[a]; + + lprintf(" converting animation %s ...\n", cAnimation->mName.C_Str()); + + jobject jAnimation; + SmartLocalRef refAnimation(env, jAnimation); + + jvalue newAnimParams[3]; + jstring nameString = env->NewStringUTF(cAnimation->mName.C_Str()); + SmartLocalRef refNameString(env, nameString); + newAnimParams[0].l = nameString; + newAnimParams[1].d = cAnimation->mDuration; + newAnimParams[2].d = cAnimation->mTicksPerSecond; + + if (!createInstance(env, "jassimp/AiAnimation", "(Ljava/lang/String;DD)V", newAnimParams, jAnimation)) + { + return false; + } + + /* add animation to m_animations java.util.List */ + jobject jAnimations = NULL; + SmartLocalRef refAnimations(env, jAnimations); + + if (!getField(env, jScene, "m_animations", "Ljava/util/List;", jAnimations)) + { + return false; + } + + jvalue addParams[1]; + addParams[0].l = jAnimation; + if (!call(env, jAnimations, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams)) + { + return false; + } + + + for (unsigned int c = 0; c < cAnimation->mNumChannels; c++) + { + const aiNodeAnim *cNodeAnim = cAnimation->mChannels[c]; + + jobject jNodeAnim; + SmartLocalRef refNodeAnim(env, jNodeAnim); + + jvalue newNodeAnimParams[6]; + jstring animationName = env->NewStringUTF(cNodeAnim->mNodeName.C_Str()); + SmartLocalRef refAnimationName(env, animationName); + newNodeAnimParams[0].l = animationName; + newNodeAnimParams[1].i = cNodeAnim->mNumPositionKeys; + newNodeAnimParams[2].i = cNodeAnim->mNumRotationKeys; + newNodeAnimParams[3].i = cNodeAnim->mNumScalingKeys; + newNodeAnimParams[4].i = cNodeAnim->mPreState; + newNodeAnimParams[5].i = cNodeAnim->mPostState; + + if (!createInstance(env, "jassimp/AiNodeAnim", "(Ljava/lang/String;IIIII)V", newNodeAnimParams, jNodeAnim)) + { + return false; + } + + + /* add nodeanim to m_animations java.util.List */ + jobject jNodeAnims = NULL; + SmartLocalRef refNodeAnims(env, jNodeAnims); + + if (!getField(env, jAnimation, "m_nodeAnims", "Ljava/util/List;", jNodeAnims)) + { + return false; + } + + jvalue addParams[1]; + addParams[0].l = jNodeAnim; + if (!call(env, jNodeAnims, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams)) + { + return false; + } + + /* copy keys */ + if (!copyBuffer(env, jNodeAnim, "m_posKeys", cNodeAnim->mPositionKeys, + cNodeAnim->mNumPositionKeys * sizeof(aiVectorKey))) + { + return false; + } + + if (!copyBuffer(env, jNodeAnim, "m_rotKeys", cNodeAnim->mRotationKeys, + cNodeAnim->mNumRotationKeys * sizeof(aiQuatKey))) + { + return false; + } + + if (!copyBuffer(env, jNodeAnim, "m_scaleKeys", cNodeAnim->mScalingKeys, + cNodeAnim->mNumScalingKeys * sizeof(aiVectorKey))) + { + return false; + } + } + } + + lprintf("converting animations finished\n"); + + return true; +} + + +static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene) +{ + lprintf("converting %d lights ...\n", cScene->mNumLights); + + for (unsigned int l = 0; l < cScene->mNumLights; l++) + { + const aiLight *cLight = cScene->mLights[l]; + + lprintf("converting light %s ...\n", cLight->mName.C_Str()); + + /* wrap color nodes */ + jvalue wrapColorParams[3]; + wrapColorParams[0].f = cLight->mColorDiffuse.r; + wrapColorParams[1].f = cLight->mColorDiffuse.g; + wrapColorParams[2].f = cLight->mColorDiffuse.b; + jobject jDiffuse; + SmartLocalRef refDiffuse(env, jDiffuse); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jDiffuse)) + { + return false; + } + + wrapColorParams[0].f = cLight->mColorSpecular.r; + wrapColorParams[1].f = cLight->mColorSpecular.g; + wrapColorParams[2].f = cLight->mColorSpecular.b; + jobject jSpecular; + SmartLocalRef refSpecular(env, jSpecular); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jSpecular)) + { + return false; + } + + wrapColorParams[0].f = cLight->mColorAmbient.r; + wrapColorParams[1].f = cLight->mColorAmbient.g; + wrapColorParams[2].f = cLight->mColorAmbient.b; + jobject jAmbient; + SmartLocalRef refAmbient(env, jAmbient); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jAmbient)) + { + return false; + } + + + /* wrap vec3 nodes */ + jvalue wrapVec3Params[3]; + wrapVec3Params[0].f = cLight->mPosition.x; + wrapVec3Params[1].f = cLight->mPosition.y; + wrapVec3Params[2].f = cLight->mPosition.z; + jobject jPosition; + SmartLocalRef refPosition(env, jPosition); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jPosition)) + { + return false; + } + + wrapVec3Params[0].f = cLight->mPosition.x; + wrapVec3Params[1].f = cLight->mPosition.y; + wrapVec3Params[2].f = cLight->mPosition.z; + jobject jDirection; + SmartLocalRef refDirection(env, jDirection); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jDirection)) + { + return false; + } + + + jobject jLight; + SmartLocalRef refLight(env, jLight); + jvalue params[12]; + jstring lightName = env->NewStringUTF(cLight->mName.C_Str()); + SmartLocalRef refLightName(env, lightName); + params[0].l = lightName; + params[1].i = cLight->mType; + params[2].l = jPosition; + params[3].l = jDirection; + params[4].f = cLight->mAttenuationConstant; + params[5].f = cLight->mAttenuationLinear; + params[6].f = cLight->mAttenuationQuadratic; + params[7].l = jDiffuse; + params[8].l = jSpecular; + params[9].l = jAmbient; + params[10].f = cLight->mAngleInnerCone; + params[11].f = cLight->mAngleOuterCone; + + if (!createInstance(env, "jassimp/AiLight", "(Ljava/lang/String;ILjava/lang/Object;Ljava/lang/Object;FFFLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;FF)V", + params, jLight)) + { + return false; + } + + /* add light to m_lights java.util.List */ + jobject jLights = NULL; + SmartLocalRef refLights(env, jLights); + + if (!getField(env, jScene, "m_lights", "Ljava/util/List;", jLights)) + { + return false; + } + + jvalue addParams[1]; + addParams[0].l = jLight; + if (!call(env, jLights, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams)) + { + return false; + } + } + + lprintf("converting lights finished ...\n"); + + return true; +} + + +static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene) +{ + lprintf("converting %d cameras ...\n", cScene->mNumCameras); + + for (unsigned int c = 0; c < cScene->mNumCameras; c++) + { + const aiCamera *cCamera = cScene->mCameras[c]; + + lprintf("converting camera %s ...\n", cCamera->mName.C_Str()); + + /* wrap color nodes */ + jvalue wrapPositionParams[3]; + wrapPositionParams[0].f = cCamera->mPosition.x; + wrapPositionParams[1].f = cCamera->mPosition.y; + wrapPositionParams[2].f = cCamera->mPosition.z; + jobject jPosition; + SmartLocalRef refPosition(env, jPosition); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jPosition)) + { + return false; + } + + wrapPositionParams[0].f = cCamera->mUp.x; + wrapPositionParams[1].f = cCamera->mUp.y; + wrapPositionParams[2].f = cCamera->mUp.z; + jobject jUp; + SmartLocalRef refUp(env, jUp); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jUp)) + { + return false; + } + + wrapPositionParams[0].f = cCamera->mLookAt.x; + wrapPositionParams[1].f = cCamera->mLookAt.y; + wrapPositionParams[2].f = cCamera->mLookAt.z; + jobject jLookAt; + SmartLocalRef refLookAt(env, jLookAt); + if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jLookAt)) + { + return false; + } + + + jobject jCamera; + SmartLocalRef refCamera(env, jCamera); + + jvalue params[8]; + jstring cameraName = env->NewStringUTF(cCamera->mName.C_Str()); + SmartLocalRef refCameraName(env, cameraName); + params[0].l = cameraName; + params[1].l = jPosition; + params[2].l = jUp; + params[3].l = jLookAt; + params[4].f = cCamera->mHorizontalFOV; + params[5].f = cCamera->mClipPlaneNear; + params[6].f = cCamera->mClipPlaneFar; + params[7].f = cCamera->mAspect; + + if (!createInstance(env, "jassimp/AiCamera", "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;FFFF)V", + params, jCamera)) + { + return false; + } + + /* add camera to m_cameras java.util.List */ + jobject jCameras = NULL; + SmartLocalRef refCameras(env, jCameras); + if (!getField(env, jScene, "m_cameras", "Ljava/util/List;", jCameras)) + { + return false; + } + + jvalue addParams[1]; + addParams[0].l = jCamera; + if (!call(env, jCameras, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", addParams)) + { + return false; + } + } + + lprintf("converting cameras finished\n"); + + return true; +} + + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getVKeysize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(aiVectorKey); + return res; +} + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getQKeysize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(aiQuatKey); + return res; +} + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getV3Dsize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(aiVector3D); + return res; +} + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getfloatsize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(float); + return res; +} + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getintsize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(int); + return res; +} + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getuintsize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(unsigned int); + return res; +} + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getdoublesize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(double); + return res; +} + +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getlongsize + (JNIEnv *env, jclass jClazz) +{ + const int res = sizeof(long); + return res; +} + +JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString + (JNIEnv *env, jclass jClazz) +{ + const char *err = gLastErrorString.c_str(); + + if (NULL == err) + { + return env->NewStringUTF(""); + } + + return env->NewStringUTF(err); +} + + +JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile + (JNIEnv *env, jclass jClazz, jstring jFilename, jlong postProcess, jobject ioSystem, jobject progressHandler) +{ + jobject jScene = NULL; + + /* convert params */ + const char* cFilename = env->GetStringUTFChars(jFilename, NULL); + + Assimp::Importer imp; + + + if(ioSystem != NULL) + { + imp.SetIOHandler(new JavaIOSystem(env, ioSystem)); + lprintf("Created aiFileIO\n"); + } + + if(progressHandler != NULL) + { + imp.SetProgressHandler(new JavaProgressHandler(env, progressHandler)); + } + + lprintf("opening file: %s\n", cFilename); + + /* do import */ + const aiScene *cScene = imp.ReadFile(cFilename, (unsigned int) postProcess); + + if (!cScene) + { + lprintf("import file returned null\n"); + goto error; + } + + if (!createInstance(env, "jassimp/AiScene", jScene)) + { + goto error; + } + + if (!loadMeshes(env, cScene, jScene)) + { + goto error; + } + + if (!loadMaterials(env, cScene, jScene)) + { + goto error; + } + + if (!loadAnimations(env, cScene, jScene)) + { + goto error; + } + + if (!loadLights(env, cScene, jScene)) + { + goto error; + } + + if (!loadCameras(env, cScene, jScene)) + { + goto error; + } + + if (!loadSceneGraph(env, cScene, jScene)) + { + goto error; + } + + /* jump over error handling section */ + goto end; + +error: + { + jclass exception = env->FindClass("java/io/IOException"); + + if (NULL == exception) + { + /* that's really a problem because we cannot throw in this case */ + env->FatalError("could not throw java.io.IOException"); + } + gLastErrorString = imp.GetErrorString(); + env->ThrowNew(exception, gLastErrorString.c_str()); + + lprintf("problem detected\n"); + } + +end: + + /* free params */ + env->ReleaseStringUTFChars(jFilename, cFilename); + + lprintf("return from native\n"); + + return jScene; +} diff --git a/libs/assimp/port/jassimp/jassimp-native/src/jassimp.h b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.h new file mode 100644 index 0000000..2a4a845 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp-native/src/jassimp.h @@ -0,0 +1,47 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +#include <stdlib.h> +/* Header for class jassimp_Jassimp */ + +#ifndef _Included_jassimp_Jassimp +#define _Included_jassimp_Jassimp +#ifdef __cplusplus +extern "C" { +#endif +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getVKeysize + (JNIEnv *, jclass); +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getQKeysize + (JNIEnv *, jclass); +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getV3Dsize + (JNIEnv *, jclass); +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getfloatsize + (JNIEnv *, jclass); +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getintsize + (JNIEnv *, jclass); +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getuintsize + (JNIEnv *, jclass); +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getdoublesize + (JNIEnv *, jclass); +JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getlongsize + (JNIEnv *, jclass); + +/* + * Class: jassimp_Jassimp + * Method: getErrorString + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString + (JNIEnv *, jclass); + +/* + * Class: jassimp_Jassimp + * Method: aiImportFile + * Signature: (Ljava/lang/String;J)Ljassimp/AiScene; + */ +JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile + (JNIEnv *, jclass, jstring, jlong, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiAnimBehavior.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiAnimBehavior.java new file mode 100644 index 0000000..ae4f04a --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiAnimBehavior.java @@ -0,0 +1,112 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Defines how an animation channel behaves outside the defined time range. + */ +public enum AiAnimBehavior { + /** + * The value from the default node transformation is taken. + */ + DEFAULT(0x0), + + + /** + * The nearest key value is used without interpolation. + */ + CONSTANT(0x1), + + + /** + * The value of the nearest two keys is linearly extrapolated for the + * current time value. + */ + LINEAR(0x2), + + + /** + * The animation is repeated.<p> + * + * If the animation key go from n to m and the current time is t, use the + * value at (t-n) % (|m-n|). + */ + REPEAT(0x3); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static AiAnimBehavior fromRawValue(int rawValue) { + for (AiAnimBehavior type : AiAnimBehavior.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiAnimBehavior(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiAnimation.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiAnimation.java new file mode 100644 index 0000000..856b918 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiAnimation.java @@ -0,0 +1,175 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.util.ArrayList; +import java.util.List; + +/** + * An animation.<p> + * + * An animation consists of keyframe data for a number of nodes. For + * each node affected by the animation a separate series of data is given.<p> + * + * Like {@link AiMesh}, the animation related classes offer a Buffer API, a + * Direct API and a wrapped API. Please consult the documentation of + * {@link AiMesh} for a description and comparison of these APIs. + */ +public final class AiAnimation { + /** + * Name. + */ + private final String m_name; + + /** + * Duration. + */ + private final double m_duration; + + /** + * Ticks per second. + */ + private final double m_ticksPerSecond; + + /** + * Bone animation channels. + */ + private final List<AiNodeAnim> m_nodeAnims = new ArrayList<AiNodeAnim>(); + + /** + * Constructor. + * + * @param name name + * @param duration duration + * @param ticksPerSecond ticks per second + */ + AiAnimation(String name, double duration, double ticksPerSecond) { + m_name = name; + m_duration = duration; + m_ticksPerSecond = ticksPerSecond; + } + + + /** + * Returns the name of the animation.<p> + * + * If the modeling package this data was exported from does support only + * a single animation channel, this name is usually empty (length is zero). + * + * @return the name + */ + public String getName() { + return m_name; + } + + + /** + * Returns the duration of the animation in ticks. + * + * @return the duration + */ + public double getDuration() { + return m_duration; + } + + + /** + * Returns the ticks per second.<p> + * + * 0 if not specified in the imported file + * + * @return the number of ticks per second + */ + public double getTicksPerSecond() { + return m_ticksPerSecond; + } + + + /** + * Returns the number of bone animation channels.<p> + * + * Each channel affects a single node. This method will return the same + * value as <code>getChannels().size()</code> + * + * @return the number of bone animation channels + */ + public int getNumChannels() { + return m_nodeAnims.size(); + } + + + /** + * Returns the list of bone animation channels.<p> + * + * Each channel affects a single node. The array is mNumChannels in size. + * + * @return the list of bone animation channels + */ + public List<AiNodeAnim> getChannels() { + return m_nodeAnims; + } + + + /** + * Returns the number of mesh animation channels.<p> + * + * Each channel affects a single mesh and defines vertex-based animation. + * This method will return the same value as + * <code>getMeshChannels().size()</code> + * + * @return the number of mesh animation channels + */ + public int getNumMeshChannels() { + throw new UnsupportedOperationException("not implemented yet"); + } + + + /** + * Returns the list of mesh animation channels.<p> + * + * Each channel affects a single mesh. + * + * @return the list of mesh animation channels + */ + public List<AiMeshAnim> getMeshChannels() { + throw new UnsupportedOperationException("not implemented yet"); + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBlendMode.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBlendMode.java new file mode 100644 index 0000000..d3a0e0e --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBlendMode.java @@ -0,0 +1,117 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Defines alpha-blend flags.<p> + * + * If you're familiar with OpenGL or D3D, these flags aren't new to you. + * They define *how* the final color value of a pixel is computed, basing + * on the previous color at that pixel and the new color value from the + * material. The blend formula is: + * <br><code> + * SourceColor * SourceBlend + DestColor * DestBlend + * </code><br> + * where <code>DestColor</code> is the previous color in the framebuffer at + * this position and <code>SourceColor</code> is the material color before the + * transparency calculation. + */ +public enum AiBlendMode { + /** + * Default blending.<p> + * + * Formula: + * <code> + * SourceColor*SourceAlpha + DestColor*(1-SourceAlpha) + * </code> + */ + DEFAULT(0x0), + + + /** + * Additive blending.<p> + * + * Formula: + * <code> + * SourceColor*1 + DestColor*1 + * </code> + */ + ADDITIVE(0x1); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static AiBlendMode fromRawValue(int rawValue) { + for (AiBlendMode type : AiBlendMode.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiBlendMode(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBone.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBone.java new file mode 100644 index 0000000..eaaf481 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBone.java @@ -0,0 +1,136 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.util.ArrayList; +import java.util.List; + + +/** + * A single bone of a mesh.<p> + * + * A bone has a name by which it can be found in the frame hierarchy and by + * which it can be addressed by animations. In addition it has a number of + * influences on vertices.<p> + * + * This class is designed to be mutable, i.e., the returned collections are + * writable and may be modified. + */ +public final class AiBone { + /** + * Name of the bone. + */ + private String m_name; + + + /** + * Bone weights. + */ + private final List<AiBoneWeight> m_boneWeights = + new ArrayList<AiBoneWeight>(); + + + /** + * Offset matrix. + */ + private Object m_offsetMatrix; + + /** + * Constructor. + */ + AiBone() { + /* nothing to do */ + } + + + /** + * Returns the name of the bone. + * + * @return the name + */ + public String getName() { + return m_name; + } + + + /** + * Returns the number of bone weights.<p> + * + * This method exists for compatibility with the native assimp API. + * The returned value is identical to <code>getBoneWeights().size()</code> + * + * @return the number of weights + */ + public int getNumWeights() { + return m_boneWeights.size(); + } + + + /** + * Returns a list of bone weights. + * + * @return the bone weights + */ + public List<AiBoneWeight> getBoneWeights() { + return m_boneWeights; + } + + + /** + * Returns the offset matrix.<p> + * + * The offset matrix is a 4x4 matrix that transforms from mesh space to + * bone space in bind pose.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers). + * + * @param wrapperProvider the wrapper provider (used for type inference) + * + * @return the offset matrix + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> M4 getOffsetMatrix( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + return (M4) m_offsetMatrix; + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBoneWeight.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBoneWeight.java new file mode 100644 index 0000000..7d7a183 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBoneWeight.java @@ -0,0 +1,88 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * A single influence of a bone on a vertex. + */ +public final class AiBoneWeight { + /** + * Constructor. + */ + AiBoneWeight() { + /* nothing to do */ + } + + + /** + * Index of the vertex which is influenced by the bone. + * + * @return the vertex index + */ + public int getVertexId() { + return m_vertexId; + } + + + /** + * The strength of the influence in the range (0...1).<p> + * + * The influence from all bones at one vertex amounts to 1 + * + * @return the influence + */ + public float getWeight() { + return m_weight; + } + + + /** + * Vertex index. + */ + private int m_vertexId; + + + /** + * Influence of bone on vertex. + */ + private float m_weight; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBuiltInWrapperProvider.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBuiltInWrapperProvider.java new file mode 100644 index 0000000..ebc23c0 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiBuiltInWrapperProvider.java @@ -0,0 +1,84 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; + + +/** + * Wrapper provider using jassimp built in types. + */ +public final class AiBuiltInWrapperProvider implements AiWrapperProvider< + AiVector, AiMatrix4f, AiColor, AiNode, AiQuaternion> { + + @Override + public AiVector wrapVector3f(ByteBuffer buffer, int offset, + int numComponents) { + + return new AiVector(buffer, offset, numComponents); + } + + + @Override + public AiMatrix4f wrapMatrix4f(float[] data) { + return new AiMatrix4f(data); + } + + + @Override + public AiColor wrapColor(ByteBuffer buffer, int offset) { + return new AiColor(buffer, offset); + } + + + @Override + public AiNode wrapSceneNode(Object parent, Object matrix, + int[] meshReferences, String name) { + + return new AiNode((AiNode) parent, matrix, meshReferences, name); + } + + + @Override + public AiQuaternion wrapQuaternion(ByteBuffer buffer, int offset) { + return new AiQuaternion(buffer, offset); + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiCamera.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiCamera.java new file mode 100644 index 0000000..b0f692e --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiCamera.java @@ -0,0 +1,303 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Helper structure to describe a virtual camera.<p> + * + * Cameras have a representation in the node graph and can be animated. + * An important aspect is that the camera itself is also part of the + * scenegraph. This means, any values such as the look-at vector are not + * *absolute*, they're <b>relative</b> to the coordinate system defined + * by the node which corresponds to the camera. This allows for camera + * animations. For static cameras parameters like the 'look-at' or 'up' vectors + * are usually specified directly in aiCamera, but beware, they could also + * be encoded in the node transformation. The following (pseudo)code sample + * shows how to do it: <p> + * <code><pre> + * // Get the camera matrix for a camera at a specific time + * // if the node hierarchy for the camera does not contain + * // at least one animated node this is a static computation + * get-camera-matrix (node sceneRoot, camera cam) : matrix + * { + * node cnd = find-node-for-camera(cam) + * matrix cmt = identity() + * + * // as usual - get the absolute camera transformation for this frame + * for each node nd in hierarchy from sceneRoot to cnd + * matrix cur + * if (is-animated(nd)) + * cur = eval-animation(nd) + * else cur = nd->mTransformation; + * cmt = mult-matrices( cmt, cur ) + * end for + * + * // now multiply with the camera's own local transform + * cam = mult-matrices (cam, get-camera-matrix(cmt) ) + * } + * </pre></code> + * + * <b>Note:</b> some file formats (such as 3DS, ASE) export a "target point" - + * the point the camera is looking at (it can even be animated). Assimp + * writes the target point as a subnode of the camera's main node, + * called "<camName>.Target". However this is just additional information + * then the transformation tracks of the camera main node make the + * camera already look in the right direction. + */ +public final class AiCamera { + /** + * Constructor. + * + * @param name name + * @param position position + * @param up up vector + * @param lookAt look-at vector + * @param horizontalFOV field of view + * @param clipNear near clip plane + * @param clipFar far clip plane + * @param aspect aspect ratio + */ + AiCamera(String name, Object position, Object up, Object lookAt, + float horizontalFOV, float clipNear, float clipFar, float aspect) { + + m_name = name; + m_position = position; + m_up = up; + m_lookAt = lookAt; + m_horizontalFOV = horizontalFOV; + m_clipNear = clipNear; + m_clipFar = clipFar; + m_aspect = aspect; + } + + + /** + * Returns the name of the camera.<p> + * + * There must be a node in the scenegraph with the same name. + * This node specifies the position of the camera in the scene + * hierarchy and can be animated. + */ + public String getName() { + return m_name; + } + + + /** + * Returns the position of the camera.<p> + * + * The returned position is relative to the coordinate space defined by the + * corresponding node.<p> + * + * The default value is 0|0|0.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the position vector + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> V3 getPosition(AiWrapperProvider<V3, M4, C, N, Q> + wrapperProvider) { + + return (V3) m_position; + } + + + /** + * Returns the 'Up' - vector of the camera coordinate system. + * + * The returned vector is relative to the coordinate space defined by the + * corresponding node.<p> + * + * The 'right' vector of the camera coordinate system is the cross product + * of the up and lookAt vectors. The default value is 0|1|0. The vector + * may be normalized, but it needn't.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the 'Up' vector + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> V3 getUp(AiWrapperProvider<V3, M4, C, N, Q> + wrapperProvider) { + + return (V3) m_up; + } + + + /** + * Returns the 'LookAt' - vector of the camera coordinate system.<p> + * + * The returned vector is relative to the coordinate space defined by the + * corresponding node.<p> + * + * This is the viewing direction of the user. The default value is 0|0|1. + * The vector may be normalized, but it needn't.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the 'LookAt' vector + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> V3 getLookAt(AiWrapperProvider<V3, M4, C, N, Q> + wrapperProvider) { + + return (V3) m_lookAt; + } + + + /** + * Returns the half horizontal field of view angle, in radians.<p> + * + * The field of view angle is the angle between the center line of the + * screen and the left or right border. The default value is 1/4PI. + * + * @return the half horizontal field of view angle + */ + public float getHorizontalFOV() { + return m_horizontalFOV; + } + + + /** + * Returns the distance of the near clipping plane from the camera.<p> + * + * The value may not be 0.f (for arithmetic reasons to prevent a division + * through zero). The default value is 0.1f. + * + * @return the distance of the near clipping plane + */ + public float getClipPlaneNear() { + return m_clipNear; + } + + + /** + * Returns the distance of the far clipping plane from the camera.<p> + * + * The far clipping plane must, of course, be further away than the + * near clipping plane. The default value is 1000.0f. The ratio + * between the near and the far plane should not be too + * large (between 1000-10000 should be ok) to avoid floating-point + * inaccuracies which could lead to z-fighting. + * + * @return the distance of the far clipping plane + */ + public float getClipPlaneFar() { + return m_clipFar; + } + + + /** + * Returns the screen aspect ratio.<p> + * + * This is the ration between the width and the height of the + * screen. Typical values are 4/3, 1/2 or 1/1. This value is + * 0 if the aspect ratio is not defined in the source file. + * 0 is also the default value. + * + * @return the screen aspect ratio + */ + public float getAspect() { + return m_aspect; + } + + + /** + * Name. + */ + private final String m_name; + + + /** + * Position. + */ + private final Object m_position; + + + /** + * Up vector. + */ + private final Object m_up; + + + /** + * Look-At vector. + */ + private final Object m_lookAt; + + + /** + * FOV. + */ + private final float m_horizontalFOV; + + + /** + * Near clipping plane. + */ + private final float m_clipNear; + + + /** + * Far clipping plane. + */ + private final float m_clipFar; + + + /** + * Aspect ratio. + */ + private final float m_aspect; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java new file mode 100644 index 0000000..687e9f3 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java @@ -0,0 +1,153 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +/** + * IOSystem based on the Java classloader.<p> + * + * This IOSystem allows loading models directly from the + * classpath. No extraction to the file system is + * necessary. + * + * @author Jesper Smith + * + */ +public class AiClassLoaderIOSystem implements AiIOSystem<AiInputStreamIOStream> +{ + private final Class<?> clazz; + private final ClassLoader classLoader; + + /** + * Construct a new AiClassLoaderIOSystem.<p> + * + * This constructor uses a ClassLoader to resolve + * resources. + * + * @param classLoader classLoader to resolve resources. + */ + public AiClassLoaderIOSystem(ClassLoader classLoader) { + this.clazz = null; + this.classLoader = classLoader; + } + + /** + * Construct a new AiClassLoaderIOSystem.<p> + * + * This constructor uses a Class to resolve + * resources. + * + * @param class<?> class to resolve resources. + */ + public AiClassLoaderIOSystem(Class<?> clazz) { + this.clazz = clazz; + this.classLoader = null; + } + + + @Override + public AiInputStreamIOStream open(String filename, String ioMode) { + try { + + InputStream is; + + if(clazz != null) { + is = clazz.getResourceAsStream(filename); + } + else if (classLoader != null) { + is = classLoader.getResourceAsStream(filename); + } + else { + System.err.println("[" + getClass().getSimpleName() + + "] No class or classLoader provided to resolve " + filename); + return null; + } + + if(is != null) { + return new AiInputStreamIOStream(is); + } + else { + System.err.println("[" + getClass().getSimpleName() + + "] Cannot find " + filename); + return null; + } + } + catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public void close(AiInputStreamIOStream file) { + } + + @Override + public boolean exists(String path) + { + URL url = null; + if(clazz != null) { + url = clazz.getResource(path); + } + else if (classLoader != null) { + url = classLoader.getResource(path); + } + + + if(url == null) + { + return false; + } + + return true; + + } + + @Override + public char getOsSeparator() + { + return '/'; + } + +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiColor.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiColor.java new file mode 100644 index 0000000..5cea22a --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiColor.java @@ -0,0 +1,160 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; + + +/** + * Wrapper for colors.<p> + * + * The wrapper is writable, i.e., changes performed via the set-methods will + * modify the underlying mesh. + */ +public final class AiColor { + /** + * Wrapped buffer. + */ + private final ByteBuffer m_buffer; + + /** + * Offset into m_buffer. + */ + private final int m_offset; + + /** + * Constructor. + * + * @param buffer the buffer to wrap + * @param offset offset into buffer + */ + public AiColor(ByteBuffer buffer, int offset) { + m_buffer = buffer; + m_offset = offset; + } + + + /** + * Returns the red color component. + * + * @return the red component + */ + public float getRed() { + return m_buffer.getFloat(m_offset); + } + + + /** + * Returns the green color component. + * + * @return the green component + */ + public float getGreen() { + return m_buffer.getFloat(m_offset + 4); + } + + + /** + * Returns the blue color component. + * + * @return the blue component + */ + public float getBlue() { + return m_buffer.getFloat(m_offset + 8); + } + + + /** + * Returns the alpha color component. + * + * @return the alpha component + */ + public float getAlpha() { + return m_buffer.getFloat(m_offset + 12); + } + + + /** + * Sets the red color component. + * + * @param red the new value + */ + public void setRed(float red) { + m_buffer.putFloat(m_offset, red); + } + + + /** + * Sets the green color component. + * + * @param green the new value + */ + public void setGreen(float green) { + m_buffer.putFloat(m_offset + 4, green); + } + + + /** + * Sets the blue color component. + * + * @param blue the new value + */ + public void setBlue(float blue) { + m_buffer.putFloat(m_offset + 8, blue); + } + + + /** + * Sets the alpha color component. + * + * @param alpha the new value + */ + public void setAlpha(float alpha) { + m_buffer.putFloat(m_offset + 12, alpha); + } + + + @Override + public String toString() { + return "[" + getRed() + ", " + getGreen() + ", " + getBlue() + ", " + + getAlpha() + "]"; + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiConfig.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiConfig.java new file mode 100644 index 0000000..f49ce86 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiConfig.java @@ -0,0 +1,15 @@ +/* + * $Revision$ + * $Date$ + */ +package jassimp; + + +/** + * Configuration interface for assimp importer.<p> + * + * This class is work-in-progress + */ +public class AiConfig { + +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiConfigOptions.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiConfigOptions.java new file mode 100644 index 0000000..6196598 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiConfigOptions.java @@ -0,0 +1,663 @@ +/* + * $Revision$ + * $Date$ + */ +package jassimp; + + +/** + * Lists all possible configuration options.<p> + * + * This class is work-in-progress + */ +public enum AiConfigOptions { + /** + * Maximum bone count per mesh for the SplitbyBoneCount step.<p> + * + * Meshes are split until the maximum number of bones is reached. The + * default value is AI_SBBC_DEFAULT_MAX_BONES, which may be altered at + * compile-time. This limit is imposed by the native jassimp library + * and typically is 60.<p> + * + * Property data type: integer. + */ + PP_SBBC_MAX_BONES("PP_SBBC_MAX_BONES"), + + + /** + * Specifies the maximum angle that may be between two vertex tangents + * that their tangents and bi-tangents are smoothed.<p> + * + * This applies to the CalcTangentSpace-Step. The angle is specified + * in degrees. The maximum value is 175.<p> + * + * Property type: float. Default value: 45 degrees + */ + PP_CT_MAX_SMOOTHING_ANGLE("PP_CT_MAX_SMOOTHING_ANGLE"), + + + /** + * Source UV channel for tangent space computation.<p> + * + * The specified channel must exist or an error will be raised.<p> + * + * Property type: integer. Default value: 0 + */ + PP_CT_TEXTURE_CHANNEL_INDEX("PP_CT_TEXTURE_CHANNEL_INDEX"), + + + /** + * Specifies the maximum angle that may be between two face normals + * at the same vertex position that their are smoothed together.<p> + * + * Sometimes referred to as 'crease angle'. This applies to the + * GenSmoothNormals-Step. The angle is specified in degrees, so 180 is PI. + * The default value is 175 degrees (all vertex normals are smoothed). The + * maximum value is 175, too.<p> + * + * Property type: float.<p> + * + * Warning: setting this option may cause a severe loss of performance. The + * performance is unaffected if the {@link #CONFIG_FAVOUR_SPEED} flag is + * set but the output quality may be reduced. + */ + PP_GSN_MAX_SMOOTHING_ANGLE("PP_GSN_MAX_SMOOTHING_ANGLE"), + + + /** + * Sets the colormap (= palette) to be used to decode embedded textures in + * MDL (Quake or 3DGS) files.<p> + * + * This must be a valid path to a file. The file is 768 (256*3) bytes + * large and contains RGB triplets for each of the 256 palette entries. + * The default value is colormap.lmp. If the file is not found, + * a default palette (from Quake 1) is used.<p> + * + * Property type: string. + */ + IMPORT_MDL_COLORMAP("IMPORT_MDL_COLORMAP"), + + + /** + * Configures the #aiProcess_RemoveRedundantMaterials step to keep + * materials matching a name in a given list.<p> + * + * This is a list of 1 to n strings, ' ' serves as delimiter character. + * Identifiers containing whitespaces must be enclosed in *single* + * quotation marks. For example:<tt> + * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'"</tt>. + * If a material matches on of these names, it will not be modified or + * removed by the postprocessing step nor will other materials be replaced + * by a reference to it.<p> + * + * This option might be useful if you are using some magic material names + * to pass additional semantics through the content pipeline. This ensures + * they won't be optimized away, but a general optimization is still + * performed for materials not contained in the list.<p> + * + * Property type: String. Default value: n/a<p> + * + * <b>Note:</b>Linefeeds, tabs or carriage returns are treated as + * whitespace. Material names are case sensitive. + */ + PP_RRM_EXCLUDE_LIST("PP_RRM_EXCLUDE_LIST"), + + + /** + * Configures the {@link AiPostProcessSteps#PRE_TRANSFORM_VERTICES} step + * to keep the scene hierarchy. Meshes are moved to worldspace, but no + * optimization is performed (read: meshes with equal materials are not + * joined. The total number of meshes won't change).<p> + * + * This option could be of use for you if the scene hierarchy contains + * important additional information which you intend to parse. + * For rendering, you can still render all meshes in the scene without + * any transformations.<p> + * + * Property type: bool. Default value: false. + */ + PP_PTV_KEEP_HIERARCHY("PP_PTV_KEEP_HIERARCHY"), + + + /** + * Configures the {@link AiPostProcessSteps#PRE_TRANSFORM_VERTICES} step + * to normalize all vertex components into the [-1,1] range.<p> + * + * That is, a bounding box for the whole scene is computed, the maximum + * component is taken and all meshes are scaled appropriately (uniformly + * of course!). This might be useful if you don't know the spatial + * dimension of the input data.<p> + * + * Property type: bool. Default value: false. + */ + PP_PTV_NORMALIZE("PP_PTV_NORMALIZE"), + + + /** + * Configures the {@link AiPostProcessSteps#FIND_DEGENERATES} step to + * remove degenerated primitives from the import - immediately.<p> + * + * The default behaviour converts degenerated triangles to lines and + * degenerated lines to points. See the documentation to the + * {@link AiPostProcessSteps#FIND_DEGENERATES} step for a detailed example + * of the various ways to get rid of these lines and points if you don't + * want them.<p> + * + * Property type: bool. Default value: false. + */ + PP_FD_REMOVE("PP_FD_REMOVE") + + +// // --------------------------------------------------------------------------- +// /** @brief Configures the #aiProcess_OptimizeGraph step to preserve nodes +// * matching a name in a given list. +// * +// * This is a list of 1 to n strings, ' ' serves as delimiter character. +// * Identifiers containing whitespaces must be enclosed in *single* +// * quotation marks. For example:<tt> +// * "keep-me and_me_to anotherNodeToBeKept \'name with whitespace\'"</tt>. +// * If a node matches on of these names, it will not be modified or +// * removed by the postprocessing step.<br> +// * This option might be useful if you are using some magic node names +// * to pass additional semantics through the content pipeline. This ensures +// * they won't be optimized away, but a general optimization is still +// * performed for nodes not contained in the list. +// * Property type: String. Default value: n/a +// * @note Linefeeds, tabs or carriage returns are treated as whitespace. +// * Node names are case sensitive. +// */ +// #define AI_CONFIG_PP_OG_EXCLUDE_LIST \ +// "PP_OG_EXCLUDE_LIST" +// +// // --------------------------------------------------------------------------- +// /** @brief Set the maximum number of triangles in a mesh. +// * +// * This is used by the "SplitLargeMeshes" PostProcess-Step to determine +// * whether a mesh must be split or not. +// * @note The default value is AI_SLM_DEFAULT_MAX_TRIANGLES +// * Property type: integer. +// */ +// #define AI_CONFIG_PP_SLM_TRIANGLE_LIMIT \ +// "PP_SLM_TRIANGLE_LIMIT" +// +// // default value for AI_CONFIG_PP_SLM_TRIANGLE_LIMIT +// #if (!defined AI_SLM_DEFAULT_MAX_TRIANGLES) +// # define AI_SLM_DEFAULT_MAX_TRIANGLES 1000000 +// #endif +// +// // --------------------------------------------------------------------------- +// /** @brief Set the maximum number of vertices in a mesh. +// * +// * This is used by the "SplitLargeMeshes" PostProcess-Step to determine +// * whether a mesh must be split or not. +// * @note The default value is AI_SLM_DEFAULT_MAX_VERTICES +// * Property type: integer. +// */ +// #define AI_CONFIG_PP_SLM_VERTEX_LIMIT \ +// "PP_SLM_VERTEX_LIMIT" +// +// // default value for AI_CONFIG_PP_SLM_VERTEX_LIMIT +// #if (!defined AI_SLM_DEFAULT_MAX_VERTICES) +// # define AI_SLM_DEFAULT_MAX_VERTICES 1000000 +// #endif +// +// // --------------------------------------------------------------------------- +// /** @brief Set the maximum number of bones affecting a single vertex +// * +// * This is used by the #aiProcess_LimitBoneWeights PostProcess-Step. +// * @note The default value is AI_LBW_MAX_WEIGHTS +// * Property type: integer.*/ +// #define AI_CONFIG_PP_LBW_MAX_WEIGHTS \ +// "PP_LBW_MAX_WEIGHTS" +// +// // default value for AI_CONFIG_PP_LBW_MAX_WEIGHTS +// #if (!defined AI_LMW_MAX_WEIGHTS) +// # define AI_LMW_MAX_WEIGHTS 0x4 +// #endif // !! AI_LMW_MAX_WEIGHTS +// +// // --------------------------------------------------------------------------- +// /** @brief Lower the deboning threshold in order to remove more bones. +// * +// * This is used by the #aiProcess_Debone PostProcess-Step. +// * @note The default value is AI_DEBONE_THRESHOLD +// * Property type: float.*/ +// #define AI_CONFIG_PP_DB_THRESHOLD \ +// "PP_DB_THRESHOLD" +// +// // default value for AI_CONFIG_PP_LBW_MAX_WEIGHTS +// #if (!defined AI_DEBONE_THRESHOLD) +// # define AI_DEBONE_THRESHOLD 1.0f +// #endif // !! AI_DEBONE_THRESHOLD +// +// // --------------------------------------------------------------------------- +// /** @brief Require all bones qualify for deboning before removing any +// * +// * This is used by the #aiProcess_Debone PostProcess-Step. +// * @note The default value is 0 +// * Property type: bool.*/ +// #define AI_CONFIG_PP_DB_ALL_OR_NONE \ +// "PP_DB_ALL_OR_NONE" +// +// /** @brief Default value for the #AI_CONFIG_PP_ICL_PTCACHE_SIZE property +// */ +// #ifndef PP_ICL_PTCACHE_SIZE +// # define PP_ICL_PTCACHE_SIZE 12 +// #endif +// +// // --------------------------------------------------------------------------- +// /** @brief Set the size of the post-transform vertex cache to optimize the +// * vertices for. This configures the #aiProcess_ImproveCacheLocality step. +// * +// * The size is given in vertices. Of course you can't know how the vertex +// * format will exactly look like after the import returns, but you can still +// * guess what your meshes will probably have. +// * @note The default value is #PP_ICL_PTCACHE_SIZE. That results in slight +// * performance improvements for most nVidia/AMD cards since 2002. +// * Property type: integer. +// */ +// #define AI_CONFIG_PP_ICL_PTCACHE_SIZE "PP_ICL_PTCACHE_SIZE" +// +// // --------------------------------------------------------------------------- +// /** @brief Enumerates components of the aiScene and aiMesh data structures +// * that can be excluded from the import using the #aiPrpcess_RemoveComponent step. +// * +// * See the documentation to #aiProcess_RemoveComponent for more details. +// */ +// enum aiComponent +// { +// /** Normal vectors */ +// #ifdef SWIG +// aiComponent_NORMALS = 0x2, +// #else +// aiComponent_NORMALS = 0x2u, +// #endif +// +// /** Tangents and bitangents go always together ... */ +// #ifdef SWIG +// aiComponent_TANGENTS_AND_BITANGENTS = 0x4, +// #else +// aiComponent_TANGENTS_AND_BITANGENTS = 0x4u, +// #endif +// +// /** ALL color sets +// * Use aiComponent_COLORn(N) to specify the N'th set */ +// aiComponent_COLORS = 0x8, +// +// /** ALL texture UV sets +// * aiComponent_TEXCOORDn(N) to specify the N'th set */ +// aiComponent_TEXCOORDS = 0x10, +// +// /** Removes all bone weights from all meshes. +// * The scenegraph nodes corresponding to the bones are NOT removed. +// * use the #aiProcess_OptimizeGraph step to do this */ +// aiComponent_BONEWEIGHTS = 0x20, +// +// /** Removes all node animations (aiScene::mAnimations). +// * The corresponding scenegraph nodes are NOT removed. +// * use the #aiProcess_OptimizeGraph step to do this */ +// aiComponent_ANIMATIONS = 0x40, +// +// /** Removes all embedded textures (aiScene::mTextures) */ +// aiComponent_TEXTURES = 0x80, +// +// /** Removes all light sources (aiScene::mLights). +// * The corresponding scenegraph nodes are NOT removed. +// * use the #aiProcess_OptimizeGraph step to do this */ +// aiComponent_LIGHTS = 0x100, +// +// /** Removes all light sources (aiScene::mCameras). +// * The corresponding scenegraph nodes are NOT removed. +// * use the #aiProcess_OptimizeGraph step to do this */ +// aiComponent_CAMERAS = 0x200, +// +// /** Removes all meshes (aiScene::mMeshes). */ +// aiComponent_MESHES = 0x400, +// +// /** Removes all materials. One default material will +// * be generated, so aiScene::mNumMaterials will be 1. */ +// aiComponent_MATERIALS = 0x800, +// +// +// /** This value is not used. It is just there to force the +// * compiler to map this enum to a 32 Bit integer. */ +// #ifndef SWIG +// _aiComponent_Force32Bit = 0x9fffffff +// #endif +// }; +// +// // Remove a specific color channel 'n' +// #define aiComponent_COLORSn(n) (1u << (n+20u)) +// +// // Remove a specific UV channel 'n' +// #define aiComponent_TEXCOORDSn(n) (1u << (n+25u)) +// +// // --------------------------------------------------------------------------- +// /** @brief Input parameter to the #aiProcess_RemoveComponent step: +// * Specifies the parts of the data structure to be removed. +// * +// * See the documentation to this step for further details. The property +// * is expected to be an integer, a bitwise combination of the +// * #aiComponent flags defined above in this header. The default +// * value is 0. Important: if no valid mesh is remaining after the +// * step has been executed (e.g you thought it was funny to specify ALL +// * of the flags defined above) the import FAILS. Mainly because there is +// * no data to work on anymore ... +// */ +// #define AI_CONFIG_PP_RVC_FLAGS \ +// "PP_RVC_FLAGS" +// +// // --------------------------------------------------------------------------- +// /** @brief Input parameter to the #aiProcess_SortByPType step: +// * Specifies which primitive types are removed by the step. +// * +// * This is a bitwise combination of the aiPrimitiveType flags. +// * Specifying all of them is illegal, of course. A typical use would +// * be to exclude all line and point meshes from the import. This +// * is an integer property, its default value is 0. +// */ +// #define AI_CONFIG_PP_SBP_REMOVE \ +// "PP_SBP_REMOVE" +// +// // --------------------------------------------------------------------------- +// /** @brief Input parameter to the #aiProcess_FindInvalidData step: +// * Specifies the floating-point accuracy for animation values. The step +// * checks for animation tracks where all frame values are absolutely equal +// * and removes them. This tweakable controls the epsilon for floating-point +// * comparisons - two keys are considered equal if the invariant +// * abs(n0-n1)>epsilon holds true for all vector respectively quaternion +// * components. The default value is 0.f - comparisons are exact then. +// */ +// #define AI_CONFIG_PP_FID_ANIM_ACCURACY \ +// "PP_FID_ANIM_ACCURACY" +// +// +// // TransformUVCoords evaluates UV scalings +// #define AI_UVTRAFO_SCALING 0x1 +// +// // TransformUVCoords evaluates UV rotations +// #define AI_UVTRAFO_ROTATION 0x2 +// +// // TransformUVCoords evaluates UV translation +// #define AI_UVTRAFO_TRANSLATION 0x4 +// +// // Everything baked together -> default value +// #define AI_UVTRAFO_ALL (AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION | AI_UVTRAFO_TRANSLATION) +// +// // --------------------------------------------------------------------------- +// /** @brief Input parameter to the #aiProcess_TransformUVCoords step: +// * Specifies which UV transformations are evaluated. +// * +// * This is a bitwise combination of the AI_UVTRAFO_XXX flags (integer +// * property, of course). By default all transformations are enabled +// * (AI_UVTRAFO_ALL). +// */ +// #define AI_CONFIG_PP_TUV_EVALUATE \ +// "PP_TUV_EVALUATE" +// +// // --------------------------------------------------------------------------- +// /** @brief A hint to assimp to favour speed against import quality. +// * +// * Enabling this option may result in faster loading, but it needn't. +// * It represents just a hint to loaders and post-processing steps to use +// * faster code paths, if possible. +// * This property is expected to be an integer, != 0 stands for true. +// * The default value is 0. +// */ +// #define AI_CONFIG_FAVOUR_SPEED \ +// "FAVOUR_SPEED" +// +// +// // ########################################################################### +// // IMPORTER SETTINGS +// // Various stuff to fine-tune the behaviour of specific importer plugins. +// // ########################################################################### +// +// +// // --------------------------------------------------------------------------- +// /** @brief Set the vertex animation keyframe to be imported +// * +// * ASSIMP does not support vertex keyframes (only bone animation is supported). +// * The library reads only one frame of models with vertex animations. +// * By default this is the first frame. +// * \note The default value is 0. This option applies to all importers. +// * However, it is also possible to override the global setting +// * for a specific loader. You can use the AI_CONFIG_IMPORT_XXX_KEYFRAME +// * options (where XXX is a placeholder for the file format for which you +// * want to override the global setting). +// * Property type: integer. +// */ +// #define AI_CONFIG_IMPORT_GLOBAL_KEYFRAME "IMPORT_GLOBAL_KEYFRAME" +// +// #define AI_CONFIG_IMPORT_MD3_KEYFRAME "IMPORT_MD3_KEYFRAME" +// #define AI_CONFIG_IMPORT_MD2_KEYFRAME "IMPORT_MD2_KEYFRAME" +// #define AI_CONFIG_IMPORT_MDL_KEYFRAME "IMPORT_MDL_KEYFRAME" +// #define AI_CONFIG_IMPORT_MDC_KEYFRAME "IMPORT_MDC_KEYFRAME" +// #define AI_CONFIG_IMPORT_SMD_KEYFRAME "IMPORT_SMD_KEYFRAME" +// #define AI_CONFIG_IMPORT_UNREAL_KEYFRAME "IMPORT_UNREAL_KEYFRAME" +// +// +// // --------------------------------------------------------------------------- +// /** @brief Configures the AC loader to collect all surfaces which have the +// * "Backface cull" flag set in separate meshes. +// * +// * Property type: bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL \ +// "IMPORT_AC_SEPARATE_BFCULL" +// +// // --------------------------------------------------------------------------- +// /** @brief Configures whether the AC loader evaluates subdivision surfaces ( +// * indicated by the presence of the 'subdiv' attribute in the file). By +// * default, Assimp performs the subdivision using the standard +// * Catmull-Clark algorithm +// * +// * * Property type: bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION \ +// "IMPORT_AC_EVAL_SUBDIVISION" +// +// // --------------------------------------------------------------------------- +// /** @brief Configures the UNREAL 3D loader to separate faces with different +// * surface flags (e.g. two-sided vs. single-sided). +// * +// * * Property type: bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS \ +// "UNREAL_HANDLE_FLAGS" +// +// // --------------------------------------------------------------------------- +// /** @brief Configures the terragen import plugin to compute uv's for +// * terrains, if not given. Furthermore a default texture is assigned. +// * +// * UV coordinates for terrains are so simple to compute that you'll usually +// * want to compute them on your own, if you need them. This option is intended +// * for model viewers which want to offer an easy way to apply textures to +// * terrains. +// * * Property type: bool. Default value: false. +// */ +// #define AI_CONFIG_IMPORT_TER_MAKE_UVS \ +// "IMPORT_TER_MAKE_UVS" +// +// // --------------------------------------------------------------------------- +// /** @brief Configures the ASE loader to always reconstruct normal vectors +// * basing on the smoothing groups loaded from the file. +// * +// * Some ASE files have carry invalid normals, other don't. +// * * Property type: bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS \ +// "IMPORT_ASE_RECONSTRUCT_NORMALS" +// +// // --------------------------------------------------------------------------- +// /** @brief Configures the M3D loader to detect and process multi-part +// * Quake player models. +// * +// * These models usually consist of 3 files, lower.md3, upper.md3 and +// * head.md3. If this property is set to true, Assimp will try to load and +// * combine all three files if one of them is loaded. +// * Property type: bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART \ +// "IMPORT_MD3_HANDLE_MULTIPART" +// +// // --------------------------------------------------------------------------- +// /** @brief Tells the MD3 loader which skin files to load. +// * +// * When loading MD3 files, Assimp checks whether a file +// * <md3_file_name>_<skin_name>.skin is existing. These files are used by +// * Quake III to be able to assign different skins (e.g. red and blue team) +// * to models. 'default', 'red', 'blue' are typical skin names. +// * Property type: String. Default value: "default". +// */ +// #define AI_CONFIG_IMPORT_MD3_SKIN_NAME \ +// "IMPORT_MD3_SKIN_NAME" +// +// // --------------------------------------------------------------------------- +// /** @brief Specify the Quake 3 shader file to be used for a particular +// * MD3 file. This can also be a search path. +// * +// * By default Assimp's behaviour is as follows: If a MD3 file +// * <tt><any_path>/models/<any_q3_subdir>/<model_name>/<file_name>.md3</tt> is +// * loaded, the library tries to locate the corresponding shader file in +// * <tt><any_path>/scripts/<model_name>.shader</tt>. This property overrides this +// * behaviour. It can either specify a full path to the shader to be loaded +// * or alternatively the path (relative or absolute) to the directory where +// * the shaders for all MD3s to be loaded reside. Assimp attempts to open +// * <tt><dir>/<model_name>.shader</tt> first, <tt><dir>/<file_name>.shader</tt> +// * is the fallback file. Note that <dir> should have a terminal (back)slash. +// * Property type: String. Default value: n/a. +// */ +// #define AI_CONFIG_IMPORT_MD3_SHADER_SRC \ +// "IMPORT_MD3_SHADER_SRC" +// +// // --------------------------------------------------------------------------- +// /** @brief Configures the LWO loader to load just one layer from the model. +// * +// * LWO files consist of layers and in some cases it could be useful to load +// * only one of them. This property can be either a string - which specifies +// * the name of the layer - or an integer - the index of the layer. If the +// * property is not set the whole LWO model is loaded. Loading fails if the +// * requested layer is not available. The layer index is zero-based and the +// * layer name may not be empty.<br> +// * Property type: Integer. Default value: all layers are loaded. +// */ +// #define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY \ +// "IMPORT_LWO_ONE_LAYER_ONLY" +// +// // --------------------------------------------------------------------------- +// /** @brief Configures the MD5 loader to not load the MD5ANIM file for +// * a MD5MESH file automatically. +// * +// * The default strategy is to look for a file with the same name but the +// * MD5ANIM extension in the same directory. If it is found, it is loaded +// * and combined with the MD5MESH file. This configuration option can be +// * used to disable this behaviour. +// * +// * * Property type: bool. Default value: false. +// */ +// #define AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD \ +// "IMPORT_MD5_NO_ANIM_AUTOLOAD" +// +// // --------------------------------------------------------------------------- +// /** @brief Defines the begin of the time range for which the LWS loader +// * evaluates animations and computes aiNodeAnim's. +// * +// * Assimp provides full conversion of LightWave's envelope system, including +// * pre and post conditions. The loader computes linearly subsampled animation +// * chanels with the frame rate given in the LWS file. This property defines +// * the start time. Note: animation channels are only generated if a node +// * has at least one envelope with more tan one key assigned. This property. +// * is given in frames, '0' is the first frame. By default, if this property +// * is not set, the importer takes the animation start from the input LWS +// * file ('FirstFrame' line)<br> +// * Property type: Integer. Default value: taken from file. +// * +// * @see AI_CONFIG_IMPORT_LWS_ANIM_END - end of the imported time range +// */ +// #define AI_CONFIG_IMPORT_LWS_ANIM_START \ +// "IMPORT_LWS_ANIM_START" +// #define AI_CONFIG_IMPORT_LWS_ANIM_END \ +// "IMPORT_LWS_ANIM_END" +// +// // --------------------------------------------------------------------------- +// /** @brief Defines the output frame rate of the IRR loader. +// * +// * IRR animations are difficult to convert for Assimp and there will +// * always be a loss of quality. This setting defines how many keys per second +// * are returned by the converter.<br> +// * Property type: integer. Default value: 100 +// */ +// #define AI_CONFIG_IMPORT_IRR_ANIM_FPS \ +// "IMPORT_IRR_ANIM_FPS" +// +// +// // --------------------------------------------------------------------------- +// /** @brief Ogre Importer will try to load this Materialfile. +// * +// * Ogre Meshes contain only the MaterialName, not the MaterialFile. If there +// * is no material file with the same name as the material, Ogre Importer will +// * try to load this file and search the material in it. +// * <br> +// * Property type: String. Default value: guessed. +// */ +// #define AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE "IMPORT_OGRE_MATERIAL_FILE" +// +// +// // --------------------------------------------------------------------------- +// /** @brief Ogre Importer detect the texture usage from its filename +// * +// * Normally, a texture is loaded as a colormap, if no target is specified in the +// * materialfile. Is this switch is enabled, texture names ending with _n, _l, _s +// * are used as normalmaps, lightmaps or specularmaps. +// * <br> +// * Property type: Bool. Default value: false. +// */ +// #define AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME "IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME" +// +// +// +// // --------------------------------------------------------------------------- +// /** @brief Specifies whether the IFC loader skips over IfcSpace elements. +// * +// * IfcSpace elements (and their geometric representations) are used to +// * represent, well, free space in a building storey.<br> +// * Property type: Bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS "IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS" +// +// +// // --------------------------------------------------------------------------- +// /** @brief Specifies whether the IFC loader skips over +// * shape representations of type 'Curve2D'. +// * +// * A lot of files contain both a faceted mesh representation and a outline +// * with a presentation type of 'Curve2D'. Currently Assimp doesn't convert those, +// * so turning this option off just clutters the log with errors.<br> +// * Property type: Bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_IFC_SKIP_CURVE_REPRESENTATIONS "IMPORT_IFC_SKIP_CURVE_REPRESENTATIONS" +// +// // --------------------------------------------------------------------------- +// /** @brief Specifies whether the IFC loader will use its own, custom triangulation +// * algorithm to triangulate wall and floor meshes. +// * +// * If this property is set to false, walls will be either triangulated by +// * #aiProcess_Triangulate or will be passed through as huge polygons with +// * faked holes (i.e. holes that are connected with the outer boundary using +// * a dummy edge). It is highly recommended to set this property to true +// * if you want triangulated data because #aiProcess_Triangulate is known to +// * have problems with the kind of polygons that the IFC loader spits out for +// * complicated meshes. +// * Property type: Bool. Default value: true. +// */ +// #define AI_CONFIG_IMPORT_IFC_CUSTOM_TRIANGULATION "IMPORT_IFC_CUSTOM_TRIANGULATION" +// + ; + + private AiConfigOptions(String name) { + m_name = name; + } + + + private final String m_name; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiIOStream.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiIOStream.java new file mode 100644 index 0000000..71405e6 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiIOStream.java @@ -0,0 +1,80 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; + + +/** + * Interface to allow custom resource loaders for jassimp.<p> + * + * The design is based on passing the file wholly in memory, + * because Java inputstreams do not have to support seek. <p> + * + * Writing files from Java is unsupported. + * + * + * @author Jesper Smith + * + */ +public interface AiIOStream +{ + + /** + * Read all data into buffer. <p> + * + * The whole stream should be read into the buffer. + * No support is provided for partial reads. + * + * @param buffer Target buffer for the model data + * + * @return true if successful, false if an error occurred. + */ + boolean read(ByteBuffer buffer); + + /** + * The total size of this stream. <p> + * + * @return total size of this stream + */ + int getFileSize(); + +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiIOSystem.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiIOSystem.java new file mode 100644 index 0000000..7e15ee0 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiIOSystem.java @@ -0,0 +1,79 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +public interface AiIOSystem <T extends AiIOStream> +{ + /** + * + * Open a new file with a given path. + * When the access to the file is finished, call close() to release all associated resources + * + * @param path Path to the file + * @param ioMode file I/O mode. Required are: "wb", "w", "wt", "rb", "r", "rt". + * + * @return AiIOStream or null if an error occurred + */ + public T open(String path, String ioMode); + + + /** + * Tests for the existence of a file at the given path. + * + * @param path path to the file + * @return true if there is a file with this path, else false. + */ + public boolean exists(String path); + + /** + * Returns the system specific directory separator.<p> + * + * @return System specific directory separator + */ + public char getOsSeparator(); + + /** + * Closes the given file and releases all resources associated with it. + * + * @param file The file instance previously created by Open(). + */ + public void close(T file); +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiInputStreamIOStream.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiInputStreamIOStream.java new file mode 100644 index 0000000..64aa40a --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiInputStreamIOStream.java @@ -0,0 +1,127 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; + + +/** + * Implementation of AiIOStream reading from a InputStream + * + * @author Jesper Smith + * + */ +public class AiInputStreamIOStream implements AiIOStream +{ + private final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + + public AiInputStreamIOStream(URI uri) throws IOException { + this(uri.toURL()); + } + + public AiInputStreamIOStream(URL url) throws IOException { + this(url.openStream()); + } + + public AiInputStreamIOStream(InputStream is) throws IOException { + int read; + byte[] data = new byte[1024]; + while((read = is.read(data, 0, data.length)) != -1) { + os.write(data, 0, read); + } + os.flush(); + + is.close(); + } + + @Override + public int getFileSize() { + return os.size(); + } + + @Override + public boolean read(ByteBuffer buffer) { + ByteBufferOutputStream bos = new ByteBufferOutputStream(buffer); + try + { + os.writeTo(bos); + } + catch (IOException e) + { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * Internal helper class to copy the contents of an OutputStream + * into a ByteBuffer. This avoids a copy. + * + */ + private static class ByteBufferOutputStream extends OutputStream { + + private final ByteBuffer buffer; + + public ByteBufferOutputStream(ByteBuffer buffer) { + this.buffer = buffer; + } + + @Override + public void write(int b) throws IOException + { + buffer.put((byte) b); + } + + @Override + public void write(byte b[], int off, int len) throws IOException { + buffer.put(b, off, len); + } + } +} + diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiLight.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiLight.java new file mode 100644 index 0000000..e0a93db --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiLight.java @@ -0,0 +1,387 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Describes a light source.<p> + * + * Assimp supports multiple sorts of light sources, including + * directional, point and spot lights. All of them are defined with just + * a single structure and distinguished by their parameters. + * Note - some file formats (such as 3DS, ASE) export a "target point" - + * the point a spot light is looking at (it can even be animated). Assimp + * writes the target point as a subnode of a spotlights's main node, + * called "<spotName>.Target". However, this is just additional + * information then, the transformation tracks of the main node make the + * spot light already point in the right direction. + */ +public final class AiLight { + /** + * Constructor. + * + * @param name + * @param type + * @param position + * @param direction + * @param attenuationConstant + * @param attenuationLinear + * @param attenuationQuadratic + * @param diffuse + * @param specular + * @param ambient + * @param innerCone + * @param outerCone + */ + AiLight(String name, int type, Object position, Object direction, + float attenuationConstant, float attenuationLinear, + float attenuationQuadratic, Object diffuse, Object specular, + Object ambient, float innerCone, float outerCone) { + + m_name = name; + m_type = AiLightType.fromRawValue(type); + m_position = position; + m_direction = direction; + m_attenuationConstant = attenuationConstant; + m_attenuationLinear = attenuationLinear; + m_attenuationQuadratic = attenuationQuadratic; + m_diffuse = diffuse; + m_specular = specular; + m_ambient = ambient; + m_innerCone = innerCone; + m_outerCone = outerCone; + } + + + /** + * Returns the name of the light source.<p> + * + * There must be a node in the scenegraph with the same name. + * This node specifies the position of the light in the scene + * hierarchy and can be animated. + * + * @return the name + */ + public String getName() { + return m_name; + } + + + /** + * Returns The type of the light source. + * + * @return the type + */ + public AiLightType getType() { + return m_type; + } + + + /** + * Returns the position of the light.<p> + * + * The position is relative to the transformation of the scene graph node + * corresponding to the light. The position is undefined for directional + * lights.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiVector}. + * + * + * @param wrapperProvider the wrapper provider (used for type inference) + * + * @return the position + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> V3 getPosition(AiWrapperProvider<V3, M4, C, N, Q> + wrapperProvider) { + + return (V3) m_position; + } + + + /** + * Returns the direction of the light.<p> + * + * The direction is relative to the transformation of the scene graph node + * corresponding to the light. The direction is undefined for point lights. + * The vector may be normalized, but it needn't..<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the position + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> V3 getDirection(AiWrapperProvider<V3, M4, C, N, Q> + wrapperProvider) { + + return (V3) m_direction; + } + + + /** + * Constant light attenuation factor.<p> + * + * The intensity of the light source at a given distance 'd' from + * the light's position is + * <code>Atten = 1/( att0 + att1 * d + att2 * d*d)</code> + * This member corresponds to the att0 variable in the equation. + * Naturally undefined for directional lights. + * + * @return the constant light attenuation factor + */ + public float getAttenuationConstant() { + return m_attenuationConstant; + } + + + /** + * Linear light attenuation factor.<p> + * + * The intensity of the light source at a given distance 'd' from + * the light's position is + * <code>Atten = 1/( att0 + att1 * d + att2 * d*d)</code> + * This member corresponds to the att1 variable in the equation. + * Naturally undefined for directional lights. + * + * @return the linear light attenuation factor + */ + public float getAttenuationLinear() { + return m_attenuationLinear; + } + + + /** + * Quadratic light attenuation factor.<p> + * + * The intensity of the light source at a given distance 'd' from + * the light's position is + * <code>Atten = 1/( att0 + att1 * d + att2 * d*d)</code> + * This member corresponds to the att2 variable in the equation. + * Naturally undefined for directional lights. + * + * @return the quadratic light attenuation factor + */ + public float getAttenuationQuadratic() { + return m_attenuationQuadratic; + } + + + /** + * Diffuse color of the light source.<p> + * + * The diffuse light color is multiplied with the diffuse + * material color to obtain the final color that contributes + * to the diffuse shading term.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiColor}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the diffuse color (alpha will be 1) + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getColorDiffuse( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + return (C) m_diffuse; + } + + + /** + * Specular color of the light source.<p> + * + * The specular light color is multiplied with the specular + * material color to obtain the final color that contributes + * to the specular shading term.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiColor}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the specular color (alpha will be 1) + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getColorSpecular( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + return (C) m_specular; + } + + + /** + * Ambient color of the light source.<p> + * + * The ambient light color is multiplied with the ambient + * material color to obtain the final color that contributes + * to the ambient shading term. Most renderers will ignore + * this value it, is just a remaining of the fixed-function pipeline + * that is still supported by quite many file formats.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiColor}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the ambient color (alpha will be 1) + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getColorAmbient( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + return (C) m_ambient; + } + + + /** + * Inner angle of a spot light's light cone.<p> + * + * The spot light has maximum influence on objects inside this + * angle. The angle is given in radians. It is 2PI for point + * lights and undefined for directional lights. + * + * @return the inner angle + */ + public float getAngleInnerCone() { + return m_innerCone; + } + + + /** + * Outer angle of a spot light's light cone.<p> + * + * The spot light does not affect objects outside this angle. + * The angle is given in radians. It is 2PI for point lights and + * undefined for directional lights. The outer angle must be + * greater than or equal to the inner angle. + * It is assumed that the application uses a smooth + * interpolation between the inner and the outer cone of the + * spot light. + * + * @return the outer angle + */ + public float getAngleOuterCone() { + return m_outerCone; + } + + + /** + * Name. + */ + private final String m_name; + + + /** + * Type. + */ + private final AiLightType m_type; + + + /** + * Position. + */ + private final Object m_position; + + + /** + * Direction. + */ + private final Object m_direction; + + + /** + * Constant attenuation. + */ + private final float m_attenuationConstant; + + + /** + * Linear attenuation. + */ + private final float m_attenuationLinear; + + + /** + * Quadratic attenuation. + */ + private final float m_attenuationQuadratic; + + + /** + * Diffuse color. + */ + private final Object m_diffuse; + + + /** + * Specular color. + */ + private final Object m_specular; + + + /** + * Ambient color. + */ + private final Object m_ambient; + + + /** + * Inner cone of spotlight. + */ + private final float m_innerCone; + + + /** + * Outer cone of spotlight. + */ + private final float m_outerCone; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiLightType.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiLightType.java new file mode 100644 index 0000000..33fd722 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiLightType.java @@ -0,0 +1,123 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * List of light types supported by {@link AiLight}. + */ +public enum AiLightType { + /** + * A directional light source.<p> + * + * A directional light has a well-defined direction but is infinitely far + * away. That's quite a good approximation for sun light. + */ + DIRECTIONAL(0x1), + + + /** + * A point light source.<p> + * + * A point light has a well-defined position in space but no direction - + * it emits light in all directions. A normal bulb is a point light. + */ + POINT(0x2), + + + /** + * A spot light source.<p> + * + * A spot light emits light in a specific angle. It has a position and a + * direction it is pointing to. A good example for a spot light is a light + * spot in sport arenas. + */ + SPOT(0x3), + + + /** + * The generic light level of the world, including the bounces of all other + * lightsources. <p> + * + * Typically, there's at most one ambient light in a scene. + * This light type doesn't have a valid position, direction, or + * other properties, just a color. + */ + AMBIENT(0x4); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static AiLightType fromRawValue(int rawValue) { + for (AiLightType type : AiLightType.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiLightType(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMaterial.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMaterial.java new file mode 100644 index 0000000..b571f14 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMaterial.java @@ -0,0 +1,1199 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * Data structure for a material.<p> + * + * Depending on the imported scene and scene format, individual properties + * might be present or not. A list of all imported properties can be retrieved + * via {@link #getProperties()}.<p> + * + * This class offers <code>getXXX()</code> for all supported properties. These + * methods are fail-save, i.e., will return a default value when the + * corresponding property is not set. To change the built in default values, + * use the <code>setDefaultXXX()</code> methods.<p> + * + * If your application expects a certain set of properties to be available, + * the {@link #hasProperties(Set)} method can be used to check whether all + * these properties are actually set. If this check fails, you can still + * use this material via the <code>getXXX()</code> methods without special + * error handling code as the implementation guarantees to return default + * values for missing properties. This check will not work on texture related + * properties (i.e., properties starting with <code>TEX_</code>). + */ +public final class AiMaterial { + /** + * List of properties. + */ + private final List<Property> m_properties = new ArrayList<Property>(); + + /** + * Number of textures for each type. + */ + private final Map<AiTextureType, Integer> m_numTextures = + new EnumMap<AiTextureType, Integer>(AiTextureType.class); + + /** + * Enumerates all supported material properties. + */ + public static enum PropertyKey { + /** + * Name. + */ + NAME("?mat.name", String.class), + + /** + * Two-sided flag. + */ + TWO_SIDED("$mat.twosided", Integer.class), + + /** + * Shading mode. + */ + SHADING_MODE("$mat.shadingm", AiShadingMode.class), + + /** + * Wireframe flag. + */ + WIREFRAME("$mat.wireframe", Integer.class), + + /** + * Blend mode. + */ + BLEND_MODE("$mat.blend", AiBlendMode.class), + + /** + * Opacity. + */ + OPACITY("$mat.opacity", Float.class), + + /** + * Bump scaling. + */ + BUMP_SCALING("$mat.bumpscaling", Float.class), + + + /** + * Shininess. + */ + SHININESS("$mat.shininess", Float.class), + + + /** + * Reflectivity. + */ + REFLECTIVITY("$mat.reflectivity", Float.class), + + + /** + * Shininess strength. + */ + SHININESS_STRENGTH("$mat.shinpercent", Float.class), + + + /** + * Refract index. + */ + REFRACTI("$mat.refracti", Float.class), + + + /** + * Diffuse color. + */ + COLOR_DIFFUSE("$clr.diffuse", Object.class), + + + /** + * Ambient color. + */ + COLOR_AMBIENT("$clr.ambient", Object.class), + + + /** + * Ambient color. + */ + COLOR_SPECULAR("$clr.specular", Object.class), + + + /** + * Emissive color. + */ + COLOR_EMISSIVE("$clr.emissive", Object.class), + + + /** + * Transparent color. + */ + COLOR_TRANSPARENT("$clr.transparent", Object.class), + + + /** + * Reflective color. + */ + COLOR_REFLECTIVE("$clr.reflective", Object.class), + + + /** + * Global background image. + */ + GLOBAL_BACKGROUND_IMAGE("?bg.global", String.class), + + + /** + * Texture file path. + */ + TEX_FILE("$tex.file", String.class), + + + /** + * Texture uv index. + */ + TEX_UV_INDEX("$tex.uvwsrc", Integer.class), + + + /** + * Texture blend factor. + */ + TEX_BLEND("$tex.blend", Float.class), + + + /** + * Texture operation. + */ + TEX_OP("$tex.op", AiTextureOp.class), + + + /** + * Texture map mode for u axis. + */ + TEX_MAP_MODE_U("$tex.mapmodeu", AiTextureMapMode.class), + + + /** + * Texture map mode for v axis. + */ + TEX_MAP_MODE_V("$tex.mapmodev", AiTextureMapMode.class), + + + /** + * Texture map mode for w axis. + */ + TEX_MAP_MODE_W("$tex.mapmodew", AiTextureMapMode.class); + + /** + * Constructor. + * + * @param key key name as used by assimp + * @param type key type, used for casts and checks + */ + private PropertyKey(String key, Class<?> type) { + m_key = key; + m_type = type; + } + + + /** + * Key. + */ + private final String m_key; + + + /** + * Type. + */ + private final Class<?> m_type; + } + + + /** + * A very primitive RTTI system for the contents of material properties. + */ + public static enum PropertyType { + /** + * Array of single-precision (32 Bit) floats. + */ + FLOAT(0x1), + + + /** + * The material property is a string. + */ + STRING(0x3), + + + /** + * Array of (32 Bit) integers. + */ + INTEGER(0x4), + + + /** + * Simple binary buffer, content undefined. Not convertible to anything. + */ + BUFFER(0x5); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static PropertyType fromRawValue(int rawValue) { + for (PropertyType type : PropertyType.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private PropertyType(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; + } + + + /** + * Data structure for a single material property.<p> + * + * As an user, you'll probably never need to deal with this data structure. + * Just use the provided get() family of functions to query material + * properties easily. + */ + public static final class Property { + /** + * Key. + */ + private final String m_key; + + + /** + * Semantic. + */ + private final int m_semantic; + + + /** + * Index. + */ + private final int m_index; + + + /** + * Type. + */ + private final PropertyType m_type; + + + /** + * Data. + */ + private final Object m_data; + + /** + * Constructor. + * + * @param key + * @param semantic + * @param index + * @param type + * @param data + */ + Property(String key, int semantic, int index, int type, + Object data) { + + m_key = key; + m_semantic = semantic; + m_index = index; + m_type = PropertyType.fromRawValue(type); + m_data = data; + } + + + /** + * Constructor. + * + * @param key + * @param semantic + * @param index + * @param type + * @param dataLen + */ + Property(String key, int semantic, int index, int type, + int dataLen) { + + m_key = key; + m_semantic = semantic; + m_index = index; + m_type = PropertyType.fromRawValue(type); + + ByteBuffer b = ByteBuffer.allocateDirect(dataLen); + b.order(ByteOrder.nativeOrder()); + + m_data = b; + } + + + /** + * Returns the key of the property.<p> + * + * Keys are generally case insensitive. + * + * @return the key + */ + public String getKey() { + return m_key; + } + + + /** + * Textures: Specifies their exact usage semantic. + * For non-texture properties, this member is always 0 + * (or, better-said, #aiTextureType_NONE). + * + * @return the semantic + */ + public int getSemantic() { + return m_semantic; + } + + + /** + * Textures: Specifies the index of the texture. + * For non-texture properties, this member is always 0. + * + * @return the index + */ + public int getIndex() { + return m_index; + } + + + /** + * Type information for the property.<p> + * + * Defines the data layout inside the data buffer. This is used + * by the library internally to perform debug checks and to + * utilize proper type conversions. + * (It's probably a hacky solution, but it works.) + * + * @return the type + */ + public PropertyType getType() { + return m_type; + } + + + /** + * Binary buffer to hold the property's value. + * The size of the buffer is always mDataLength. + * + * @return the data + */ + public Object getData() { + return m_data; + } + } + + + /** + * Constructor. + */ + AiMaterial() { + /* nothing to do */ + } + + + /** + * Checks whether the given set of properties is available. + * + * @param keys the keys to check + * @return true if all properties are available, false otherwise + */ + public boolean hasProperties(Set<PropertyKey> keys) { + for (PropertyKey key : keys) { + if (null == getProperty(key.m_key)) { + return false; + } + } + + return true; + } + + + /** + * Sets a default value.<p> + * + * The passed in Object must match the type of the key as returned by + * the corresponding <code>getXXX()</code> method. + * + * @param key the key + * @param defaultValue the new default, may not be null + * @throws IllegalArgumentException if defaultValue is null or has a wrong + * type + */ + public void setDefault(PropertyKey key, Object defaultValue) { + if (null == defaultValue) { + throw new IllegalArgumentException("defaultValue may not be null"); + } + if (key.m_type != defaultValue.getClass()) { + throw new IllegalArgumentException( + "defaultValue has wrong type, " + + "expected: " + key.m_type + ", found: " + + defaultValue.getClass()); + } + + m_defaults.put(key, defaultValue); + } + + + // {{ Fail-save Getters + /** + * Returns the name of the material.<p> + * + * If missing, defaults to empty string + * + * @return the name + */ + public String getName() { + return getTyped(PropertyKey.NAME, String.class); + } + + + /** + * Returns the two-sided flag.<p> + * + * If missing, defaults to 0 + * + * @return the two-sided flag + */ + public int getTwoSided() { + return getTyped(PropertyKey.TWO_SIDED, Integer.class); + } + + + /** + * Returns the shading mode.<p> + * + * If missing, defaults to {@link AiShadingMode#FLAT} + * + * @return the shading mode + */ + public AiShadingMode getShadingMode() { + Property p = getProperty(PropertyKey.SHADING_MODE.m_key); + + if (null == p || null == p.getData()) { + return (AiShadingMode) m_defaults.get(PropertyKey.SHADING_MODE); + } + + return AiShadingMode.fromRawValue((Integer) p.getData()); + } + + + /** + * Returns the wireframe flag.<p> + * + * If missing, defaults to 0 + * + * @return the wireframe flag + */ + public int getWireframe() { + return getTyped(PropertyKey.WIREFRAME, Integer.class); + } + + + /** + * Returns the blend mode.<p> + * + * If missing, defaults to {@link AiBlendMode#DEFAULT} + * + * @return the blend mode + */ + public AiBlendMode getBlendMode() { + Property p = getProperty(PropertyKey.BLEND_MODE.m_key); + + if (null == p || null == p.getData()) { + return (AiBlendMode) m_defaults.get(PropertyKey.BLEND_MODE); + } + + return AiBlendMode.fromRawValue((Integer) p.getData()); + } + + + /** + * Returns the opacity.<p> + * + * If missing, defaults to 1.0 + * + * @return the opacity + */ + public float getOpacity() { + return getTyped(PropertyKey.OPACITY, Float.class); + } + + + /** + * Returns the bump scaling factor.<p> + * + * If missing, defaults to 1.0 + * + * @return the bump scaling factor + */ + public float getBumpScaling() { + return getTyped(PropertyKey.BUMP_SCALING, Float.class); + } + + + /** + * Returns the shininess.<p> + * + * If missing, defaults to 1.0 + * + * @return the shininess + */ + public float getShininess() { + return getTyped(PropertyKey.SHININESS, Float.class); + } + + + /** + * Returns the reflectivity.<p> + * + * If missing, defaults to 0.0 + * + * @return the reflectivity + */ + public float getReflectivity() { + return getTyped(PropertyKey.REFLECTIVITY, Float.class); + } + + + /** + * Returns the shininess strength.<p> + * + * If missing, defaults to 0.0 + * + * @return the shininess strength + */ + public float getShininessStrength() { + return getTyped(PropertyKey.SHININESS_STRENGTH, Float.class); + } + + + /** + * Returns the refract index.<p> + * + * If missing, defaults to 0.0 + * + * @return the refract index + */ + public float getRefractIndex() { + return getTyped(PropertyKey.REFRACTI, Float.class); + } + + + /** + * Returns the diffuse color.<p> + * + * If missing, defaults to opaque white (1.0, 1.0, 1.0, 1.0)<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the diffuse color + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getDiffuseColor( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + Property p = getProperty(PropertyKey.COLOR_DIFFUSE.m_key); + + if (null == p || null == p.getData()) { + Object def = m_defaults.get(PropertyKey.COLOR_DIFFUSE); + if (def == null) { + return (C) Jassimp.wrapColor4(1.0f, 1.0f, 1.0f, 1.0f); + } + + return (C) def; + } + + return (C) p.getData(); + } + + + /** + * Returns the ambient color.<p> + * + * If missing, defaults to opaque white (1.0, 1.0, 1.0, 1.0)<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the ambient color + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getAmbientColor( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + Property p = getProperty(PropertyKey.COLOR_AMBIENT.m_key); + + if (null == p || null == p.getData()) { + Object def = m_defaults.get(PropertyKey.COLOR_AMBIENT); + if (def == null) { + return (C) Jassimp.wrapColor4(1.0f, 1.0f, 1.0f, 1.0f); + } + + return (C) def; + } + + return (C) p.getData(); + } + + + /** + * Returns the specular color.<p> + * + * If missing, defaults to opaque white (1.0, 1.0, 1.0, 1.0)<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the specular color + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getSpecularColor( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + Property p = getProperty(PropertyKey.COLOR_SPECULAR.m_key); + + if (null == p || null == p.getData()) { + Object def = m_defaults.get(PropertyKey.COLOR_SPECULAR); + if (def == null) { + return (C) Jassimp.wrapColor4(1.0f, 1.0f, 1.0f, 1.0f); + } + + return (C) def; + } + + return (C) p.getData(); + } + + + /** + * Returns the emissive color.<p> + * + * If missing, defaults to opaque white (1.0, 1.0, 1.0, 1.0)<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the emissive color + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getEmissiveColor( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + Property p = getProperty(PropertyKey.COLOR_EMISSIVE.m_key); + + if (null == p || null == p.getData()) { + Object def = m_defaults.get(PropertyKey.COLOR_EMISSIVE); + if (def == null) { + return (C) Jassimp.wrapColor4(1.0f, 1.0f, 1.0f, 1.0f); + } + + return (C) def; + } + + return (C) p.getData(); + } + + + /** + * Returns the transparent color.<p> + * + * If missing, defaults to opaque white (1.0, 1.0, 1.0, 1.0)<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the transparent color + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getTransparentColor( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + Property p = getProperty(PropertyKey.COLOR_TRANSPARENT.m_key); + + if (null == p || null == p.getData()) { + Object def = m_defaults.get(PropertyKey.COLOR_TRANSPARENT); + if (def == null) { + return (C) Jassimp.wrapColor4(1.0f, 1.0f, 1.0f, 1.0f); + } + + return (C) def; + } + + return (C) p.getData(); + } + + + /** + * Returns the reflective color.<p> + * + * If missing, defaults to opaque white (1.0, 1.0, 1.0, 1.0)<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the reflective color + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> C getReflectiveColor( + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + Property p = getProperty(PropertyKey.COLOR_REFLECTIVE.m_key); + + if (null == p || null == p.getData()) { + Object def = m_defaults.get(PropertyKey.COLOR_REFLECTIVE); + if (def == null) { + return (C) Jassimp.wrapColor4(1.0f, 1.0f, 1.0f, 1.0f); + } + + return (C) def; + } + + return (C) p.getData(); + } + + + /** + * Returns the global background image.<p> + * + * If missing, defaults to empty string + * + * @return the global background image + */ + public String getGlobalBackgroundImage() { + return getTyped(PropertyKey.GLOBAL_BACKGROUND_IMAGE, String.class); + } + + + /** + * Returns the number of textures of the given type. + * + * @param type the type + * @return the number of textures + */ + public int getNumTextures(AiTextureType type) { + return m_numTextures.get(type); + } + + + /** + * Returns the texture file.<p> + * + * If missing, defaults to empty string + * + * @param type the texture type + * @param index the index in the texture stack + * @return the file + * @throws IndexOutOfBoundsException if index is invalid + */ + public String getTextureFile(AiTextureType type, int index) { + checkTexRange(type, index); + + return getTyped(PropertyKey.TEX_FILE, type, index, String.class); + } + + + /** + * Returns the index of the UV coordinate set used by the texture.<p> + * + * If missing, defaults to 0 + * + * @param type the texture type + * @param index the index in the texture stack + * @return the UV index + * @throws IndexOutOfBoundsException if index is invalid + */ + public int getTextureUVIndex(AiTextureType type, int index) { + checkTexRange(type, index); + + return getTyped(PropertyKey.TEX_UV_INDEX, type, index, Integer.class); + } + + + /** + * Returns the blend factor of the texture.<p> + * + * If missing, defaults to 1.0 + * + * @param type the texture type + * @param index the index in the texture stack + * @return the blend factor + */ + public float getBlendFactor(AiTextureType type, int index) { + checkTexRange(type, index); + + return getTyped(PropertyKey.TEX_BLEND, type, index, Float.class); + } + + + /** + * Returns the texture operation.<p> + * + * If missing, defaults to {@link AiTextureOp#ADD} + * + * @param type the texture type + * @param index the index in the texture stack + * @return the texture operation + */ + public AiTextureOp getTextureOp(AiTextureType type, int index) { + checkTexRange(type, index); + + Property p = getProperty(PropertyKey.TEX_OP.m_key); + + if (null == p || null == p.getData()) { + return (AiTextureOp) m_defaults.get(PropertyKey.TEX_OP); + } + + return AiTextureOp.fromRawValue((Integer) p.getData()); + } + + + /** + * Returns the texture mapping mode for the u axis.<p> + * + * If missing, defaults to {@link AiTextureMapMode#CLAMP} + * + * @param type the texture type + * @param index the index in the texture stack + * @return the texture mapping mode + */ + public AiTextureMapMode getTextureMapModeU(AiTextureType type, int index) { + checkTexRange(type, index); + + Property p = getProperty(PropertyKey.TEX_MAP_MODE_U.m_key); + + if (null == p || null == p.getData()) { + return (AiTextureMapMode) m_defaults.get( + PropertyKey.TEX_MAP_MODE_U); + } + + return AiTextureMapMode.fromRawValue((Integer) p.getData()); + } + + + /** + * Returns the texture mapping mode for the v axis.<p> + * + * If missing, defaults to {@link AiTextureMapMode#CLAMP} + * + * @param type the texture type + * @param index the index in the texture stack + * @return the texture mapping mode + */ + public AiTextureMapMode getTextureMapModeV(AiTextureType type, int index) { + checkTexRange(type, index); + + Property p = getProperty(PropertyKey.TEX_MAP_MODE_V.m_key); + + if (null == p || null == p.getData()) { + return (AiTextureMapMode) m_defaults.get( + PropertyKey.TEX_MAP_MODE_V); + } + + return AiTextureMapMode.fromRawValue((Integer) p.getData()); + } + + + /** + * Returns the texture mapping mode for the w axis.<p> + * + * If missing, defaults to {@link AiTextureMapMode#CLAMP} + * + * @param type the texture type + * @param index the index in the texture stack + * @return the texture mapping mode + */ + public AiTextureMapMode getTextureMapModeW(AiTextureType type, int index) { + checkTexRange(type, index); + + Property p = getProperty(PropertyKey.TEX_MAP_MODE_W.m_key); + + if (null == p || null == p.getData()) { + return (AiTextureMapMode) m_defaults.get( + PropertyKey.TEX_MAP_MODE_W); + } + + return AiTextureMapMode.fromRawValue((Integer) p.getData()); + } + + + /** + * Returns all information related to a single texture. + * + * @param type the texture type + * @param index the index in the texture stack + * @return the texture information + */ + public AiTextureInfo getTextureInfo(AiTextureType type, int index) { + return new AiTextureInfo(type, index, getTextureFile(type, index), + getTextureUVIndex(type, index), getBlendFactor(type, index), + getTextureOp(type, index), getTextureMapModeW(type, index), + getTextureMapModeW(type, index), + getTextureMapModeW(type, index)); + } + // }} + + // {{ Generic Getters + /** + * Returns a single property based on its key. + * + * @param key the key + * @return the property or null if the property is not set + */ + public Property getProperty(String key) { + for (Property property : m_properties) { + if (property.getKey().equals(key)) { + return property; + } + } + + return null; + } + + + /** + * Returns a single property based on its key. + * + * @param key the key + * @param semantic the semantic type (texture type) + * @param index the index + * @return the property or null if the property is not set + */ + public Property getProperty(String key, int semantic, int index) { + for (Property property : m_properties) { + if (property.getKey().equals(key) && + property.m_semantic == semantic && + property.m_index == index) { + + return property; + } + } + + return null; + } + + + /** + * Returns all properties of the material. + * + * @return the list of properties + */ + public List<Property> getProperties() { + return m_properties; + } + // }} + + + /** + * Helper method. Returns typed property data. + * + * @param <T> type + * @param key the key + * @param clazz type + * @return the data + */ + private <T> T getTyped(PropertyKey key, Class<T> clazz) { + Property p = getProperty(key.m_key); + + if (null == p || null == p.getData()) { + return clazz.cast(m_defaults.get(key)); + } + + return clazz.cast(p.getData()); + } + + + /** + * Helper method. Returns typed property data. + * + * @param <T> type + * @param key the key + * @param type the texture type + * @param index the texture index + * @param clazz type + * @return the data + */ + private <T> T getTyped(PropertyKey key, AiTextureType type, int index, + Class<T> clazz) { + + Property p = getProperty(key.m_key, AiTextureType.toRawValue(type), + index); + + if (null == p || null == p.getData()) { + return clazz.cast(m_defaults.get(key)); + } + + return clazz.cast(p.getData()); + } + + + /** + * Checks that index is valid an throw an exception if not. + * + * @param type the type + * @param index the index to check + */ + private void checkTexRange(AiTextureType type, int index) { + if (index < 0 || index > m_numTextures.get(type)) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + + m_numTextures.get(type)); + } + } + + + /** + * Defaults for missing properties. + */ + private Map<PropertyKey, Object> m_defaults = + new EnumMap<PropertyKey, Object>(PropertyKey.class); + + { + setDefault(PropertyKey.NAME, ""); + setDefault(PropertyKey.TWO_SIDED, 0); + setDefault(PropertyKey.SHADING_MODE, AiShadingMode.FLAT); + setDefault(PropertyKey.WIREFRAME, 0); + setDefault(PropertyKey.BLEND_MODE, AiBlendMode.DEFAULT); + setDefault(PropertyKey.OPACITY, 1.0f); + setDefault(PropertyKey.BUMP_SCALING, 1.0f); + setDefault(PropertyKey.SHININESS, 1.0f); + setDefault(PropertyKey.REFLECTIVITY, 0.0f); + setDefault(PropertyKey.SHININESS_STRENGTH, 0.0f); + setDefault(PropertyKey.REFRACTI, 0.0f); + + /* bypass null checks for colors */ + m_defaults.put(PropertyKey.COLOR_DIFFUSE, null); + m_defaults.put(PropertyKey.COLOR_AMBIENT, null); + m_defaults.put(PropertyKey.COLOR_SPECULAR, null); + m_defaults.put(PropertyKey.COLOR_EMISSIVE, null); + m_defaults.put(PropertyKey.COLOR_TRANSPARENT, null); + m_defaults.put(PropertyKey.COLOR_REFLECTIVE, null); + + setDefault(PropertyKey.GLOBAL_BACKGROUND_IMAGE, ""); + + /* texture related values */ + setDefault(PropertyKey.TEX_FILE, ""); + setDefault(PropertyKey.TEX_UV_INDEX, 0); + setDefault(PropertyKey.TEX_BLEND, 1.0f); + setDefault(PropertyKey.TEX_OP, AiTextureOp.ADD); + setDefault(PropertyKey.TEX_MAP_MODE_U, AiTextureMapMode.CLAMP); + setDefault(PropertyKey.TEX_MAP_MODE_V, AiTextureMapMode.CLAMP); + setDefault(PropertyKey.TEX_MAP_MODE_W, AiTextureMapMode.CLAMP); + + /* ensure we have defaults for everything */ + for (PropertyKey key : PropertyKey.values()) { + if (!m_defaults.containsKey(key)) { + throw new IllegalStateException("missing default for: " + key); + } + } + } + + + /** + * This method is used by JNI, do not call or modify. + * + * @param type the type + * @param number the number + */ + @SuppressWarnings("unused") + private void setTextureNumber(int type, int number) { + m_numTextures.put(AiTextureType.fromRawValue(type), number); + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMatrix4f.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMatrix4f.java new file mode 100644 index 0000000..f78c951 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMatrix4f.java @@ -0,0 +1,133 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +/** + * Simple 4x4 matrix of floats. + */ +public final class AiMatrix4f { + /** + * Wraps the given array of floats as matrix. + * <p> + * + * The array must have exactly 16 entries. The data in the array must be in + * row-major order. + * + * @param data + * the array to wrap, may not be null + */ + public AiMatrix4f(float[] data) { + if (data == null) { + throw new IllegalArgumentException("data may not be null"); + } + if (data.length != 16) { + throw new IllegalArgumentException("array length is not 16"); + } + + m_data = data; + } + + /** + * Gets an element of the matrix. + * + * @param row + * the row + * @param col + * the column + * @return the element at the given position + */ + public float get(int row, int col) { + if (row < 0 || row > 3) { + throw new IndexOutOfBoundsException("Index: " + row + ", Size: 4"); + } + if (col < 0 || col > 3) { + throw new IndexOutOfBoundsException("Index: " + col + ", Size: 4"); + } + + return m_data[row * 4 + col]; + } + + /** + * Stores the matrix in a new direct ByteBuffer with native byte order. + * <p> + * + * The returned buffer can be passed to rendering APIs such as LWJGL, e.g., + * as parameter for <code>GL20.glUniformMatrix4()</code>. Be sure to set + * <code>transpose</code> to <code>true</code> in this case, as OpenGL + * expects the matrix in column order. + * + * @return a new native order, direct ByteBuffer + */ + public FloatBuffer toByteBuffer() { + ByteBuffer bbuf = ByteBuffer.allocateDirect(16 * 4); + bbuf.order(ByteOrder.nativeOrder()); + FloatBuffer fbuf = bbuf.asFloatBuffer(); + fbuf.put(m_data); + fbuf.flip(); + + return fbuf; + } + + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + + for (int row = 0; row < 4; row++) { + for (int col = 0; col < 4; col++) { + buf.append(m_data[row * 4 + col]).append(" "); + } + buf.append("\n"); + } + + return buf.toString(); + } + + + /** + * Data buffer. + */ + private final float[] m_data; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMesh.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMesh.java new file mode 100644 index 0000000..eb2ff3c --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMesh.java @@ -0,0 +1,1421 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + + +/** + * A mesh represents a geometry or model with a single material. + * <p> + * + * <h3>Data</h3> + * Meshes usually consist of a number of vertices and a series of faces + * referencing the vertices. In addition there might be a series of bones, each + * of them addressing a number of vertices with a certain weight. Vertex data is + * presented in channels with each channel containing a single per-vertex + * information such as a set of texture coordinates or a normal vector.<p> + * + * Faces consist of one or more references to vertices, called vertex indices. + * The {@link #getPrimitiveTypes()} method can be used to check what + * face types are present in the mesh. Note that a single mesh can possess + * faces of different types. The number of indices used by a specific face can + * be retrieved with the {@link #getFaceNumIndices(int)} method. + * + * + * <h3>API for vertex and face data</h3> + * The jassimp interface for accessing vertex and face data is not a one-to-one + * mapping of the c/c++ interface. The c/c++ interface uses an object-oriented + * approach to represent data, which provides a considerable + * overhead using a naive java based realization (cache locality would be + * unpredictable and most likely bad, bulk data transfer would be impossible). + * <p> + * + * The jassimp interface uses flat byte buffers to store vertex and face data. + * This data can be accessed through three APIs: + * <ul> + * <li><b>Buffer API:</b> the <code>getXXXBuffer()</code> methods return + * raw data buffers. + * <li><b>Direct API:</b> the <code>getXXX()</code> methods allow reading + * and writing of individual data values. + * <li><b>Wrapped API:</b> the <code>getWrappedXXX()</code> methods provide + * an object oriented view on the data. + * </ul> + * + * The Buffer API is optimized for use in conjunction with rendering APIs + * such as LWJGL. The returned buffers are guaranteed to have native byte order + * and to be direct byte buffers. They can be passed directly to LWJGL + * methods, e.g., to fill VBOs with data. Each invocation of a + * <code>getXXXBuffer()</code> method will return a new view of the internal + * buffer, i.e., if is safe to use the relative byte buffer operations. + * The Buffer API provides the best performance of all three APIs, especially + * if large data volumes have to be processed.<p> + * + * The Direct API provides an easy to use interface for reading and writing + * individual data values. Its performance is comparable to the Buffer API's + * performance for these operations. The main difference to the Buffer API is + * the missing support for bulk operations. If you intend to retrieve or modify + * large subsets of the raw data consider using the Buffer API, especially + * if the subsets are contiguous. + * <p> + * + * The Wrapped API offers an object oriented interface for accessing + * and modifying mesh data. As the name implies, this interface is realized + * through wrapper objects that provide a view on the raw data. For each + * invocation of a <code>getWrappedXXX()</code> method, a new wrapper object + * is created. Iterating over mesh data via this interface will create many + * short-lived wrapper objects which -depending on usage and virtual machine- + * may cause considerable garbage collection overhead. The Wrapped API provides + * the worst performance of all three APIs, which may nevertheless still be + * good enough to warrant its usage. See {@link AiWrapperProvider} for more + * details on wrappers. + * + * + * <h3>API for bones</h3> + * As there is no standardized way for doing skinning in different graphics + * engines, bones are not represented as flat buffers but as object structure. + * Users of this library should convert this structure to the format required + * by the specific graphics engine. + * + * + * <h3>Changing Data</h3> + * This class is designed to be mutable, i.e., the returned objects and buffers + * may be modified. It is not possible to add/remove vertices as this would + * require reallocation of the data buffers. Wrapped objects may or may not + * propagate changes to the underlying data buffers. Consult the documentation + * of your wrapper provider for details. The built in wrappers will propagate + * changes. + * <p> + * Modification of face data is theoretically possible by modifying the face + * buffer and the faceOffset buffer however it is strongly disadvised to do so + * because it might break all algorithms that depend on the internal consistency + * of these two data structures. + */ +public final class AiMesh { + /** + * Number of bytes per float value. + */ + private final int SIZEOF_FLOAT = Jassimp.NATIVE_FLOAT_SIZE; + + /** + * Number of bytes per int value. + */ + private final int SIZEOF_INT = Jassimp.NATIVE_INT_SIZE; + + /** + * Size of an AiVector3D in the native world. + */ + private final int SIZEOF_V3D = Jassimp.NATIVE_AIVEKTOR3D_SIZE; + + + /** + * The primitive types used by this mesh. + */ + private final Set<AiPrimitiveType> m_primitiveTypes = + EnumSet.noneOf(AiPrimitiveType.class); + + + /** + * Number of vertices in this mesh. + */ + private int m_numVertices = 0; + + + /** + * Number of faces in this mesh. + */ + private int m_numFaces = 0; + + /** + * Material used by this mesh. + */ + private int m_materialIndex = -1; + + /** + * The name of the mesh. + */ + private String m_name = ""; + + /** + * Buffer for vertex position data. + */ + private ByteBuffer m_vertices = null; + + /** + * Buffer for faces/ indices. + */ + private ByteBuffer m_faces = null; + + + /** + * Index structure for m_faces.<p> + * + * Only used by meshes that are not pure triangular + */ + private ByteBuffer m_faceOffsets = null; + + /** + * Buffer for normals. + */ + private ByteBuffer m_normals = null; + + /** + * Buffer for tangents. + */ + private ByteBuffer m_tangents = null; + + /** + * Buffer for bitangents. + */ + private ByteBuffer m_bitangents = null; + + /** + * Vertex colors. + */ + private ByteBuffer[] m_colorsets = + new ByteBuffer[JassimpConfig.MAX_NUMBER_COLORSETS]; + + /** + * Number of UV components for each texture coordinate set. + */ + private int[] m_numUVComponents = new int[JassimpConfig.MAX_NUMBER_TEXCOORDS]; + + /** + * Texture coordinates. + */ + private ByteBuffer[] m_texcoords = + new ByteBuffer[JassimpConfig.MAX_NUMBER_TEXCOORDS]; + + /** + * Bones. + */ + private final List<AiBone> m_bones = new ArrayList<AiBone>(); + + /** + * This class is instantiated via JNI, no accessible constructor. + */ + private AiMesh() { + /* nothing to do */ + } + + + /** + * Returns the primitive types used by this mesh. + * + * @return a set of primitive types used by this mesh + */ + public Set<AiPrimitiveType> getPrimitiveTypes() { + return m_primitiveTypes; + } + + + /** + * Tells whether the mesh is a pure triangle mesh, i.e., contains only + * triangular faces.<p> + * + * To automatically triangulate meshes the + * {@link AiPostProcessSteps#TRIANGULATE} post processing option can be + * used when loading the scene + * + * @return true if the mesh is a pure triangle mesh, false otherwise + */ + public boolean isPureTriangle() { + return m_primitiveTypes.contains(AiPrimitiveType.TRIANGLE) && + m_primitiveTypes.size() == 1; + } + + + /** + * Tells whether the mesh has vertex positions.<p> + * + * Meshes almost always contain position data + * + * @return true if positions are available + */ + public boolean hasPositions() { + return m_vertices != null; + } + + + /** + * Tells whether the mesh has faces.<p> + * + * Meshes almost always contain faces + * + * @return true if faces are available + */ + public boolean hasFaces() { + return m_faces != null; + } + + + /** + * Tells whether the mesh has normals. + * + * @return true if normals are available + */ + public boolean hasNormals() { + return m_normals != null; + } + + + /** + * Tells whether the mesh has tangents and bitangents.<p> + * + * It is not possible that it contains tangents and no bitangents (or the + * other way round). The existence of one of them implies that the second + * is there, too. + * + * @return true if tangents and bitangents are available + */ + public boolean hasTangentsAndBitangents() { + return m_tangents != null && m_tangents != null; + } + + + /** + * Tells whether the mesh has a vertex color set. + * + * @param colorset index of the color set + * @return true if colors are available + */ + public boolean hasColors(int colorset) { + return m_colorsets[colorset] != null; + } + + + /** + * Tells whether the mesh has any vertex colors.<p> + * + * Use {@link #hasColors(int)} to check which color sets are + * available. + * + * @return true if any colors are available + */ + public boolean hasVertexColors() { + for (ByteBuffer buf : m_colorsets) { + if (buf != null) { + return true; + } + } + + return false; + } + + + /** + * Tells whether the mesh has a texture coordinate set. + * + * @param coords index of the texture coordinate set + * @return true if texture coordinates are available + */ + public boolean hasTexCoords(int coords) { + return m_texcoords[coords] != null; + } + + + /** + * Tells whether the mesh has any texture coordinate sets.<p> + * + * Use {@link #hasTexCoords(int)} to check which texture coordinate + * sets are available + * + * @return true if any texture coordinates are available + */ + public boolean hasTexCoords() { + for (ByteBuffer buf : m_texcoords) { + if (buf != null) { + return true; + } + } + + return false; + } + + + /** + * Tells whether the mesh has bones. + * + * @return true if bones are available + */ + public boolean hasBones() { + return !m_bones.isEmpty(); + } + + + /** + * Returns the bones of this mesh. + * + * @return a list of bones + */ + public List<AiBone> getBones() { + return m_bones; + } + + + /** + * Returns the number of vertices in this mesh. + * + * @return the number of vertices. + */ + public int getNumVertices() { + return m_numVertices; + } + + + /** + * Returns the number of faces in the mesh. + * + * @return the number of faces + */ + public int getNumFaces() { + return m_numFaces; + } + + + /** + * Returns the number of vertex indices for a single face. + * + * @param face the face + * @return the number of indices + */ + public int getFaceNumIndices(int face) { + if (null == m_faceOffsets) { + if (face >= m_numFaces || face < 0) { + throw new IndexOutOfBoundsException("Index: " + face + + ", Size: " + m_numFaces); + } + return 3; + } + else { + /* + * no need to perform bound checks here as the array access will + * throw IndexOutOfBoundsExceptions if the index is invalid + */ + + if (face == m_numFaces - 1) { + return m_faces.capacity() / 4 - m_faceOffsets.getInt(face * 4); + } + + return m_faceOffsets.getInt((face + 1) * 4) - + m_faceOffsets.getInt(face * 4); + } + } + + + /** + * Returns the number of UV components for a texture coordinate set.<p> + * + * Possible values range from 1 to 3 (1D to 3D texture coordinates) + * + * @param coords the coordinate set + * @return the number of components + */ + public int getNumUVComponents(int coords) { + return m_numUVComponents[coords]; + } + + + /** + * Returns the material used by this mesh.<p> + * + * A mesh does use only a single material. If an imported model uses + * multiple materials, the import splits up the mesh. Use this value + * as index into the scene's material list. + * + * @return the material index + */ + public int getMaterialIndex() { + return m_materialIndex; + } + + + /** + * Returns the name of the mesh.<p> + * + * Not all meshes have a name, if no name is set an empty string is + * returned. + * + * @return the name or an empty string if no name is set + */ + public String getName() { + return m_name; + } + + + // CHECKSTYLE:OFF + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append("Mesh(").append(m_numVertices).append(" vertices, "). + append(m_numFaces).append(" faces"); + + if (hasNormals()) { + buf.append(", normals"); + } + if (hasTangentsAndBitangents()) { + buf.append(", (bi-)tangents"); + } + if (hasVertexColors()) { + buf.append(", colors"); + } + if (hasTexCoords()) { + buf.append(", texCoords"); + } + + buf.append(")"); + return buf.toString(); + } + // CHECKSTYLE:ON + + + // {{ Buffer API + /** + * Returns a buffer containing vertex positions.<p> + * + * A vertex position consists of a triple of floats, the buffer will + * therefore contain <code>3 * getNumVertices()</code> floats + * + * @return a native-order direct buffer, or null if no data is available + */ + public FloatBuffer getPositionBuffer() { + if (m_vertices == null) { + return null; + } + + return m_vertices.asFloatBuffer(); + } + + + /** + * Returns a buffer containing face data.<p> + * + * You should use the {@link #getIndexBuffer()} method if you are + * interested in getting an index buffer used by graphics APIs such as + * LWJGL.<p> + * + * The buffer contains all vertex indices from all faces as a flat list. If + * the mesh is a pure triangle mesh, the buffer returned by this method is + * identical to the buffer returned by {@link #getIndexBuffer()}. For other + * meshes, the {@link #getFaceOffsets()} method can be used to retrieve + * an index structure that allows addressing individual faces in the list. + * + * @return a native-order direct buffer, or null if no data is available + */ + public IntBuffer getFaceBuffer() { + if (m_faces == null) { + return null; + } + + return m_faces.asIntBuffer(); + } + + + /** + * Returns an index structure for the buffer returned by + * {@link #getFaceBuffer()}.<p> + * + * You should use the {@link #getIndexBuffer()} method if you are + * interested in getting an index buffer used by graphics APIs such as + * LWJGL.<p> + * + * The returned buffer contains one integer entry for each face. This entry + * specifies the offset at which the face's data is located inside the + * face buffer. The difference between two subsequent entries can be used + * to determine how many vertices belong to a given face (the last face + * contains all entries between the offset and the end of the face buffer). + * + * @return a native-order direct buffer, or null if no data is available + */ + public IntBuffer getFaceOffsets() { + if (m_faceOffsets == null) { + return null; + } + + return m_faceOffsets.asIntBuffer(); + } + + + + /** + * Returns a buffer containing vertex indices for the mesh's faces.<p> + * + * This method may only be called on pure triangle meshes, i.e., meshes + * containing only triangles. The {@link #isPureTriangle()} method can be + * used to check whether this is the case.<p> + * + * Indices are stored as integers, the buffer will therefore contain + * <code>3 * getNumVertices()</code> integers (3 indices per triangle) + * + * @return a native-order direct buffer + * @throws UnsupportedOperationException + * if the mesh is not a pure triangle mesh + */ + public IntBuffer getIndexBuffer() { + if (!isPureTriangle()) { + throw new UnsupportedOperationException( + "mesh is not a pure triangle mesh"); + } + + return getFaceBuffer(); + } + + + /** + * Returns a buffer containing normals.<p> + * + * A normal consists of a triple of floats, the buffer will + * therefore contain <code>3 * getNumVertices()</code> floats + * + * @return a native-order direct buffer + */ + public FloatBuffer getNormalBuffer() { + if (m_normals == null) { + return null; + } + + return m_normals.asFloatBuffer(); + } + + + /** + * Returns a buffer containing tangents.<p> + * + * A tangent consists of a triple of floats, the buffer will + * therefore contain <code>3 * getNumVertices()</code> floats + * + * @return a native-order direct buffer + */ + public FloatBuffer getTangentBuffer() { + if (m_tangents == null) { + return null; + } + + return m_tangents.asFloatBuffer(); + } + + + /** + * Returns a buffer containing bitangents.<p> + * + * A bitangent consists of a triple of floats, the buffer will + * therefore contain <code>3 * getNumVertices()</code> floats + * + * @return a native-order direct buffer + */ + public FloatBuffer getBitangentBuffer() { + if (m_bitangents == null) { + return null; + } + + return m_bitangents.asFloatBuffer(); + } + + + /** + * Returns a buffer containing vertex colors for a color set.<p> + * + * A vertex color consists of 4 floats (red, green, blue and alpha), the + * buffer will therefore contain <code>4 * getNumVertices()</code> floats + * + * @param colorset the color set + * + * @return a native-order direct buffer, or null if no data is available + */ + public FloatBuffer getColorBuffer(int colorset) { + if (m_colorsets[colorset] == null) { + return null; + } + + return m_colorsets[colorset].asFloatBuffer(); + } + + + /** + * Returns a buffer containing coordinates for a texture coordinate set.<p> + * + * A texture coordinate consists of up to 3 floats (u, v, w). The actual + * number can be queried via {@link #getNumUVComponents(int)}. The + * buffer will contain + * <code>getNumUVComponents(coords) * getNumVertices()</code> floats + * + * @param coords the texture coordinate set + * + * @return a native-order direct buffer, or null if no data is available + */ + public FloatBuffer getTexCoordBuffer(int coords) { + if (m_texcoords[coords] == null) { + return null; + } + + return m_texcoords[coords].asFloatBuffer(); + } + // }} + + + // {{ Direct API + /** + * Returns the x-coordinate of a vertex position. + * + * @param vertex the vertex index + * @return the x coordinate + */ + public float getPositionX(int vertex) { + if (!hasPositions()) { + throw new IllegalStateException("mesh has no positions"); + } + + checkVertexIndexBounds(vertex); + + return m_vertices.getFloat(vertex * 3 * SIZEOF_FLOAT); + } + + + /** + * Returns the y-coordinate of a vertex position. + * + * @param vertex the vertex index + * @return the y coordinate + */ + public float getPositionY(int vertex) { + if (!hasPositions()) { + throw new IllegalStateException("mesh has no positions"); + } + + checkVertexIndexBounds(vertex); + + return m_vertices.getFloat((vertex * 3 + 1) * SIZEOF_FLOAT); + } + + /** + * Returns the z-coordinate of a vertex position. + * + * @param vertex the vertex index + * @return the z coordinate + */ + public float getPositionZ(int vertex) { + if (!hasPositions()) { + throw new IllegalStateException("mesh has no positions"); + } + + checkVertexIndexBounds(vertex); + + return m_vertices.getFloat((vertex * 3 + 2) * SIZEOF_FLOAT); + } + + + /** + * Returns a vertex reference from a face.<p> + * + * A face contains <code>getFaceNumIndices(face)</code> vertex references. + * This method returns the n'th of these. The returned index can be passed + * directly to the vertex oriented methods, such as + * <code>getPosition()</code> etc. + * + * @param face the face + * @param n the reference + * @return a vertex index + */ + public int getFaceVertex(int face, int n) { + if (!hasFaces()) { + throw new IllegalStateException("mesh has no faces"); + } + + if (face >= m_numFaces || face < 0) { + throw new IndexOutOfBoundsException("Index: " + face + ", Size: " + + m_numFaces); + } + if (n >= getFaceNumIndices(face) || n < 0) { + throw new IndexOutOfBoundsException("Index: " + n + ", Size: " + + getFaceNumIndices(face)); + } + + int faceOffset = 0; + if (m_faceOffsets == null) { + faceOffset = 3 * face * SIZEOF_INT; + } + else { + faceOffset = m_faceOffsets.getInt(face * SIZEOF_INT) * SIZEOF_INT; + } + + return m_faces.getInt(faceOffset + n * SIZEOF_INT); + } + + + /** + * Returns the x-coordinate of a vertex normal. + * + * @param vertex the vertex index + * @return the x coordinate + */ + public float getNormalX(int vertex) { + if (!hasNormals()) { + throw new IllegalStateException("mesh has no normals"); + } + + checkVertexIndexBounds(vertex); + + return m_normals.getFloat(vertex * 3 * SIZEOF_FLOAT); + } + + + /** + * Returns the y-coordinate of a vertex normal. + * + * @param vertex the vertex index + * @return the y coordinate + */ + public float getNormalY(int vertex) { + if (!hasNormals()) { + throw new IllegalStateException("mesh has no normals"); + } + + checkVertexIndexBounds(vertex); + + return m_normals.getFloat((vertex * 3 + 1) * SIZEOF_FLOAT); + } + + + /** + * Returns the z-coordinate of a vertex normal. + * + * @param vertex the vertex index + * @return the z coordinate + */ + public float getNormalZ(int vertex) { + if (!hasNormals()) { + throw new IllegalStateException("mesh has no normals"); + } + + checkVertexIndexBounds(vertex); + + return m_normals.getFloat((vertex * 3 + 2) * SIZEOF_FLOAT); + } + + + /** + * Returns the x-coordinate of a vertex tangent. + * + * @param vertex the vertex index + * @return the x coordinate + */ + public float getTangentX(int vertex) { + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no tangents"); + } + + checkVertexIndexBounds(vertex); + + return m_tangents.getFloat(vertex * 3 * SIZEOF_FLOAT); + } + + + /** + * Returns the y-coordinate of a vertex bitangent. + * + * @param vertex the vertex index + * @return the y coordinate + */ + public float getTangentY(int vertex) { + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no bitangents"); + } + + checkVertexIndexBounds(vertex); + + return m_tangents.getFloat((vertex * 3 + 1) * SIZEOF_FLOAT); + } + + + /** + * Returns the z-coordinate of a vertex tangent. + * + * @param vertex the vertex index + * @return the z coordinate + */ + public float getTangentZ(int vertex) { + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no tangents"); + } + + checkVertexIndexBounds(vertex); + + return m_tangents.getFloat((vertex * 3 + 2) * SIZEOF_FLOAT); + } + + + /** + * Returns the x-coordinate of a vertex tangent. + * + * @param vertex the vertex index + * @return the x coordinate + */ + public float getBitangentX(int vertex) { + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no bitangents"); + } + + checkVertexIndexBounds(vertex); + + return m_bitangents.getFloat(vertex * 3 * SIZEOF_FLOAT); + } + + + /** + * Returns the y-coordinate of a vertex tangent. + * + * @param vertex the vertex index + * @return the y coordinate + */ + public float getBitangentY(int vertex) { + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no bitangents"); + } + + checkVertexIndexBounds(vertex); + + return m_bitangents.getFloat((vertex * 3 + 1) * SIZEOF_FLOAT); + } + + + /** + * Returns the z-coordinate of a vertex tangent. + * + * @param vertex the vertex index + * @return the z coordinate + */ + public float getBitangentZ(int vertex) { + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no bitangents"); + } + + checkVertexIndexBounds(vertex); + + return m_bitangents.getFloat((vertex * 3 + 2) * SIZEOF_FLOAT); + } + + + /** + * Returns the red color component of a color from a vertex color set. + * + * @param vertex the vertex index + * @param colorset the color set + * @return the red color component + */ + public float getColorR(int vertex, int colorset) { + if (!hasColors(colorset)) { + throw new IllegalStateException("mesh has no colorset " + colorset); + } + + checkVertexIndexBounds(vertex); + /* bound checks for colorset are done by java for us */ + + return m_colorsets[colorset].getFloat(vertex * 4 * SIZEOF_FLOAT); + } + + + /** + * Returns the green color component of a color from a vertex color set. + * + * @param vertex the vertex index + * @param colorset the color set + * @return the green color component + */ + public float getColorG(int vertex, int colorset) { + if (!hasColors(colorset)) { + throw new IllegalStateException("mesh has no colorset " + colorset); + } + + checkVertexIndexBounds(vertex); + /* bound checks for colorset are done by java for us */ + + return m_colorsets[colorset].getFloat((vertex * 4 + 1) * SIZEOF_FLOAT); + } + + + /** + * Returns the blue color component of a color from a vertex color set. + * + * @param vertex the vertex index + * @param colorset the color set + * @return the blue color component + */ + public float getColorB(int vertex, int colorset) { + if (!hasColors(colorset)) { + throw new IllegalStateException("mesh has no colorset " + colorset); + } + + checkVertexIndexBounds(vertex); + /* bound checks for colorset are done by java for us */ + + return m_colorsets[colorset].getFloat((vertex * 4 + 2) * SIZEOF_FLOAT); + } + + + /** + * Returns the alpha color component of a color from a vertex color set. + * + * @param vertex the vertex index + * @param colorset the color set + * @return the alpha color component + */ + public float getColorA(int vertex, int colorset) { + if (!hasColors(colorset)) { + throw new IllegalStateException("mesh has no colorset " + colorset); + } + + checkVertexIndexBounds(vertex); + /* bound checks for colorset are done by java for us */ + + return m_colorsets[colorset].getFloat((vertex * 4 + 3) * SIZEOF_FLOAT); + } + + + /** + * Returns the u component of a coordinate from a texture coordinate set. + * + * @param vertex the vertex index + * @param coords the texture coordinate set + * @return the u component + */ + public float getTexCoordU(int vertex, int coords) { + if (!hasTexCoords(coords)) { + throw new IllegalStateException( + "mesh has no texture coordinate set " + coords); + } + + checkVertexIndexBounds(vertex); + /* bound checks for coords are done by java for us */ + + return m_texcoords[coords].getFloat( + vertex * m_numUVComponents[coords] * SIZEOF_FLOAT); + } + + + /** + * Returns the v component of a coordinate from a texture coordinate set.<p> + * + * This method may only be called on 2- or 3-dimensional coordinate sets. + * Call <code>getNumUVComponents(coords)</code> to determine how may + * coordinate components are available. + * + * @param vertex the vertex index + * @param coords the texture coordinate set + * @return the v component + */ + public float getTexCoordV(int vertex, int coords) { + if (!hasTexCoords(coords)) { + throw new IllegalStateException( + "mesh has no texture coordinate set " + coords); + } + + checkVertexIndexBounds(vertex); + + /* bound checks for coords are done by java for us */ + + if (getNumUVComponents(coords) < 2) { + throw new IllegalArgumentException("coordinate set " + coords + + " does not contain 2D texture coordinates"); + } + + return m_texcoords[coords].getFloat( + (vertex * m_numUVComponents[coords] + 1) * SIZEOF_FLOAT); + } + + + /** + * Returns the w component of a coordinate from a texture coordinate set.<p> + * + * This method may only be called on 3-dimensional coordinate sets. + * Call <code>getNumUVComponents(coords)</code> to determine how may + * coordinate components are available. + * + * @param vertex the vertex index + * @param coords the texture coordinate set + * @return the w component + */ + public float getTexCoordW(int vertex, int coords) { + if (!hasTexCoords(coords)) { + throw new IllegalStateException( + "mesh has no texture coordinate set " + coords); + } + + checkVertexIndexBounds(vertex); + + /* bound checks for coords are done by java for us */ + + if (getNumUVComponents(coords) < 3) { + throw new IllegalArgumentException("coordinate set " + coords + + " does not contain 3D texture coordinates"); + } + + return m_texcoords[coords].getFloat( + (vertex * m_numUVComponents[coords] + 1) * SIZEOF_FLOAT); + } + // }} + + + // {{ Wrapped API + /** + * Returns the vertex position as 3-dimensional vector.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param vertex the vertex index + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the position wrapped as object + */ + public <V3, M4, C, N, Q> V3 getWrappedPosition(int vertex, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + if (!hasPositions()) { + throw new IllegalStateException("mesh has no positions"); + } + + checkVertexIndexBounds(vertex); + + return wrapperProvider.wrapVector3f(m_vertices, + vertex * 3 * SIZEOF_FLOAT, 3); + } + + + /** + * Returns the vertex normal as 3-dimensional vector.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param vertex the vertex index + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the normal wrapped as object + */ + public <V3, M4, C, N, Q> V3 getWrappedNormal(int vertex, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + if (!hasNormals()) { + throw new IllegalStateException("mesh has no positions"); + } + + checkVertexIndexBounds(vertex); + + return wrapperProvider.wrapVector3f(m_normals, + vertex * 3 * SIZEOF_FLOAT, 3); + } + + + /** + * Returns the vertex tangent as 3-dimensional vector.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param vertex the vertex index + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the tangent wrapped as object + */ + public <V3, M4, C, N, Q> V3 getWrappedTangent(int vertex, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no tangents"); + } + + checkVertexIndexBounds(vertex); + + return wrapperProvider.wrapVector3f(m_tangents, + vertex * 3 * SIZEOF_FLOAT, 3); + } + + + /** + * Returns the vertex bitangent as 3-dimensional vector.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param vertex the vertex index + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the bitangent wrapped as object + */ + public <V3, M4, C, N, Q> V3 getWrappedBitangent(int vertex, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + if (!hasTangentsAndBitangents()) { + throw new IllegalStateException("mesh has no bitangents"); + } + + checkVertexIndexBounds(vertex); + + return wrapperProvider.wrapVector3f(m_bitangents, + vertex * 3 * SIZEOF_FLOAT, 3); + } + + + /** + * Returns the vertex color.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiColor}. + * + * @param vertex the vertex index + * @param colorset the color set + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the vertex color wrapped as object + */ + public <V3, M4, C, N, Q> C getWrappedColor(int vertex, int colorset, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + if (!hasColors(colorset)) { + throw new IllegalStateException("mesh has no colorset " + colorset); + } + + checkVertexIndexBounds(vertex); + + return wrapperProvider.wrapColor( + m_colorsets[colorset], vertex * 4 * SIZEOF_FLOAT); + } + + + /** + * Returns the texture coordinates as n-dimensional vector.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param vertex the vertex index + * @param coords the texture coordinate set + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the texture coordinates wrapped as object + */ + public <V3, M4, C, N, Q> V3 getWrappedTexCoords(int vertex, int coords, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + if (!hasTexCoords(coords)) { + throw new IllegalStateException( + "mesh has no texture coordinate set " + coords); + } + + checkVertexIndexBounds(vertex); + + return wrapperProvider.wrapVector3f(m_texcoords[coords], + vertex * 3 * SIZEOF_FLOAT, getNumUVComponents(coords)); + } + // }} + + + // {{ Helpers + /** + * Throws an exception if the vertex index is not in the allowed range. + * + * @param vertex the index to check + */ + private void checkVertexIndexBounds(int vertex) { + if (vertex >= m_numVertices || vertex < 0) { + throw new IndexOutOfBoundsException("Index: " + vertex + + ", Size: " + m_numVertices); + } + } + // }} + + // {{ JNI interface + /* + * Channel constants used by allocate data channel. Do not modify or use + * as these may change at will + */ + // CHECKSTYLE:OFF + private static final int NORMALS = 0; + private static final int TANGENTS = 1; + private static final int BITANGENTS = 2; + private static final int COLORSET = 3; + private static final int TEXCOORDS_1D = 4; + private static final int TEXCOORDS_2D = 5; + private static final int TEXCOORDS_3D = 6; + // CHECKSTYLE:ON + + + /** + * This method is used by JNI. Do not call or modify.<p> + * + * Sets the primitive types enum set + * + * @param types the bitwise or'ed c/c++ aiPrimitiveType enum values + */ + @SuppressWarnings("unused") + private void setPrimitiveTypes(int types) { + AiPrimitiveType.fromRawValue(m_primitiveTypes, types); + } + + + /** + * This method is used by JNI. Do not call or modify.<p> + * + * Allocates byte buffers + * + * @param numVertices the number of vertices in the mesh + * @param numFaces the number of faces in the mesh + * @param optimizedFaces set true for optimized face representation + * @param faceBufferSize size of face buffer for non-optimized face + * representation + */ + @SuppressWarnings("unused") + private void allocateBuffers(int numVertices, int numFaces, + boolean optimizedFaces, int faceBufferSize) { + /* + * the allocated buffers are native order direct byte buffers, so they + * can be passed directly to LWJGL or similar graphics APIs + */ + + /* ensure face optimization is possible */ + if (optimizedFaces && !isPureTriangle()) { + throw new IllegalArgumentException("mesh is not purely triangular"); + } + + + m_numVertices = numVertices; + m_numFaces = numFaces; + + + /* allocate for each vertex 3 floats */ + if (m_numVertices > 0) { + m_vertices = ByteBuffer.allocateDirect(numVertices * 3 * + SIZEOF_FLOAT); + m_vertices.order(ByteOrder.nativeOrder()); + } + + + if (m_numFaces > 0) { + /* for optimized faces allocate 3 integers per face */ + if (optimizedFaces) { + m_faces = ByteBuffer.allocateDirect(numFaces * 3 * SIZEOF_INT); + m_faces.order(ByteOrder.nativeOrder()); + } + /* + * for non-optimized faces allocate the passed in buffer size + * and allocate the face index structure + */ + else { + m_faces = ByteBuffer.allocateDirect(faceBufferSize); + m_faces.order(ByteOrder.nativeOrder()); + + m_faceOffsets = ByteBuffer.allocateDirect(numFaces * + SIZEOF_INT); + m_faceOffsets.order(ByteOrder.nativeOrder()); + } + } + } + + + /** + * This method is used by JNI. Do not call or modify.<p> + * + * Allocates a byte buffer for a vertex data channel + * + * @param channelType the channel type + * @param channelIndex sub-index, used for types that can have multiple + * channels, such as texture coordinates + */ + @SuppressWarnings("unused") + private void allocateDataChannel(int channelType, int channelIndex) { + switch (channelType) { + case NORMALS: + m_normals = ByteBuffer.allocateDirect( + m_numVertices * 3 * SIZEOF_FLOAT); + m_normals.order(ByteOrder.nativeOrder()); + break; + case TANGENTS: + m_tangents = ByteBuffer.allocateDirect( + m_numVertices * 3 * SIZEOF_FLOAT); + m_tangents.order(ByteOrder.nativeOrder()); + break; + case BITANGENTS: + m_bitangents = ByteBuffer.allocateDirect( + m_numVertices * 3 * SIZEOF_FLOAT); + m_bitangents.order(ByteOrder.nativeOrder()); + break; + case COLORSET: + m_colorsets[channelIndex] = ByteBuffer.allocateDirect( + m_numVertices * 4 * SIZEOF_FLOAT); + m_colorsets[channelIndex].order(ByteOrder.nativeOrder()); + break; + case TEXCOORDS_1D: + m_numUVComponents[channelIndex] = 1; + m_texcoords[channelIndex] = ByteBuffer.allocateDirect( + m_numVertices * 1 * SIZEOF_FLOAT); + m_texcoords[channelIndex].order(ByteOrder.nativeOrder()); + break; + case TEXCOORDS_2D: + m_numUVComponents[channelIndex] = 2; + m_texcoords[channelIndex] = ByteBuffer.allocateDirect( + m_numVertices * 2 * SIZEOF_FLOAT); + m_texcoords[channelIndex].order(ByteOrder.nativeOrder()); + break; + case TEXCOORDS_3D: + m_numUVComponents[channelIndex] = 3; + m_texcoords[channelIndex] = ByteBuffer.allocateDirect( + m_numVertices * 3 * SIZEOF_FLOAT); + m_texcoords[channelIndex].order(ByteOrder.nativeOrder()); + break; + default: + throw new IllegalArgumentException("unsupported channel type"); + } + } + // }} +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMeshAnim.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMeshAnim.java new file mode 100644 index 0000000..7c893e0 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMeshAnim.java @@ -0,0 +1,49 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * This class is a stub - mesh animations are currently not supported. + */ +public class AiMeshAnim { + +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMetadataEntry.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMetadataEntry.java new file mode 100644 index 0000000..76e6664 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiMetadataEntry.java @@ -0,0 +1,118 @@ +package jassimp; +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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()); + } + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiNode.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiNode.java new file mode 100644 index 0000000..54baf9c --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiNode.java @@ -0,0 +1,246 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * A node in the imported hierarchy.<p> + * + * Each node has name, a parent node (except for the root node), + * a transformation relative to its parent and possibly several child nodes. + * Simple file formats don't support hierarchical structures - for these formats + * the imported scene consists of only a single root node without children. + */ +public final class AiNode { + /** + * Parent node. + */ + private final AiNode m_parent; + + + /** + * Mesh references. + */ + private final int[] m_meshReferences; + + + /** + * 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>(); + + + /** + * Buffer for transformation matrix. + */ + private final Object m_transformationMatrix; + + /** + * Constructor. + * + * @param parent the parent node, may be null + * @param transform the transform matrix + * @param meshReferences array of mesh references + * @param name the name of the node + */ + AiNode(AiNode parent, Object transform, int[] meshReferences, String name) { + m_parent = parent; + m_transformationMatrix = transform; + m_meshReferences = meshReferences; + m_name = name; + + if (null != m_parent) { + m_parent.addChild(this); + } + } + + + /** + * Returns the name of this node. + * + * @return the name + */ + public String getName() { + return m_name; + } + + + /** + * Returns the number of child nodes.<p> + * + * This method exists for compatibility reasons with the native assimp API. + * The returned value is identical to <code>getChildren().size()</code> + * + * @return the number of child nodes + */ + public int getNumChildren() { + return getChildren().size(); + } + + + /** + * Returns a 4x4 matrix that specifies the transformation relative to + * the parent node.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiMatrix4f}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * + * @return a matrix + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> M4 getTransform(AiWrapperProvider<V3, M4, C, N, Q> + wrapperProvider) { + + return (M4) m_transformationMatrix; + } + + + /** + * Returns the children of this node. + * + * @return the children, or an empty list if the node has no children + */ + public List<AiNode> getChildren() { + return m_children; + } + + + /** + * Returns the parent node. + * + * @return the parent, or null of the node has no parent + */ + public AiNode getParent() { + return m_parent; + } + + + /** + * Searches the node hierarchy below (and including) this node for a node + * with the specified name. + * + * @param name the name to look for + * @return the first node with the given name, or null if no such node + * exists + */ + public AiNode findNode(String name) { + /* classic recursive depth first search */ + + if (m_name.equals(name)) { + return this; + } + + for (AiNode child : m_children) { + if (null != child.findNode(name)) { + return child; + } + } + + return null; + } + + + /** + * Returns the number of meshes references by this node.<p> + * + * This method exists for compatibility with the native assimp API. + * The returned value is identical to <code>getMeshes().length</code> + * + * @return the number of references + */ + public int getNumMeshes() { + return m_meshReferences.length; + } + + + /** + * Returns the meshes referenced by this node.<p> + * + * Each entry is an index into the mesh list stored in {@link AiScene}. + * + * @return an array of indices + */ + 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; + } + + + /** + * Adds a child node. + * + * @param child the child to add + */ + void addChild(AiNode child) { + m_children.add(child); + } + + + /** + * Name. + */ + private final String m_name; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiNodeAnim.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiNodeAnim.java new file mode 100644 index 0000000..b07c7ce --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiNodeAnim.java @@ -0,0 +1,501 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + + +/** + * Describes the animation of a single node.<p> + * + * The node name ({@link #getNodeName()} specifies the bone/node which is + * affected by this animation channel. The keyframes are given in three + * separate series of values, one each for position, rotation and scaling. + * The transformation matrix computed from these values replaces the node's + * original transformation matrix at a specific time.<p> + * + * This means all keys are absolute and not relative to the bone default pose. + * The order in which the transformations are applied is - as usual - + * scaling, rotation, translation.<p> + * + * <b>Note:</b> All keys are returned in their correct, chronological order. + * Duplicate keys don't pass the validation step. Most likely there + * will be no negative time values, but they are not forbidden also (so + * implementations need to cope with them!)<p> + * + * Like {@link AiMesh}, the animation related classes offer a Buffer API, a + * Direct API and a wrapped API. Please consult the documentation of + * {@link AiMesh} for a description and comparison of these APIs. + */ +public final class AiNodeAnim { + /** + * Size of one position key entry. + */ + private final int POS_KEY_SIZE = Jassimp.NATIVE_AIVEKTORKEY_SIZE; + + /** + * Size of one rotation key entry. + */ + private final int ROT_KEY_SIZE = Jassimp.NATIVE_AIQUATKEY_SIZE; + + /** + * Size of one scaling key entry. + */ + private final int SCALE_KEY_SIZE = Jassimp.NATIVE_AIVEKTORKEY_SIZE; + + + /** + * Constructor. + * + * @param nodeName name of corresponding scene graph node + * @param numPosKeys number of position keys + * @param numRotKeys number of rotation keys + * @param numScaleKeys number of scaling keys + * @param preBehavior behavior before animation start + * @param postBehavior behavior after animation end + */ + AiNodeAnim(String nodeName, int numPosKeys, int numRotKeys, + int numScaleKeys, int preBehavior, int postBehavior) { + + m_nodeName = nodeName; + m_numPosKeys = numPosKeys; + m_numRotKeys = numRotKeys; + m_numScaleKeys = numScaleKeys; + m_preState = AiAnimBehavior.fromRawValue(preBehavior); + m_postState = AiAnimBehavior.fromRawValue(postBehavior); + + m_posKeys = ByteBuffer.allocateDirect(numPosKeys * POS_KEY_SIZE); + m_posKeys.order(ByteOrder.nativeOrder()); + + m_rotKeys = ByteBuffer.allocateDirect(numRotKeys * ROT_KEY_SIZE); + m_rotKeys.order(ByteOrder.nativeOrder()); + + m_scaleKeys = ByteBuffer.allocateDirect(numScaleKeys * SCALE_KEY_SIZE); + m_scaleKeys.order(ByteOrder.nativeOrder()); + } + + + /** + * Returns the name of the scene graph node affected by this animation.<p> + * + * The node must exist and it must be unique. + * + * @return the name of the affected node + */ + public String getNodeName() { + return m_nodeName; + } + + + /** + * Returns the number of position keys. + * + * @return the number of position keys + */ + public int getNumPosKeys() { + return m_numPosKeys; + } + + + /** + * Returns the buffer with position keys of this animation channel.<p> + * + * Position keys consist of a time value (double) and a position (3D vector + * of floats), resulting in a total of 20 bytes per entry. + * The buffer contains {@link #getNumPosKeys()} of these entries.<p> + * + * If there are position keys, there will also be at least one + * scaling and one rotation key.<p> + * + * @return a native order, direct ByteBuffer + */ + public ByteBuffer getPosKeyBuffer() { + ByteBuffer buf = m_posKeys.duplicate(); + buf.order(ByteOrder.nativeOrder()); + + return buf; + } + + + /** + * Returns the time component of the specified position key. + * + * @param keyIndex the index of the position key + * @return the time component + */ + public double getPosKeyTime(int keyIndex) { + return m_posKeys.getDouble(POS_KEY_SIZE * keyIndex); + } + + + /** + * Returns the position x component of the specified position key. + * + * @param keyIndex the index of the position key + * @return the x component + */ + public float getPosKeyX(int keyIndex) { + return m_posKeys.getFloat(POS_KEY_SIZE * keyIndex + 8); + } + + + /** + * Returns the position y component of the specified position key. + * + * @param keyIndex the index of the position key + * @return the y component + */ + public float getPosKeyY(int keyIndex) { + return m_posKeys.getFloat(POS_KEY_SIZE * keyIndex + 12); + } + + + /** + * Returns the position z component of the specified position key. + * + * @param keyIndex the index of the position key + * @return the z component + */ + public float getPosKeyZ(int keyIndex) { + return m_posKeys.getFloat(POS_KEY_SIZE * keyIndex + 16); + } + + + /** + * Returns the position as vector.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * + * @return the position as vector + */ + public <V3, M4, C, N, Q> V3 getPosKeyVector(int keyIndex, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + return wrapperProvider.wrapVector3f(m_posKeys, + POS_KEY_SIZE * keyIndex + 8, 3); + } + + + /** + * Returns the number of rotation keys. + * + * @return the number of rotation keys + */ + public int getNumRotKeys() { + return m_numRotKeys; + } + + + /** + * Returns the buffer with rotation keys of this animation channel.<p> + * + * Rotation keys consist of a time value (double) and a quaternion (4D + * vector of floats), resulting in a total of 24 bytes per entry. The + * buffer contains {@link #getNumRotKeys()} of these entries.<p> + * + * If there are rotation keys, there will also be at least one + * scaling and one position key. + * + * @return a native order, direct ByteBuffer + */ + public ByteBuffer getRotKeyBuffer() { + ByteBuffer buf = m_rotKeys.duplicate(); + buf.order(ByteOrder.nativeOrder()); + + return buf; + } + + + /** + * Returns the time component of the specified rotation key. + * + * @param keyIndex the index of the position key + * @return the time component + */ + public double getRotKeyTime(int keyIndex) { + return m_rotKeys.getDouble(ROT_KEY_SIZE * keyIndex); + } + + + /** + * Returns the rotation w component of the specified rotation key. + * + * @param keyIndex the index of the position key + * @return the w component + */ + public float getRotKeyW(int keyIndex) { + return m_rotKeys.getFloat(ROT_KEY_SIZE * keyIndex + 8); + } + + + /** + * Returns the rotation x component of the specified rotation key. + * + * @param keyIndex the index of the position key + * @return the x component + */ + public float getRotKeyX(int keyIndex) { + return m_rotKeys.getFloat(ROT_KEY_SIZE * keyIndex + 12); + } + + + /** + * Returns the rotation y component of the specified rotation key. + * + * @param keyIndex the index of the position key + * @return the y component + */ + public float getRotKeyY(int keyIndex) { + return m_rotKeys.getFloat(ROT_KEY_SIZE * keyIndex + 16); + } + + + /** + * Returns the rotation z component of the specified rotation key. + * + * @param keyIndex the index of the position key + * @return the z component + */ + public float getRotKeyZ(int keyIndex) { + return m_rotKeys.getFloat(ROT_KEY_SIZE * keyIndex + 20); + } + + + /** + * Returns the rotation as quaternion.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiQuaternion}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * + * @return the rotation as quaternion + */ + public <V3, M4, C, N, Q> Q getRotKeyQuaternion(int keyIndex, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + return wrapperProvider.wrapQuaternion(m_rotKeys, + ROT_KEY_SIZE * keyIndex + 8); + } + + + /** + * Returns the number of scaling keys. + * + * @return the number of scaling keys + */ + public int getNumScaleKeys() { + return m_numScaleKeys; + } + + + /** + * Returns the buffer with scaling keys of this animation channel.<p> + * + * Scaling keys consist of a time value (double) and a 3D vector of floats, + * resulting in a total of 20 bytes per entry. The buffer + * contains {@link #getNumScaleKeys()} of these entries.<p> + * + * If there are scaling keys, there will also be at least one + * position and one rotation key. + * + * @return a native order, direct ByteBuffer + */ + public ByteBuffer getScaleKeyBuffer() { + ByteBuffer buf = m_scaleKeys.duplicate(); + buf.order(ByteOrder.nativeOrder()); + + return buf; + } + + + /** + * Returns the time component of the specified scaling key. + * + * @param keyIndex the index of the position key + * @return the time component + */ + public double getScaleKeyTime(int keyIndex) { + return m_scaleKeys.getDouble(SCALE_KEY_SIZE * keyIndex); + } + + + /** + * Returns the scaling x component of the specified scaling key. + * + * @param keyIndex the index of the position key + * @return the x component + */ + public float getScaleKeyX(int keyIndex) { + return m_scaleKeys.getFloat(SCALE_KEY_SIZE * keyIndex + 8); + } + + + /** + * Returns the scaling y component of the specified scaling key. + * + * @param keyIndex the index of the position key + * @return the y component + */ + public float getScaleKeyY(int keyIndex) { + return m_scaleKeys.getFloat(SCALE_KEY_SIZE * keyIndex + 12); + } + + + /** + * Returns the scaling z component of the specified scaling key. + * + * @param keyIndex the index of the position key + * @return the z component + */ + public float getScaleKeyZ(int keyIndex) { + return m_scaleKeys.getFloat(SCALE_KEY_SIZE * keyIndex + 16); + } + + + /** + * Returns the scaling factor as vector.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built in behavior is to return an {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * + * @return the scaling factor as vector + */ + public <V3, M4, C, N, Q> V3 getScaleKeyVector(int keyIndex, + AiWrapperProvider<V3, M4, C, N, Q> wrapperProvider) { + + return wrapperProvider.wrapVector3f(m_scaleKeys, + SCALE_KEY_SIZE * keyIndex + 8, 3); + } + + + /** + * Defines how the animation behaves before the first key is encountered. + * <p> + * + * The default value is {@link AiAnimBehavior#DEFAULT} (the original + * transformation matrix of the affected node is used). + * + * @return the animation behavior before the first key + */ + public AiAnimBehavior getPreState() { + return m_preState; + } + + + /** + * Defines how the animation behaves after the last key was processed.<p> + * + * The default value is {@link AiAnimBehavior#DEFAULT} (the original + * transformation matrix of the affected node is taken). + * + * @return the animation behavior before after the last key + */ + public AiAnimBehavior getPostState() { + return m_postState; + } + + + /** + * Node name. + */ + private final String m_nodeName; + + + /** + * Number of position keys. + */ + private final int m_numPosKeys; + + + /** + * Buffer with position keys. + */ + private ByteBuffer m_posKeys; + + + /** + * Number of rotation keys. + */ + private final int m_numRotKeys; + + + /** + * Buffer for rotation keys. + */ + private ByteBuffer m_rotKeys; + + + /** + * Number of scaling keys. + */ + private final int m_numScaleKeys; + + + /** + * Buffer for scaling keys. + */ + private ByteBuffer m_scaleKeys; + + + /** + * Pre animation behavior. + */ + private final AiAnimBehavior m_preState; + + + /** + * Post animation behavior. + */ + private final AiAnimBehavior m_postState; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java new file mode 100644 index 0000000..7bb617b --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiPostProcessSteps.java @@ -0,0 +1,571 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.util.Set; + +/** + * Enumerates the post processing steps supported by assimp. + */ +public enum AiPostProcessSteps { + + /** + * Calculates the tangents and bitangents for the imported meshes. + * <p> + * + * Does nothing if a mesh does not have normals. You might want this post + * processing step to be executed if you plan to use tangent space + * calculations such as normal mapping applied to the meshes. There's a + * config setting, <tt>#AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE</tt>, which + * allows you to specify a maximum smoothing angle for the algorithm. + * However, usually you'll want to leave it at the default value. + */ + CALC_TANGENT_SPACE(0x1), + + + /** + * Identifies and joins identical vertex data sets within all imported + * meshes.<p> + * + * After this step is run, each mesh contains unique vertices, so a vertex + * may be used by multiple faces. You usually want to use this post + * processing step. If your application deals with indexed geometry, this + * step is compulsory or you'll just waste rendering time. <b>If this flag + * is not specified</b>, no vertices are referenced by more than one face + * and <b>no index buffer is required</b> for rendering. + */ + JOIN_IDENTICAL_VERTICES(0x2), + + + /** + * Converts all the imported data to a left-handed coordinate space.<p> + * + * By default the data is returned in a right-handed coordinate space (which + * OpenGL prefers). In this space, +X points to the right, +Z points towards + * the viewer, and +Y points upwards. In the DirectX coordinate space +X + * points to the right, +Y points upwards, and +Z points away from the + * viewer.<p> + * + * You'll probably want to consider this flag if you use Direct3D for + * rendering. The #ConvertToLeftHanded flag supersedes this + * setting and bundles all conversions typically required for D3D-based + * applications. + */ + MAKE_LEFT_HANDED(0x4), + + + /** + * Triangulates all faces of all meshes.<p> + * + * By default the imported mesh data might contain faces with more than 3 + * indices. For rendering you'll usually want all faces to be triangles. + * This post processing step splits up faces with more than 3 indices into + * triangles. Line and point primitives are *not* modified! If you want + * 'triangles only' with no other kinds of primitives, try the following + * solution: + * <ul> + * <li>Specify both #Triangulate and #SortByPType + * <li>Ignore all point and line meshes when you process assimp's output + * </ul> + */ + TRIANGULATE(0x8), + + + /** + * Removes some parts of the data structure (animations, materials, light + * sources, cameras, textures, vertex components).<p> + * + * The components to be removed are specified in a separate configuration + * option, <tt>#AI_CONFIG_PP_RVC_FLAGS</tt>. This is quite useful if you + * don't need all parts of the output structure. Vertex colors are rarely + * used today for example... Calling this step to remove unneeded data from + * the pipeline as early as possible results in increased performance and a + * more optimized output data structure. This step is also useful if you + * want to force Assimp to recompute normals or tangents. The corresponding + * steps don't recompute them if they're already there (loaded from the + * source asset). By using this step you can make sure they are NOT there. + * <p> + * + * This flag is a poor one, mainly because its purpose is usually + * misunderstood. Consider the following case: a 3D model has been exported + * from a CAD app, and it has per-face vertex colors. Vertex positions can't + * be shared, thus the #JoinIdenticalVertices step fails to + * optimize the data because of these nasty little vertex colors. Most apps + * don't even process them, so it's all for nothing. By using this step, + * unneeded components are excluded as early as possible thus opening more + * room for internal optimizations. + */ + REMOVE_COMPONENT(0x10), + + + /** + * Generates normals for all faces of all meshes.<p> + * + * This is ignored if normals are already there at the time this flag is + * evaluated. Model importers try to load them from the source file, so + * they're usually already there. Face normals are shared between all points + * of a single face, so a single point can have multiple normals, which + * forces the library to duplicate vertices in some cases. + * #JoinIdenticalVertices is *senseless* then.<p> + * + * This flag may not be specified together with {@link #GEN_SMOOTH_NORMALS}. + */ + GEN_NORMALS(0x20), + + + /** + * Generates smooth normals for all vertices in the mesh.<p> + * + * This is ignored if normals are already there at the time this flag is + * evaluated. Model importers try to load them from the source file, so + * they're usually already there.<p> + * + * This flag may not be specified together with {@link #GEN_NORMALS} + * There's a configuration option, + * <tt>#AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE</tt> which allows you to + * specify an angle maximum for the normal smoothing algorithm. Normals + * exceeding this limit are not smoothed, resulting in a 'hard' seam between + * two faces. Using a decent angle here (e.g. 80 degrees) results in very + * good visual appearance. + */ + GEN_SMOOTH_NORMALS(0x40), + + + /** + * Splits large meshes into smaller sub-meshes.<p> + * + * This is quite useful for real-time rendering, where the number of + * triangles which can be maximally processed in a single draw-call is + * limited by the video driver/hardware. The maximum vertex buffer is + * usually limited too. Both requirements can be met with this step: you may + * specify both a triangle and vertex limit for a single mesh.<p> + * + * The split limits can (and should!) be set through the + * <tt>#AI_CONFIG_PP_SLM_VERTEX_LIMIT</tt> and + * <tt>#AI_CONFIG_PP_SLM_TRIANGLE_LIMIT</tt> settings. The default values + * are <tt>#AI_SLM_DEFAULT_MAX_VERTICES</tt> and + * <tt>#AI_SLM_DEFAULT_MAX_TRIANGLES</tt>.<p> + * + * Note that splitting is generally a time-consuming task, but only if + * there's something to split. The use of this step is recommended for most + * users. + */ + SPLIT_LARGE_MESHES(0x80), + + + /** + * Removes the node graph and pre-transforms all vertices with the local + * transformation matrices of their nodes.<p> + * + * The output scene still contains nodes, however there is only a root node + * with children, each one referencing only one mesh, and each mesh + * referencing one material. For rendering, you can simply render all meshes + * in order - you don't need to pay attention to local transformations and + * the node hierarchy. Animations are removed during this step. This step is + * intended for applications without a scenegraph. The step CAN cause some + * problems: if e.g. a mesh of the asset contains normals and another, using + * the same material index, does not, they will be brought together, but the + * first meshes's part of the normal list is zeroed. However, these + * artifacts are rare.<p> + * + * <b>Note:</b> The <tt>#AI_CONFIG_PP_PTV_NORMALIZE</tt> configuration + * property can be set to normalize the scene's spatial dimension to the + * -1...1 range. + */ + PRE_TRANSFORM_VERTICES(0x100), + + + /** + * Limits the number of bones simultaneously affecting a single vertex to a + * maximum value.<p> + * + * If any vertex is affected by more than the maximum number of bones, the + * least important vertex weights are removed and the remaining vertex + * weights are renormalized so that the weights still sum up to 1. The + * default bone weight limit is 4 (defined as <tt>#AI_LMW_MAX_WEIGHTS</tt> + * in config.h), but you can use the <tt>#AI_CONFIG_PP_LBW_MAX_WEIGHTS</tt> + * setting to supply your own limit to the post processing step.<p> + * + * If you intend to perform the skinning in hardware, this post processing + * step might be of interest to you. + */ + LIMIT_BONE_WEIGHTS(0x200), + + + /** + * Validates the imported scene data structure. This makes sure that all + * indices are valid, all animations and bones are linked correctly, all + * material references are correct .. etc.<p> + * + * It is recommended that you capture Assimp's log output if you use this + * flag, so you can easily find out what's wrong if a file fails the + * validation. The validator is quite strict and will find *all* + * inconsistencies in the data structure... It is recommended that plugin + * developers use it to debug their loaders. There are two types of + * validation failures: + * <ul> + * <li>Error: There's something wrong with the imported data. Further + * postprocessing is not possible and the data is not usable at all. The + * import fails. #Importer::GetErrorString() or #aiGetErrorString() carry + * the error message around.</li> + * <li>Warning: There are some minor issues (e.g. 1000000 animation + * keyframes with the same time), but further postprocessing and use of the + * data structure is still safe. Warning details are written to the log + * file, <tt>#AI_SCENE_FLAGS_VALIDATION_WARNING</tt> is set in + * #aiScene::mFlags</li> + * </ul> + * + * This post-processing step is not time-consuming. Its use is not + * compulsory, but recommended. + */ + VALIDATE_DATA_STRUCTURE(0x400), + + + /** + * Reorders triangles for better vertex cache locality.<p> + * + * The step tries to improve the ACMR (average post-transform vertex cache + * miss ratio) for all meshes. The implementation runs in O(n) and is + * roughly based on the 'tipsify' algorithm (see <a href=" + * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf">this + * paper</a>).<p> + * + * If you intend to render huge models in hardware, this step might be of + * interest to you. The <tt>#AI_CONFIG_PP_ICL_PTCACHE_SIZE</tt>config + * setting can be used to fine-tune the cache optimization. + */ + IMPROVE_CACHE_LOCALITY(0x800), + + + /** + * Searches for redundant/unreferenced materials and removes them.<p> + * + * This is especially useful in combination with the + * #PretransformVertices and #OptimizeMeshes flags. Both + * join small meshes with equal characteristics, but they can't do their + * work if two meshes have different materials. Because several material + * settings are lost during Assimp's import filters, (and because many + * exporters don't check for redundant materials), huge models often have + * materials which are are defined several times with exactly the same + * settings.<p> + * + * Several material settings not contributing to the final appearance of a + * surface are ignored in all comparisons (e.g. the material name). So, if + * you're passing additional information through the content pipeline + * (probably using *magic* material names), don't specify this flag. + * Alternatively take a look at the <tt>#AI_CONFIG_PP_RRM_EXCLUDE_LIST</tt> + * setting. + */ + REMOVE_REDUNDANT_MATERIALS(0x1000), + + + /** + * This step tries to determine which meshes have normal vectors that are + * facing inwards and inverts them.<p> + * + * The algorithm is simple but effective: the bounding box of all vertices + + * their normals is compared against the volume of the bounding box of all + * vertices without their normals. This works well for most objects, + * problems might occur with planar surfaces. However, the step tries to + * filter such cases. The step inverts all in-facing normals. Generally it + * is recommended to enable this step, although the result is not always + * correct. + */ + FIX_INFACING_NORMALS(0x2000), + + + /** + * This step splits meshes with more than one primitive type in homogeneous + * sub-meshes.<p> + * + * The step is executed after the triangulation step. After the step + * returns, just one bit is set in aiMesh::mPrimitiveTypes. This is + * especially useful for real-time rendering where point and line primitives + * are often ignored or rendered separately. You can use the + * <tt>#AI_CONFIG_PP_SBP_REMOVE</tt> option to specify which primitive types + * you need. This can be used to easily exclude lines and points, which are + * rarely used, from the import. + */ + SORT_BY_PTYPE(0x8000), + + + /** + * This step searches all meshes for degenerate primitives and converts them + * to proper lines or points.<p> + * + * A face is 'degenerate' if one or more of its points are identical. To + * have the degenerate stuff not only detected and collapsed but removed, + * try one of the following procedures: <br> + * <b>1.</b> (if you support lines and points for rendering but don't want + * the degenerates)</br> + * <ul> + * <li>Specify the #FindDegenerates flag.</li> + * <li>Set the <tt>AI_CONFIG_PP_FD_REMOVE</tt> option to 1. This will cause + * the step to remove degenerate triangles from the import as soon as + * they're detected. They won't pass any further pipeline steps.</li> + * </ul> + * <br> + * <b>2.</b>(if you don't support lines and points at all)</br> + * <ul> + * <li>Specify the #FindDegenerates flag. + * <li>Specify the #SortByPType flag. This moves line and point + * primitives to separate meshes. + * <li>Set the <tt>AI_CONFIG_PP_SBP_REMOVE</tt> option to + * <code>aiPrimitiveType_POINTS | aiPrimitiveType_LINES</code> + * to cause SortByPType to reject point and line meshes from the + * scene. + * </ul> + * <b>Note:</b> Degenerated polygons are not necessarily evil and that's + * why they're not removed by default. There are several file formats + * which don't support lines or points, and some exporters bypass the + * format specification and write them as degenerate triangles instead. + */ + FIND_DEGENERATES(0x10000), + + + /** + * This step searches all meshes for invalid data, such as zeroed normal + * vectors or invalid UV coords and removes/fixes them. This is intended to + * get rid of some common exporter errors.<p> + * + * This is especially useful for normals. If they are invalid, and the step + * recognizes this, they will be removed and can later be recomputed, i.e. + * by the {@link #GEN_SMOOTH_NORMALS} flag.<p> + * + * The step will also remove meshes that are infinitely small and reduce + * animation tracks consisting of hundreds if redundant keys to a single + * key. The <tt>AI_CONFIG_PP_FID_ANIM_ACCURACY</tt> config property decides + * the accuracy of the check for duplicate animation tracks. + */ + FIND_INVALID_DATA(0x20000), + + + /** + * This step converts non-UV mappings (such as spherical or cylindrical + * mapping) to proper texture coordinate channels.<p> + * + * Most applications will support UV mapping only, so you will probably want + * to specify this step in every case. Note that Assimp is not always able + * to match the original mapping implementation of the 3D app which produced + * a model perfectly. It's always better to let the modelling app compute + * the UV channels - 3ds max, Maya, Blender, LightWave, and Modo do this for + * example.<p> + * + * <b>Note:</b> If this step is not requested, you'll need to process the + * <tt>MATKEY_MAPPING</tt> material property in order to display all + * assets properly. + */ + GEN_UV_COORDS(0x40000), + + + /** + * This step applies per-texture UV transformations and bakes them into + * stand-alone vtexture coordinate channels.<p> + * + * UV transformations are specified per-texture - see the + * <tt>MATKEY_UVTRANSFORM</tt> material key for more information. This + * step processes all textures with transformed input UV coordinates and + * generates a new (pre-transformed) UV channel which replaces the old + * channel. Most applications won't support UV transformations, so you will + * probably want to specify this step.<p> + * + * <b>Note:</b> UV transformations are usually implemented in real-time + * apps by transforming texture coordinates at vertex shader stage with a + * 3x3 (homogenous) transformation matrix. + */ + TRANSFORM_UV_COORDS(0x80000), + + + /** + * This step searches for duplicate meshes and replaces them with references + * to the first mesh.<p> + * + * This step takes a while, so don't use it if speed is a concern. Its main + * purpose is to workaround the fact that many export file formats don't + * support instanced meshes, so exporters need to duplicate meshes. This + * step removes the duplicates again. Please note that Assimp does not + * currently support per-node material assignment to meshes, which means + * that identical meshes with different materials are currently *not* + * joined, although this is planned for future versions. + */ + FIND_INSTANCES(0x100000), + + + /** + * A postprocessing step to reduce the number of meshes.<p> + * + * This will, in fact, reduce the number of draw calls.<p> + * + * This is a very effective optimization and is recommended to be used + * together with #OptimizeGraph, if possible. The flag is fully + * compatible with both {@link #SPLIT_LARGE_MESHES} and + * {@link #SORT_BY_PTYPE}. + */ + OPTIMIZE_MESHES(0x200000), + + + /** + * A postprocessing step to optimize the scene hierarchy.<p> + * + * Nodes without animations, bones, lights or cameras assigned are collapsed + * and joined.<p> + * + * Node names can be lost during this step. If you use special 'tag nodes' + * to pass additional information through your content pipeline, use the + * <tt>#AI_CONFIG_PP_OG_EXCLUDE_LIST</tt> setting to specify a list of node + * names you want to be kept. Nodes matching one of the names in this list + * won't be touched or modified.<p> + * + * Use this flag with caution. Most simple files will be collapsed to a + * single node, so complex hierarchies are usually completely lost. This is + * not useful for editor environments, but probably a very effective + * optimization if you just want to get the model data, convert it to your + * own format, and render it as fast as possible.<p> + * + * This flag is designed to be used with #OptimizeMeshes for best + * results.<p> + * + * <b>Note:</b> 'Crappy' scenes with thousands of extremely small meshes + * packed in deeply nested nodes exist for almost all file formats. + * {@link #OPTIMIZE_MESHES} in combination with {@link #OPTIMIZE_GRAPH} + * usually fixes them all and makes them renderable. + */ + OPTIMIZE_GRAPH(0x400000), + + + /** + * This step flips all UV coordinates along the y-axis and adjusts material + * settings and bitangents accordingly.<p> + * + * <b>Output UV coordinate system:</b><br> + * <code><pre> + * 0y|0y ---------- 1x|0y + * | | + * | | + * | | + * 0x|1y ---------- 1x|1y + * </pre></code> + * <p> + * + * You'll probably want to consider this flag if you use Direct3D for + * rendering. The {@link #MAKE_LEFT_HANDED} flag supersedes this setting + * and bundles all conversions typically required for D3D-based + * applications. + */ + FLIP_UVS(0x800000), + + + /** + * This step adjusts the output face winding order to be CW.<p> + * + * The default face winding order is counter clockwise (CCW). + * + * <b>Output face order:</b> + * + * <code><pre> + * x2 + * + * x0 + * x1 + * </pre></code> + */ + FLIP_WINDING_ORDER(0x1000000), + + + /** + * This step splits meshes with many bones into sub-meshes so that each + * sub-mesh has fewer or as many bones as a given limit.<p> + */ + SPLIT_BY_BONE_COUNT(0x2000000), + + + /** + * This step removes bones losslessly or according to some threshold.<p> + * + * In some cases (i.e. formats that require it) exporters are forced to + * assign dummy bone weights to otherwise static meshes assigned to animated + * meshes. Full, weight-based skinning is expensive while animating nodes is + * extremely cheap, so this step is offered to clean up the data in that + * regard.<p> + * + * Use <tt>#AI_CONFIG_PP_DB_THRESHOLD</tt> to control this. Use + * <tt>#AI_CONFIG_PP_DB_ALL_OR_NONE</tt> if you want bones removed if and + * only if all bones within the scene qualify for removal. + */ + DEBONE(0x4000000); + + + /** + * Utility method for converting to c/c++ based integer enums from java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param set the set to convert + * @return an integer based enum value (as defined by assimp) + */ + static long toRawValue(Set<AiPostProcessSteps> set) { + long rawValue = 0L; + + for (AiPostProcessSteps step : set) { + rawValue |= step.m_rawValue; + } + + return rawValue; + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiPostProcessSteps(long rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final long m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiPrimitiveType.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiPrimitiveType.java new file mode 100644 index 0000000..af8aa28 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiPrimitiveType.java @@ -0,0 +1,113 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.util.Set; + + +/** + * Enumerates the types of geometric primitives supported by Assimp.<p> + */ +public enum AiPrimitiveType { + /** + * A point primitive. + */ + POINT(0x1), + + + /** + * A line primitive. + */ + LINE(0x2), + + + /** + * A triangular primitive. + */ + TRIANGLE(0x4), + + + /** + * A higher-level polygon with more than 3 edges.<p> + * + * A triangle is a polygon, but polygon in this context means + * "all polygons that are not triangles". The "Triangulate"-Step is provided + * for your convenience, it splits all polygons in triangles (which are much + * easier to handle). + */ + POLYGON(0x8); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param set the target set to fill + * @param rawValue an integer based enum value (as defined by assimp) + */ + static void fromRawValue(Set<AiPrimitiveType> set, int rawValue) { + + for (AiPrimitiveType type : AiPrimitiveType.values()) { + if ((type.m_rawValue & rawValue) != 0) { + set.add(type); + } + } + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiPrimitiveType(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiProgressHandler.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiProgressHandler.java new file mode 100644 index 0000000..2987e59 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiProgressHandler.java @@ -0,0 +1,46 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +public interface AiProgressHandler +{ + boolean update(float percentage); +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiQuaternion.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiQuaternion.java new file mode 100644 index 0000000..a9ca7be --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiQuaternion.java @@ -0,0 +1,165 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; + + +/** + * Wrapper for a quaternion.<p> + * + * The wrapper is writable, i.e., changes performed via the set-methods will + * modify the underlying mesh/animation. + */ +public final class AiQuaternion { + /** + * Wrapped buffer. + */ + private final ByteBuffer m_buffer; + + + /** + * Offset into m_buffer. + */ + private final int m_offset; + + /** + * Constructor. + * + * @param buffer the buffer to wrap + * @param offset offset into buffer + */ + public AiQuaternion(ByteBuffer buffer, int offset) { + if (null == buffer) { + throw new IllegalArgumentException("buffer may not be null"); + } + + m_buffer = buffer; + m_offset = offset; + } + + + /** + * Returns the x value. + * + * @return the x value + */ + public float getX() { + return m_buffer.getFloat(m_offset + 4); + } + + + /** + * Returns the y value. + * + * @return the y value + */ + public float getY() { + return m_buffer.getFloat(m_offset + 8); + } + + + /** + * Returns the z value. + * + * @return the z value + */ + public float getZ() { + return m_buffer.getFloat(m_offset + 12); + } + + + /** + * Returns the w value. + * + * @return the w value + */ + public float getW() { + return m_buffer.getFloat(m_offset); + } + + + /** + * Sets the x component. + * + * @param x the new value + */ + public void setX(float x) { + m_buffer.putFloat(m_offset + 4, x); + } + + + /** + * Sets the y component. + * + * @param y the new value + */ + public void setY(float y) { + m_buffer.putFloat(m_offset + 8, y); + } + + + /** + * Sets the z component. + * + * @param z the new value + */ + public void setZ(float z) { + m_buffer.putFloat(m_offset + 12, z); + } + + + /** + * Sets the z component. + * + * @param w the new value + */ + public void setW(float w) { + m_buffer.putFloat(m_offset, w); + } + + + @Override + public String toString() { + return "[" + getX() + ", " + getY() + ", " + getZ() + ", " + + getW() + "]"; + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiScene.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiScene.java new file mode 100644 index 0000000..b4eed2f --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiScene.java @@ -0,0 +1,251 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.util.ArrayList; +import java.util.List; + + +/** + * The root structure of the imported data.<p> + * + * Everything that was imported from the given file can be accessed from here. + * <p> + * Jassimp copies all data into "java memory" during import and frees + * resources allocated by native code after scene loading is completed. No + * special care has to be taken for freeing resources, unreferenced jassimp + * objects (including the scene itself) are eligible to garbage collection like + * any other java object. + */ +public final class AiScene { + /** + * Constructor. + */ + AiScene() { + /* nothing to do */ + } + + + /** + * Returns the number of meshes contained in the scene.<p> + * + * This method is provided for completeness reasons. It will return the + * same value as <code>getMeshes().size()</code> + * + * @return the number of meshes + */ + public int getNumMeshes() { + return m_meshes.size(); + } + + + /** + * Returns the meshes contained in the scene.<p> + * + * If there are no meshes in the scene, an empty collection is returned + * + * @return the list of meshes + */ + public List<AiMesh> getMeshes() { + return m_meshes; + } + + + /** + * Returns the number of materials in the scene.<p> + * + * This method is provided for completeness reasons. It will return the + * same value as <code>getMaterials().size()</code> + * + * @return the number of materials + */ + public int getNumMaterials() { + return m_materials.size(); + } + + + /** + * Returns the list of materials.<p> + * + * Use the index given in each aiMesh structure to access this + * array. If the {@link AiSceneFlag#INCOMPLETE} flag is not set there will + * always be at least ONE material. + * + * @return the list of materials + */ + public List<AiMaterial> getMaterials() { + return m_materials; + } + + + /** + * Returns the number of animations in the scene.<p> + * + * This method is provided for completeness reasons. It will return the + * same value as <code>getAnimations().size()</code> + * + * @return the number of materials + */ + public int getNumAnimations() { + return m_animations.size(); + } + + + /** + * Returns the list of animations. + * + * @return the list of animations + */ + public List<AiAnimation> getAnimations() { + return m_animations; + } + + + /** + * Returns the number of light sources in the scene.<p> + * + * This method is provided for completeness reasons. It will return the + * same value as <code>getLights().size()</code> + * + * @return the number of lights + */ + public int getNumLights() { + return m_lights.size(); + } + + + /** + * Returns the list of light sources.<p> + * + * Light sources are fully optional, the returned list may be empty + * + * @return a possibly empty list of lights + */ + public List<AiLight> getLights() { + return m_lights; + } + + + /** + * Returns the number of cameras in the scene.<p> + * + * This method is provided for completeness reasons. It will return the + * same value as <code>getCameras().size()</code> + * + * @return the number of cameras + */ + public int getNumCameras() { + return m_cameras.size(); + } + + + /** + * Returns the list of cameras.<p> + * + * Cameras are fully optional, the returned list may be empty + * + * @return a possibly empty list of cameras + */ + public List<AiCamera> getCameras() { + return m_cameras; + } + + + /** + * Returns the scene graph root. + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers).<p> + * + * The built-in behavior is to return a {@link AiVector}. + * + * @param wrapperProvider the wrapper provider (used for type inference) + * @return the scene graph root + */ + @SuppressWarnings("unchecked") + public <V3, M4, C, N, Q> N getSceneRoot(AiWrapperProvider<V3, M4, C, N, Q> + wrapperProvider) { + + return (N) m_sceneRoot; + } + + + @Override + public String toString() { + return "AiScene (" + m_meshes.size() + " mesh/es)"; + } + + + /** + * Meshes. + */ + private final List<AiMesh> m_meshes = new ArrayList<AiMesh>(); + + + /** + * Materials. + */ + private final List<AiMaterial> m_materials = new ArrayList<AiMaterial>(); + + + /** + * Animations. + */ + private final List<AiAnimation> m_animations = new ArrayList<AiAnimation>(); + + + /** + * Lights. + */ + private final List<AiLight> m_lights = new ArrayList<AiLight>(); + + + /** + * Cameras. + */ + private final List<AiCamera> m_cameras = new ArrayList<AiCamera>(); + + + /** + * Scene graph root. + */ + private Object m_sceneRoot; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiSceneFlag.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiSceneFlag.java new file mode 100644 index 0000000..772b495 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiSceneFlag.java @@ -0,0 +1,151 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.util.Set; + + +/** + * Status flags for {@link AiScene}s. + */ +public enum AiSceneFlag { + /** + * Specifies that the scene data structure that was imported is not + * complete.<p> + * + * This flag bypasses some internal validations and allows the import + * of animation skeletons, material libraries or camera animation paths + * using Assimp. Most applications won't support such data. + */ + INCOMPLETE(0x1), + + + /** + * This flag is set by the validation + * ({@link AiPostProcessSteps#VALIDATE_DATA_STRUCTURE + * VALIDATE_DATA_STRUCTURE}) + * postprocess-step if the validation is successful.<p> + * + * In a validated scene you can be sure that any cross references in the + * data structure (e.g. vertex indices) are valid. + */ + VALIDATED(0x2), + + + /** + * * This flag is set by the validation + * ({@link AiPostProcessSteps#VALIDATE_DATA_STRUCTURE + * VALIDATE_DATA_STRUCTURE}) + * postprocess-step if the validation is successful but some issues have + * been found.<p> + * + * This can for example mean that a texture that does not exist is + * referenced by a material or that the bone weights for a vertex don't sum + * to 1.0 ... . In most cases you should still be able to use the import. + * This flag could be useful for applications which don't capture Assimp's + * log output. + */ + VALIDATION_WARNING(0x4), + + + /** + * This flag is currently only set by the + * {@link jassimp.AiPostProcessSteps#JOIN_IDENTICAL_VERTICES + * JOIN_IDENTICAL_VERTICES}.<p> + * + * It indicates that the vertices of the output meshes aren't in the + * internal verbose format anymore. In the verbose format all vertices are + * unique, no vertex is ever referenced by more than one face. + */ + NON_VERBOSE_FORMAT(0x8), + + + /** + * Denotes pure height-map terrain data.<p> + * + * Pure terrains usually consist of quads, sometimes triangles, in a + * regular grid. The x,y coordinates of all vertex positions refer to the + * x,y coordinates on the terrain height map, the z-axis stores the + * elevation at a specific point.<p> + * + * TER (Terragen) and HMP (3D Game Studio) are height map formats. + * <p> + * Assimp is probably not the best choice for loading *huge* terrains - + * fully triangulated data takes extremely much free store and should be + * avoided as long as possible (typically you'll do the triangulation when + * you actually need to render it). + */ + TERRAIN(0x10); + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param set the target set to fill + * @param rawValue an integer based enum value (as defined by assimp) + */ + static void fromRawValue(Set<AiSceneFlag> set, int rawValue) { + + for (AiSceneFlag type : AiSceneFlag.values()) { + if ((type.m_rawValue & rawValue) != 0) { + set.add(type); + } + } + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiSceneFlag(int rawValue) { + m_rawValue = rawValue; + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiShadingMode.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiShadingMode.java new file mode 100644 index 0000000..fbf6573 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiShadingMode.java @@ -0,0 +1,168 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Defines all shading modes supported by the library.<p> + * + * The list of shading modes has been taken from Blender. + * See Blender documentation for more information. The API does + * not distinguish between "specular" and "diffuse" shaders (thus the + * specular term for diffuse shading models like Oren-Nayar remains + * undefined).<p> + * Again, this value is just a hint. Assimp tries to select the shader whose + * most common implementation matches the original rendering results of the + * 3D modeller which wrote a particular model as closely as possible. + */ +public enum AiShadingMode { + /** + * Flat shading.<p> + * + * Shading is done on per-face base, diffuse only. Also known as + * 'faceted shading'. + */ + FLAT(0x1), + + + /** + * Simple Gouraud shading. + */ + GOURAUD(0x2), + + + /** + * Phong-Shading. + */ + PHONG(0x3), + + + /** + * Phong-Blinn-Shading. + */ + BLINN(0x4), + + + /** + * Toon-Shading per pixel.<p> + * + * Also known as 'comic' shader. + */ + TOON(0x5), + + + /** + * OrenNayar-Shading per pixel.<p> + * + * Extension to standard Lambertian shading, taking the roughness of the + * material into account + */ + OREN_NAYAR(0x6), + + + /** + * Minnaert-Shading per pixel.<p> + * + * Extension to standard Lambertian shading, taking the "darkness" of the + * material into account + */ + MINNAERT(0x7), + + + /** + * CookTorrance-Shading per pixel.<p> + * + * Special shader for metallic surfaces. + */ + COOK_TORRANCE(0x8), + + + /** + * No shading at all.<p> + * + * Constant light influence of 1.0. + */ + NO_SHADING(0x9), + + + /** + * Fresnel shading. + */ + FRESNEL(0xa); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static AiShadingMode fromRawValue(int rawValue) { + for (AiShadingMode type : AiShadingMode.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiShadingMode(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureInfo.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureInfo.java new file mode 100644 index 0000000..5092303 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureInfo.java @@ -0,0 +1,224 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Data structure for texture related material properties. + */ +public final class AiTextureInfo { + + /** + * Constructor. + * + * @param type type + * @param index index + * @param file file + * @param uvIndex uv index + * @param blend blend factor + * @param texOp texture operation + * @param mmU map mode for u axis + * @param mmV map mode for v axis + * @param mmW map mode for w axis + */ + AiTextureInfo(AiTextureType type, int index, String file, + int uvIndex, float blend, AiTextureOp texOp, AiTextureMapMode mmU, + AiTextureMapMode mmV, AiTextureMapMode mmW) { + + m_type = type; + m_index = index; + m_file = file; + m_uvIndex = uvIndex; + m_blend = blend; + m_textureOp = texOp; + m_textureMapModeU = mmU; + m_textureMapModeV = mmV; + m_textureMapModeW = mmW; + } + + + /** + * Specifies the type of the texture (e.g. diffuse, specular, ...). + * + * @return the type. + */ + public AiTextureType getType() { + return m_type; + } + + + /** + * Index of the texture in the texture stack.<p> + * + * Each type maintains a stack of textures, i.e., there may be a diffuse.0, + * a diffuse.1, etc + * + * @return the index + */ + public int getIndex() { + return m_index; + } + + + /** + * Returns the path to the texture file. + * + * @return the path + */ + public String getFile() { + return m_file; + } + + + /** + * Returns the index of the UV coordinate set. + * + * @return the uv index + */ + public int getUVIndex() { + return m_uvIndex; + } + + + /** + * Returns the blend factor. + * + * @return the blend factor + */ + public float getBlend() { + return m_blend; + } + + + /** + * Returns the texture operation used to combine this texture and the + * preceding texture in the stack. + * + * @return the texture operation + */ + public AiTextureOp getTextureOp() { + return m_textureOp; + } + + + /** + * Returns the texture map mode for U texture axis. + * + * @return the texture map mode + */ + public AiTextureMapMode getTextureMapModeU() { + return m_textureMapModeU; + } + + + /** + * Returns the texture map mode for V texture axis. + * + * @return the texture map mode + */ + public AiTextureMapMode getTextureMapModeV() { + return m_textureMapModeV; + } + + + /** + * Returns the texture map mode for W texture axis. + * + * @return the texture map mode + */ + public AiTextureMapMode getTextureMapModeW() { + return m_textureMapModeW; + } + + + /** + * Type. + */ + private final AiTextureType m_type; + + + /** + * Index. + */ + private final int m_index; + + + /** + * Path. + */ + private final String m_file; + + + /** + * UV index. + */ + private final int m_uvIndex; + + + /** + * Blend factor. + */ + private final float m_blend; + + + /** + * Texture operation. + */ + private final AiTextureOp m_textureOp; + + + /** + * Map mode U axis. + */ + private final AiTextureMapMode m_textureMapModeU; + + + /** + * Map mode V axis. + */ + private final AiTextureMapMode m_textureMapModeV; + + + /** + * Map mode W axis. + */ + private final AiTextureMapMode m_textureMapModeW; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureMapMode.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureMapMode.java new file mode 100644 index 0000000..c08ca10 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureMapMode.java @@ -0,0 +1,113 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Defines how UV coordinates outside the [0...1] range are handled.<p> + * + * Commonly referred to as 'wrapping mode'. + */ +public enum AiTextureMapMode { + /** + * A texture coordinate u|v is translated to u%1|v%1. + */ + WRAP(0x0), + + + /** + * Texture coordinates outside [0...1] are clamped to the nearest + * valid value. + */ + CLAMP(0x1), + + + /** + * A texture coordinate u|v becomes u%1|v%1 if (u-(u%1))%2 is zero and + * 1-(u%1)|1-(v%1) otherwise. + */ + MIRROR(0x2), + + + /** + * If the texture coordinates for a pixel are outside [0...1] the texture + * is not applied to that pixel. + */ + DECAL(0x3); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static AiTextureMapMode fromRawValue(int rawValue) { + for (AiTextureMapMode type : AiTextureMapMode.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiTextureMapMode(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureMapping.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureMapping.java new file mode 100644 index 0000000..48c219d --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureMapping.java @@ -0,0 +1,78 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Defines how the mapping coords for a texture are generated.<p> + * + * Real-time applications typically require full UV coordinates, so the use of + * the {@link AiPostProcessSteps#GEN_UV_COORDS} step is highly recommended. + * It generates proper UV channels for non-UV mapped objects, as long as an + * accurate description how the mapping should look like (e.g spherical) is + * given. + */ +public enum AiTextureMapping { + /** + * The mapping coordinates are taken from an UV channel. + * + * The #AI_MATKEY_UVWSRC key specifies from which UV channel + * the texture coordinates are to be taken from (remember, + * meshes can have more than one UV channel). + */ +// aiTextureMapping_UV = 0x0, +// +// /** Spherical mapping */ +// aiTextureMapping_SPHERE = 0x1, +// +// /** Cylindrical mapping */ +// aiTextureMapping_CYLINDER = 0x2, +// +// /** Cubic mapping */ +// aiTextureMapping_BOX = 0x3, +// +// /** Planar mapping */ +// aiTextureMapping_PLANE = 0x4, +// +// /** Undefined mapping. Have fun. */ +// aiTextureMapping_OTHER = 0x5, + +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureOp.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureOp.java new file mode 100644 index 0000000..df87d96 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureOp.java @@ -0,0 +1,137 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Defines how the Nth texture of a specific type is combined with the result + * of all previous layers.<p> + * + * Example (left: key, right: value): <br> + * <code><pre> + * DiffColor0 - gray + * DiffTextureOp0 - aiTextureOpMultiply + * DiffTexture0 - tex1.png + * DiffTextureOp0 - aiTextureOpAdd + * DiffTexture1 - tex2.png + * </pre></code> + * + * Written as equation, the final diffuse term for a specific pixel would be: + * <code><pre> + * diffFinal = DiffColor0 * sampleTex(DiffTexture0,UV0) + + * sampleTex(DiffTexture1,UV0) * diffContrib; + * </pre></code> + * where 'diffContrib' is the intensity of the incoming light for that pixel. + */ +public enum AiTextureOp { + /** + * <code>T = T1 * T2</code>. + */ + MULTIPLY(0x0), + + + /** + * <code>T = T1 + T2</code>. + */ + ADD(0x1), + + + /** + * <code>T = T1 - T2</code>. + */ + SUBTRACT(0x2), + + + /** + * <code>T = T1 / T2</code>. + */ + DIVIDE(0x3), + + + /** + * <code>T = (T1 + T2) - (T1 * T2)</code> . + */ + SMOOTH_ADD(0x4), + + + /** + * <code>T = T1 + (T2-0.5)</code>. + */ + SIGNED_ADD(0x5); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static AiTextureOp fromRawValue(int rawValue) { + for (AiTextureOp type : AiTextureOp.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiTextureOp(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureType.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureType.java new file mode 100644 index 0000000..9b236ee --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiTextureType.java @@ -0,0 +1,218 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +/** + * Defines the purpose of a texture.<p> + * + * This is a very difficult topic. Different 3D packages support different + * kinds of textures. For very common texture types, such as bumpmaps, the + * rendering results depend on implementation details in the rendering + * pipelines of these applications. Assimp loads all texture references from + * the model file and tries to determine which of the predefined texture + * types below is the best choice to match the original use of the texture + * as closely as possible.<p> + * + * In content pipelines you'll usually define how textures have to be handled, + * and the artists working on models have to conform to this specification, + * regardless which 3D tool they're using. + */ +public enum AiTextureType { + /** Dummy value. + * + * No texture, but the value to be used as 'texture semantic' + * (#aiMaterialProperty::mSemantic) for all material properties + * *not* related to textures. + */ + NONE(0), + + /** LEGACY API MATERIALS + * Legacy refers to materials which + * Were originally implemented in the specifications around 2000. + * These must never be removed, as most engines support them. + */ + + /** The texture is combined with the result of the diffuse + * lighting equation. + */ + DIFFUSE(1), + + /** The texture is combined with the result of the specular + * lighting equation. + */ + SPECULAR(2), + + /** The texture is combined with the result of the ambient + * lighting equation. + */ + AMBIENT(3), + + /** The texture is added to the result of the lighting + * calculation. It isn't influenced by incoming light. + */ + EMISSIVE(4), + + /** The texture is a height map. + * + * By convention, higher gray-scale values stand for + * higher elevations from the base height. + */ + HEIGHT(5), + + /** The texture is a (tangent space) normal-map. + * + * Again, there are several conventions for tangent-space + * normal maps. Assimp does (intentionally) not + * distinguish here. + */ + NORMALS(6), + + /** The texture defines the glossiness of the material. + * + * The glossiness is in fact the exponent of the specular + * (phong) lighting equation. Usually there is a conversion + * function defined to map the linear color values in the + * texture to a suitable exponent. Have fun. + */ + SHININESS(7), + + /** The texture defines per-pixel opacity. + * + * Usually 'white' means opaque and 'black' means + * 'transparency'. Or quite the opposite. Have fun. + */ + OPACITY(8), + + /** Displacement texture + * + * The exact purpose and format is application-dependent. + * Higher color values stand for higher vertex displacements. + */ + DISPLACEMENT(9), + + /** Lightmap texture (aka Ambient Occlusion) + * + * Both 'Lightmaps' and dedicated 'ambient occlusion maps' are + * covered by this material property. The texture contains a + * scaling value for the final color value of a pixel. Its + * intensity is not affected by incoming light. + */ + LIGHTMAP(10), + + /** Reflection texture + * + * Contains the color of a perfect mirror reflection. + * Rarely used, almost never for real-time applications. + */ + REFLECTION(11), + + /** PBR Materials + * PBR definitions from maya and other modelling packages now use this standard. + * This was originally introduced around 2012. + * Support for this is in game engines like Godot, Unreal or Unity3D. + * Modelling packages which use this are very common now. + */ + + BASE_COLOR(12), + NORMAL_CAMERA(13), + EMISSION_COLOR(14), + METALNESS(15), + DIFFUSE_ROUGHNESS(16), + AMBIENT_OCCLUSION(17), + + /** Unknown texture + * + * A texture reference that does not match any of the definitions + * above is considered to be 'unknown'. It is still imported, + * but is excluded from any further post-processing. + */ + UNKNOWN(18); + + + /** + * Utility method for converting from c/c++ based integer enums to java + * enums.<p> + * + * This method is intended to be used from JNI and my change based on + * implementation needs. + * + * @param rawValue an integer based enum value (as defined by assimp) + * @return the enum value corresponding to rawValue + */ + static AiTextureType fromRawValue(int rawValue) { + for (AiTextureType type : AiTextureType.values()) { + if (type.m_rawValue == rawValue) { + return type; + } + } + + throw new IllegalArgumentException("unexptected raw value: " + + rawValue); + } + + + /** + * Utility method for converting from java enums to c/c++ based integer + * enums.<p> + * + * @param type the type to convert, may not be null + * @return the rawValue corresponding to type + */ + static int toRawValue(AiTextureType type) { + return type.m_rawValue; + } + + + /** + * Constructor. + * + * @param rawValue maps java enum to c/c++ integer enum values + */ + private AiTextureType(int rawValue) { + m_rawValue = rawValue; + } + + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiVector.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiVector.java new file mode 100644 index 0000000..440be20 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiVector.java @@ -0,0 +1,195 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; + + +/** + * Wrapper for 3-dimensional vectors.<p> + * + * This wrapper is also used to represent 1- and 2-dimensional vectors. In + * these cases only the x (or the x and y coordinate) will be used. + * Accessing unused components will throw UnsupportedOperationExceptions.<p> + * + * The wrapper is writable, i.e., changes performed via the set-methods will + * modify the underlying mesh. + */ +public final class AiVector { + /** + * Constructor. + * + * @param buffer the buffer to wrap + * @param offset offset into buffer + * @param numComponents number vector of components + */ + public AiVector(ByteBuffer buffer, int offset, int numComponents) { + if (null == buffer) { + throw new IllegalArgumentException("buffer may not be null"); + } + + m_buffer = buffer; + m_offset = offset; + m_numComponents = numComponents; + } + + + /** + * Returns the x value. + * + * @return the x value + */ + public float getX() { + return m_buffer.getFloat(m_offset); + } + + + /** + * Returns the y value.<p> + * + * May only be called on 2- or 3-dimensional vectors. + * + * @return the y value + */ + public float getY() { + if (m_numComponents <= 1) { + throw new UnsupportedOperationException( + "vector has only 1 component"); + } + + return m_buffer.getFloat(m_offset + 4); + } + + + /** + * Returns the z value.<p> + * + * May only be called on 3-dimensional vectors. + * + * @return the z value + */ + public float getZ() { + if (m_numComponents <= 2) { + throw new UnsupportedOperationException( + "vector has only 2 components"); + } + + return m_buffer.getFloat(m_offset + 8); + } + + + /** + * Sets the x component. + * + * @param x the new value + */ + public void setX(float x) { + m_buffer.putFloat(m_offset, x); + } + + + /** + * Sets the y component.<p> + * + * May only be called on 2- or 3-dimensional vectors. + * + * @param y the new value + */ + public void setY(float y) { + if (m_numComponents <= 1) { + throw new UnsupportedOperationException( + "vector has only 1 component"); + } + + m_buffer.putFloat(m_offset + 4, y); + } + + + /** + * Sets the z component.<p> + * + * May only be called on 3-dimensional vectors. + * + * @param z the new value + */ + public void setZ(float z) { + if (m_numComponents <= 2) { + throw new UnsupportedOperationException( + "vector has only 2 components"); + } + + m_buffer.putFloat(m_offset + 8, z); + } + + + /** + * Returns the number of components in this vector. + * + * @return the number of components + */ + public int getNumComponents() { + return m_numComponents; + } + + + @Override + public String toString() { + return "[" + getX() + ", " + getY() + ", " + getZ() + "]"; + } + + + /** + * Wrapped buffer. + */ + private final ByteBuffer m_buffer; + + + /** + * Offset into m_buffer. + */ + private final int m_offset; + + + /** + * Number of components. + */ + private final int m_numComponents; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/AiWrapperProvider.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiWrapperProvider.java new file mode 100644 index 0000000..a29f9d1 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/AiWrapperProvider.java @@ -0,0 +1,149 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; + + +/** + * Provides wrapper objects for raw data buffers.<p> + * + * It is likely that applications using Jassimp will already have a scene + * graph implementation and/ or the typical math related classes such as + * vectors, matrices, etc.<p> + * + * To ease the integration with existing code, Jassimp can be customized to + * represent the scene graph and compound data structures such as vectors and + * matrices with user supplied classes.<p> + * + * All methods returning wrapped objects rely on the AiWrapperProvider to + * create individual instances. Custom wrappers can be created by implementing + * AiWrapperProvider and registering the implementation via + * {@link Jassimp#setWrapperProvider(AiWrapperProvider)} <b>before</b> the + * scene is imported.<p> + * + * The methods returning wrapped types take an AiWrapperProvider instance. This + * instance must match the instance set via + * {@link Jassimp#setWrapperProvider(AiWrapperProvider)}. The method parameter + * is used to infer the type of the returned object. The passed in wrapper + * provider is not necessarily used to actually create the wrapped object, as + * the object may be cached for performance reasons. <b>It is not possible to + * use different AiWrapperProviders throughout the lifetime of an imported + * scene.</b> + * + * @param <V3> the type used to represent vectors + * @param <M4> the type used to represent matrices + * @param <C> the type used to represent colors + * @param <N> the type used to represent scene graph nodes + * @param <Q> the type used to represent quaternions + */ +public interface AiWrapperProvider<V3, M4, C, N, Q> { + /** + * Wraps a vector.<p> + * + * Most vectors are 3-dimensional, i.e., with 3 components. The exception + * are texture coordinates, which may be 1- or 2-dimensional. A vector + * consists of numComponents floats (x,y,z) starting from offset + * + * @param buffer the buffer to wrap + * @param offset the offset into buffer + * @param numComponents the number of components + * @return the wrapped vector + */ + V3 wrapVector3f(ByteBuffer buffer, int offset, int numComponents); + + + /** + * Wraps a 4x4 matrix of floats.<p> + * + * The calling code will allocate a new array for each invocation of this + * method. It is safe to store a reference to the passed in array and + * use the array to store the matrix data. + * + * @param data the matrix data in row-major order + * @return the wrapped matrix + */ + M4 wrapMatrix4f(float[] data); + + + /** + * Wraps a RGBA color.<p> + * + * A color consists of 4 float values (r,g,b,a) starting from offset + * + * @param buffer the buffer to wrap + * @param offset the offset into buffer + * @return the wrapped color + */ + C wrapColor(ByteBuffer buffer, int offset); + + + /** + * Wraps a scene graph node.<p> + * + * See {@link AiNode} for a description of the scene graph structure used + * by assimp.<p> + * + * The parent node is either null or an instance returned by this method. + * It is therefore safe to cast the passed in parent object to the + * implementation specific type + * + * @param parent the parent node + * @param matrix the transformation matrix + * @param meshReferences array of mesh references (indexes) + * @param name the name of the node + * @return the wrapped scene graph node + */ + N wrapSceneNode(Object parent, Object matrix, int[] meshReferences, + String name); + + + /** + * Wraps a quaternion.<p> + * + * A quaternion consists of 4 float values (w,x,y,z) starting from offset + * + * @param buffer the buffer to wrap + * @param offset the offset into buffer + * @return the wrapped quaternion + */ + Q wrapQuaternion(ByteBuffer buffer, int offset); +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/JaiDebug.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/JaiDebug.java new file mode 100644 index 0000000..0ed112a --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/JaiDebug.java @@ -0,0 +1,209 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.nio.ByteBuffer; + + +/** + * Debug/utility methods. + */ +public final class JaiDebug { + + /** + * Pure static class, no accessible constructor. + */ + private JaiDebug() { + /* nothing to do */ + } + + + /** + * Dumps vertex positions of a mesh to stdout.<p> + * + * @param mesh the mesh + */ + public static void dumpPositions(AiMesh mesh) { + if (!mesh.hasPositions()) { + System.out.println("mesh has no vertex positions"); + return; + } + + for (int i = 0; i < mesh.getNumVertices(); i++) { + System.out.println("[" + + mesh.getPositionX(i) + ", " + + mesh.getPositionY(i) + ", " + + mesh.getPositionZ(i) + "]" + ); + } + } + + + /** + * Dumps faces of a mesh to stdout.<p> + * + * @param mesh the mesh + */ + public static void dumpFaces(AiMesh mesh) { + if (!mesh.hasFaces()) { + System.out.println("mesh has no faces"); + return; + } + + for (int face = 0; face < mesh.getNumFaces(); face++) { + int faceNumIndices = mesh.getFaceNumIndices(face); + System.out.print(faceNumIndices + ": "); + + for (int vertex = 0; vertex < faceNumIndices; vertex++) { + int reference = mesh.getFaceVertex(face, vertex); + + System.out.print("[" + + mesh.getPositionX(reference) + ", " + + mesh.getPositionY(reference) + ", " + + mesh.getPositionZ(reference) + "] " + ); + } + + System.out.println(); + } + } + + + /** + * Dumps a vertex color set of a mesh to stdout.<p> + * + * @param mesh the mesh + * @param colorset the color set + */ + public static void dumpColorset(AiMesh mesh, int colorset) { + if (!mesh.hasColors(colorset)) { + System.out.println("mesh has no vertex color set " + colorset); + return; + } + + for (int i = 0; i < mesh.getNumVertices(); i++) { + System.out.println("[" + + mesh.getColorR(i, colorset) + ", " + + mesh.getColorG(i, colorset) + ", " + + mesh.getColorB(i, colorset) + ", " + + mesh.getColorA(i, colorset) + "]" + ); + } + } + + + /** + * Dumps a texture coordinate set of a mesh to stdout. + * + * @param mesh the mesh + * @param coords the coordinates + */ + public static void dumpTexCoords(AiMesh mesh, int coords) { + if (!mesh.hasTexCoords(coords)) { + System.out.println("mesh has no texture coordinate set " + coords); + return; + } + + for (int i = 0; i < mesh.getNumVertices(); i++) { + int numComponents = mesh.getNumUVComponents(coords); + System.out.print("[" + mesh.getTexCoordU(i, coords)); + + if (numComponents > 1) { + System.out.print(", " + mesh.getTexCoordV(i, coords)); + } + + if (numComponents > 2) { + System.out.print(", " + mesh.getTexCoordW(i, coords)); + } + + System.out.println("]"); + } + } + + + /** + * Dumps a single material property to stdout. + * + * @param property the property + */ + public static void dumpMaterialProperty(AiMaterial.Property property) { + System.out.print(property.getKey() + " " + property.getSemantic() + + " " + property.getIndex() + ": "); + Object data = property.getData(); + + if (data instanceof ByteBuffer) { + ByteBuffer buf = (ByteBuffer) data; + for (int i = 0; i < buf.capacity(); i++) { + System.out.print(Integer.toHexString(buf.get(i) & 0xFF) + " "); + } + + System.out.println(); + } + else { + System.out.println(data.toString()); + } + } + + + /** + * Dumps all properties of a material to stdout. + * + * @param material the material + */ + public static void dumpMaterial(AiMaterial material) { + for (AiMaterial.Property prop : material.getProperties()) { + dumpMaterialProperty(prop); + } + } + + + /** + * Dumps an animation channel to stdout. + * + * @param nodeAnim the channel + */ + public static void dumpNodeAnim(AiNodeAnim nodeAnim) { + for (int i = 0; i < nodeAnim.getNumPosKeys(); i++) { + System.out.println(i + ": " + nodeAnim.getPosKeyTime(i) + + " ticks, " + nodeAnim.getPosKeyVector(i, Jassimp.BUILTIN)); + } + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/Jassimp.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/Jassimp.java new file mode 100644 index 0000000..4610fb1 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/Jassimp.java @@ -0,0 +1,402 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.EnumSet; +import java.util.Set; + + + +/** + * Entry point to the jassimp library.<p> + * + * Use {@link #importFile(String, Set)} to load a file. + * + * <h3>General Notes and Pitfalls</h3> + * Due to the loading via JNI, strings (for example as returned by the + * <code>getName()</code> methods) are not interned. You should therefore + * compare strings the way it should be done, i.e, via <code>equals()</code>. + * Pointer comparison will fail. + */ +public final class Jassimp { + + /** + * The native interface. + * + * @param filename the file to load + * @param postProcessing post processing flags + * @return the loaded scene, or null if an error occurred + * @throws IOException if an error occurs + */ + private static native AiScene aiImportFile(String filename, + long postProcessing, AiIOSystem<?> ioSystem, + AiProgressHandler progressHandler) throws IOException; + + + /** + * The active wrapper provider. + */ + private static AiWrapperProvider<?, ?, ?, ?, ?> s_wrapperProvider = + new AiBuiltInWrapperProvider(); + + + /** + * The library loader to load the native library. + */ + private static JassimpLibraryLoader s_libraryLoader = + new JassimpLibraryLoader(); + + /** + * Status flag if the library is loaded. + * + * Volatile to avoid problems with double checked locking. + * + */ + private static volatile boolean s_libraryLoaded = false; + + /** + * Lock for library loading. + */ + private static final Object s_libraryLoadingLock = new Object(); + + /** + * The default wrapper provider using built in types. + */ + public static final AiWrapperProvider<?, ?, ?, ?, ?> BUILTIN = + new AiBuiltInWrapperProvider(); + + + /** + * Imports a file via assimp without post processing. + * + * @param filename the file to import + * @return the loaded scene + * @throws IOException if an error occurs + */ + public static AiScene importFile(String filename) throws IOException { + + return importFile(filename, EnumSet.noneOf(AiPostProcessSteps.class)); + } + + /** + * Imports a file via assimp without post processing. + * + * @param filename the file to import + * @param ioSystem ioSystem to load files, or null for default + * @return the loaded scene + * @throws IOException if an error occurs + */ + public static AiScene importFile(String filename, AiIOSystem<?> ioSystem) + throws IOException { + + return importFile(filename, EnumSet.noneOf(AiPostProcessSteps.class), ioSystem); + } + + + /** + * Imports a file via assimp. + * + * @param filename the file to import + * @param postProcessing post processing flags + * @return the loaded scene, or null if an error occurred + * @throws IOException if an error occurs + */ + public static AiScene importFile(String filename, + Set<AiPostProcessSteps> postProcessing) + throws IOException { + return importFile(filename, postProcessing, null); + } + + /** + * Imports a file via assimp. + * + * @param filename the file to import + * @param postProcessing post processing flags + * @param ioSystem ioSystem to load files, or null for default + * @return the loaded scene, or null if an error occurred + * @throws IOException if an error occurs + */ + public static AiScene importFile(String filename, + Set<AiPostProcessSteps> postProcessing, AiIOSystem<?> ioSystem) + throws IOException { + return importFile(filename, postProcessing, ioSystem, null); + } + + /** + * Imports a file via assimp. + * + * @param filename the file to import + * @param postProcessing post processing flags + * @param ioSystem ioSystem to load files, or null for default + * @return the loaded scene, or null if an error occurred + * @throws IOException if an error occurs + */ + public static AiScene importFile(String filename, + Set<AiPostProcessSteps> postProcessing, AiIOSystem<?> ioSystem, + AiProgressHandler progressHandler) throws IOException { + + loadLibrary(); + + return aiImportFile(filename, AiPostProcessSteps.toRawValue( + postProcessing), ioSystem, progressHandler); + } + + + /** + * Returns the size of a struct or ptimitive.<p> + * + * @return the result of sizeof call + */ + public static native int getVKeysize(); + + /** + * @see #getVKeysize + */ + public static native int getQKeysize(); + + /** + * @see #getVKeysize + */ + public static native int getV3Dsize(); + + /** + * @see #getVKeysize + */ + public static native int getfloatsize(); + + /** + * @see #getVKeysize + */ + public static native int getintsize(); + + /** + * @see #getVKeysize + */ + public static native int getuintsize(); + + /** + * @see #getVKeysize + */ + public static native int getdoublesize(); + + /** + * @see #getVKeysize + */ + public static native int getlongsize(); + + /** + * Returns a human readable error description.<p> + * + * This method can be called when one of the import methods fails, i.e., + * throws an exception, to get a human readable error description. + * + * @return the error string + */ + public static native String getErrorString(); + + + /** + * Returns the active wrapper provider.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers). + * + * @return the active wrapper provider + */ + public static AiWrapperProvider<?, ?, ?, ?, ?> getWrapperProvider() { + return s_wrapperProvider; + } + + + /** + * Sets a new wrapper provider.<p> + * + * This method is part of the wrapped API (see {@link AiWrapperProvider} + * for details on wrappers). + * + * @param wrapperProvider the new wrapper provider + */ + public static void setWrapperProvider(AiWrapperProvider<?, ?, ?, ?, ?> + wrapperProvider) { + + s_wrapperProvider = wrapperProvider; + } + + + public static void setLibraryLoader(JassimpLibraryLoader libraryLoader) { + s_libraryLoader = libraryLoader; + } + + + /** + * Helper method for wrapping a matrix.<p> + * + * Used by JNI, do not modify! + * + * @param data the matrix data + * @return the wrapped matrix + */ + static Object wrapMatrix(float[] data) { + return s_wrapperProvider.wrapMatrix4f(data); + } + + + /** + * Helper method for wrapping a color (rgb).<p> + * + * Used by JNI, do not modify! + * + * @param red red component + * @param green green component + * @param blue blue component + * @return the wrapped color + */ + static Object wrapColor3(float red, float green, float blue) { + return wrapColor4(red, green, blue, 1.0f); + } + + + /** + * Helper method for wrapping a color (rgba).<p> + * + * Used by JNI, do not modify! + * + * @param red red component + * @param green green component + * @param blue blue component + * @param alpha alpha component + * @return the wrapped color + */ + static Object wrapColor4(float red, float green, float blue, float alpha) { + ByteBuffer temp = ByteBuffer.allocate(4 * 4); + temp.putFloat(red); + temp.putFloat(green); + temp.putFloat(blue); + temp.putFloat(alpha); + temp.flip(); + return s_wrapperProvider.wrapColor(temp, 0); + } + + + /** + * Helper method for wrapping a vector.<p> + * + * Used by JNI, do not modify! + * + * @param x x component + * @param y y component + * @param z z component + * @return the wrapped vector + */ + static Object wrapVec3(float x, float y, float z) { + ByteBuffer temp = ByteBuffer.allocate(3 * 4); + temp.putFloat(x); + temp.putFloat(y); + temp.putFloat(z); + temp.flip(); + return s_wrapperProvider.wrapVector3f(temp, 0, 3); + } + + + /** + * Helper method for wrapping a scene graph node.<p> + * + * Used by JNI, do not modify! + * + * @param parent the parent node + * @param matrix the transformation matrix + * @param meshRefs array of matrix references + * @param name the name of the node + * @return the wrapped matrix + */ + static Object wrapSceneNode(Object parent, Object matrix, int[] meshRefs, + String name) { + + return s_wrapperProvider.wrapSceneNode(parent, matrix, meshRefs, name); + } + + /** + * Helper method to load the library using the provided JassimpLibraryLoader.<p> + * + * Synchronized to avoid race conditions. + */ + private static void loadLibrary() + { + if(!s_libraryLoaded) + { + synchronized(s_libraryLoadingLock) + { + if(!s_libraryLoaded) + { + s_libraryLoader.loadLibrary(); + NATIVE_AIVEKTORKEY_SIZE = getVKeysize(); + NATIVE_AIQUATKEY_SIZE = getQKeysize(); + NATIVE_AIVEKTOR3D_SIZE = getV3Dsize(); + NATIVE_FLOAT_SIZE = getfloatsize(); + NATIVE_INT_SIZE = getintsize(); + NATIVE_UINT_SIZE = getuintsize(); + NATIVE_DOUBLE_SIZE = getdoublesize(); + NATIVE_LONG_SIZE = getlongsize(); + + s_libraryLoaded = true; + } + } + } + } + + /** + * Pure static class, no accessible constructor. + */ + private Jassimp() { + /* nothing to do */ + } + + public static int NATIVE_AIVEKTORKEY_SIZE; + public static int NATIVE_AIQUATKEY_SIZE; + public static int NATIVE_AIVEKTOR3D_SIZE; + public static int NATIVE_FLOAT_SIZE; + public static int NATIVE_INT_SIZE; + public static int NATIVE_UINT_SIZE; + public static int NATIVE_DOUBLE_SIZE; + public static int NATIVE_LONG_SIZE; +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/JassimpConfig.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/JassimpConfig.java new file mode 100644 index 0000000..7591f0e --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/JassimpConfig.java @@ -0,0 +1,66 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + + +/** + * Global configuration values (limits). + */ +public final class JassimpConfig { + /** + * Maximum number of vertex color sets. + */ + public static final int MAX_NUMBER_COLORSETS = 8; + + + /** + * Maximum number of texture coordinate sets. + */ + public static final int MAX_NUMBER_TEXCOORDS = 8; + + + /** + * Pure static class, no accessible constructor. + */ + private JassimpConfig() { + /* nothing to do */ + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/JassimpLibraryLoader.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/JassimpLibraryLoader.java new file mode 100644 index 0000000..d87cc82 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/JassimpLibraryLoader.java @@ -0,0 +1,65 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +/** + * Library loader for the jassimp library.<p> + * + * The default implementation uses "System.loadLibrary" to + * load the jassimp native library. <p> + * + * Custom implementations should override the loadLibrary() + * function. + * + */ +public class JassimpLibraryLoader +{ + /** + * Function to load the native jassimp library. + * + * Called the first time Jassimp.importFile() is + * called. + */ + public void loadLibrary() + { + System.loadLibrary("jassimp"); + } +} diff --git a/libs/assimp/port/jassimp/jassimp/src/jassimp/package-info.java b/libs/assimp/port/jassimp/jassimp/src/jassimp/package-info.java new file mode 100644 index 0000000..7ec8c88 --- /dev/null +++ b/libs/assimp/port/jassimp/jassimp/src/jassimp/package-info.java @@ -0,0 +1,45 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. +--------------------------------------------------------------------------- +*/ + +/** + * Java binding for the Open Asset Import Library. + */ +package jassimp; diff --git a/libs/assimp/port/swig/DONOTUSEYET b/libs/assimp/port/swig/DONOTUSEYET new file mode 100644 index 0000000..87c6e06 --- /dev/null +++ b/libs/assimp/port/swig/DONOTUSEYET @@ -0,0 +1 @@ +The interface files are by no means complete yet and only work with the not-yet-released D SWIG backend, although adding support for other languages should not be too much of problem via #ifdefs. diff --git a/libs/assimp/port/swig/assimp.i b/libs/assimp/port/swig/assimp.i new file mode 100644 index 0000000..58e1546 --- /dev/null +++ b/libs/assimp/port/swig/assimp.i @@ -0,0 +1,140 @@ +%module assimp + +// SWIG helpers for std::string and std::vector wrapping. +%include <std_string.i> +%include <std_vector.i> + +// Globally enable enum prefix stripping. +%dstripprefix; + + +// PACK_STRUCT is a no-op for SWIG – it does not matter for the generated +// bindings how the underlying C++ code manages its memory. +#define PACK_STRUCT + + +// Helper macros for wrapping the pointer-and-length arrays used in the +// Assimp API. + +%define ASSIMP_ARRAY(CLASS, TYPE, NAME, LENGTH) +%newobject CLASS::NAME; +%extend CLASS { + std::vector<TYPE > *NAME() const { + std::vector<TYPE > *result = new std::vector<TYPE >; + result->reserve(LENGTH); + + for (unsigned int i = 0; i < LENGTH; ++i) { + result->push_back($self->NAME[i]); + } + + return result; + } +} +%ignore CLASS::NAME; +%enddef + +%define ASSIMP_POINTER_ARRAY(CLASS, TYPE, NAME, LENGTH) +%newobject CLASS::NAME; +%extend CLASS { + std::vector<TYPE *> *NAME() const { + std::vector<TYPE *> *result = new std::vector<TYPE *>; + result->reserve(LENGTH); + + TYPE *currentValue = $self->NAME; + TYPE *valueLimit = $self->NAME + LENGTH; + while (currentValue < valueLimit) { + result->push_back(currentValue); + ++currentValue; + } + + return result; + } +} +%ignore CLASS::NAME; +%enddef + +%define ASSIMP_POINTER_ARRAY_ARRAY(CLASS, TYPE, NAME, OUTER_LENGTH, INNER_LENGTH) +%newobject CLASS::NAME; +%extend CLASS { + std::vector<std::vector<TYPE *> > *NAME() const { + std::vector<std::vector<TYPE *> > *result = new std::vector<std::vector<TYPE *> >; + result->reserve(OUTER_LENGTH); + + for (unsigned int i = 0; i < OUTER_LENGTH; ++i) { + std::vector<TYPE *> currentElements; + + if ($self->NAME[i] != 0) { + currentElements.reserve(INNER_LENGTH); + + TYPE *currentValue = $self->NAME[i]; + TYPE *valueLimit = $self->NAME[i] + INNER_LENGTH; + while (currentValue < valueLimit) { + currentElements.push_back(currentValue); + ++currentValue; + } + } + + result->push_back(currentElements); + } + + return result; + } +} +%ignore CLASS::NAME; +%enddef + + +%include "interface/aiDefines.i" +%include "interface/aiTypes.i" +%include "interface/assimp.i" +%include "interface/aiTexture.i" +%include "interface/aiMatrix4x4.i" +%include "interface/aiMatrix3x3.i" +%include "interface/aiVector3D.i" +%include "interface/aiVector2D.i" +%include "interface/aiColor4D.i" +%include "interface/aiLight.i" +%include "interface/aiCamera.i" +%include "interface/aiFileIO.i" +%include "interface/aiAssert.i" +%include "interface/aiVersion.i" +%include "interface/aiAnim.i" +%include "interface/aiMaterial.i" +%include "interface/aiMesh.i" +%include "interface/aiPostProcess.i" +%include "interface/aiConfig.i" +%include "interface/assimp.i" +%include "interface/aiQuaternion.i" +%include "interface/aiScene.i" +%include "interface/Logger.i" +%include "interface/DefaultLogger.i" +%include "interface/NullLogger.i" +%include "interface/LogStream.i" +%include "interface/IOStream.i" +%include "interface/IOSystem.i" + + +// We have to "instantiate" the templates used by the ASSSIMP_*_ARRAY macros +// here at the end to avoid running into forward reference issues (SWIG would +// spit out the helper functions before the header includes for the element +// types otherwise). + +%template(UintVector) std::vector<unsigned int>; +%template(aiAnimationVector) std::vector<aiAnimation *>; +%template(aiAnimMeshVector) std::vector<aiAnimMesh *>; +%template(aiBonesVector) std::vector<aiBone *>; +%template(aiCameraVector) std::vector<aiCamera *>; +%template(aiColor4DVector) std::vector<aiColor4D *>; +%template(aiColor4DVectorVector) std::vector<std::vector<aiColor4D *> >; +%template(aiFaceVector) std::vector<aiFace *>; +%template(aiLightVector) std::vector<aiLight *>; +%template(aiMaterialVector) std::vector<aiMaterial *>; +%template(aiMaterialPropertyVector) std::vector<aiMaterialProperty *>; +%template(aiMeshAnimVector) std::vector<aiMeshAnim *>; +%template(aiMeshVector) std::vector<aiMesh *>; +%template(aiNodeVector) std::vector<aiNode *>; +%template(aiNodeAnimVector) std::vector<aiNodeAnim *>; +%template(aiTextureVector) std::vector<aiTexture *>; +%template(aiVector3DVector) std::vector<aiVector3D *>; +%template(aiVector3DVectorVector) std::vector<std::vector<aiVector3D *> >; +%template(aiVertexWeightVector) std::vector<aiVertexWeight *>; diff --git a/libs/assimp/port/swig/d/build.sh b/libs/assimp/port/swig/d/build.sh new file mode 100755 index 0000000..0bf6bff --- /dev/null +++ b/libs/assimp/port/swig/d/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gcc -shared -fPIC -g3 -I../../../include/ -lassimp -olibassimp_wrap.so assimp_wrap.cxx diff --git a/libs/assimp/port/swig/d/generate.sh b/libs/assimp/port/swig/d/generate.sh new file mode 100755 index 0000000..7de66b1 --- /dev/null +++ b/libs/assimp/port/swig/d/generate.sh @@ -0,0 +1,4 @@ +#!/bin/sh +rm -rf assimp/ +mkdir assimp +swig -c++ -d -outcurrentdir -I../../../include -splitproxy -package assimp $@ ../assimp.i diff --git a/libs/assimp/port/swig/interface/DefaultLogger.i b/libs/assimp/port/swig/interface/DefaultLogger.i new file mode 100644 index 0000000..600d28e --- /dev/null +++ b/libs/assimp/port/swig/interface/DefaultLogger.i @@ -0,0 +1,5 @@ +%{ +#include "DefaultLogger.h" +%} + +%include "DefaultLogger.h" diff --git a/libs/assimp/port/swig/interface/IOStream.i b/libs/assimp/port/swig/interface/IOStream.i new file mode 100644 index 0000000..baca5ef --- /dev/null +++ b/libs/assimp/port/swig/interface/IOStream.i @@ -0,0 +1,5 @@ +%{ +#include "IOStream.h" +%} + +%include "IOStream.h" diff --git a/libs/assimp/port/swig/interface/IOSystem.i b/libs/assimp/port/swig/interface/IOSystem.i new file mode 100644 index 0000000..3e3e04a --- /dev/null +++ b/libs/assimp/port/swig/interface/IOSystem.i @@ -0,0 +1,11 @@ +%{ +#include "IOSystem.h" +%} + +// The const char* overload is used instead. +%ignore Assimp::IOSystem::Exists(const std::string&) const; +%ignore Assimp::IOSystem::Open(const std::string& pFile); +%ignore Assimp::IOSystem::Open(const std::string& pFile, const std::string& pMode); +%ignore Assimp::IOSystem::ComparePaths(const std::string& one, const std::string& second) const; + +%include "IOSystem.h" diff --git a/libs/assimp/port/swig/interface/LogStream.i b/libs/assimp/port/swig/interface/LogStream.i new file mode 100644 index 0000000..022f8e5 --- /dev/null +++ b/libs/assimp/port/swig/interface/LogStream.i @@ -0,0 +1,5 @@ +%{ +#include "LogStream.h" +%} + +%include "LogStream.h" diff --git a/libs/assimp/port/swig/interface/Logger.i b/libs/assimp/port/swig/interface/Logger.i new file mode 100644 index 0000000..cadc50b --- /dev/null +++ b/libs/assimp/port/swig/interface/Logger.i @@ -0,0 +1,5 @@ +%{ +#include "Logger.h" +%} + +%include "Logger.h" diff --git a/libs/assimp/port/swig/interface/NullLogger.i b/libs/assimp/port/swig/interface/NullLogger.i new file mode 100644 index 0000000..5cf42ed --- /dev/null +++ b/libs/assimp/port/swig/interface/NullLogger.i @@ -0,0 +1,5 @@ +%{ +#include "NullLogger.h" +%} + +%include "NullLogger.h" diff --git a/libs/assimp/port/swig/interface/aiAnim.i b/libs/assimp/port/swig/interface/aiAnim.i new file mode 100644 index 0000000..de49700 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiAnim.i @@ -0,0 +1,8 @@ +%{ +#include "aiAnim.h" +%} + +ASSIMP_ARRAY(aiAnimation, aiNodeAnim*, mChannels, $self->mNumChannels); +ASSIMP_ARRAY(aiAnimation, aiMeshAnim*, mMeshChannels, $self->mNumMeshChannels); + +%include "aiAnim.h" diff --git a/libs/assimp/port/swig/interface/aiAssert.i b/libs/assimp/port/swig/interface/aiAssert.i new file mode 100644 index 0000000..bc8a9b8 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiAssert.i @@ -0,0 +1,5 @@ +%{ +#include "aiAssert.h" +%} + +%include "aiAssert.h" diff --git a/libs/assimp/port/swig/interface/aiCamera.i b/libs/assimp/port/swig/interface/aiCamera.i new file mode 100644 index 0000000..5c21245 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiCamera.i @@ -0,0 +1,5 @@ +%{ +#include "aiCamera.h" +%} + +%include "aiCamera.h" diff --git a/libs/assimp/port/swig/interface/aiColor4D.i b/libs/assimp/port/swig/interface/aiColor4D.i new file mode 100644 index 0000000..3c00916 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiColor4D.i @@ -0,0 +1,5 @@ +%{ +#include "aiColor4D.h" +%} + +%include "aiColor4D.h" diff --git a/libs/assimp/port/swig/interface/aiConfig.i b/libs/assimp/port/swig/interface/aiConfig.i new file mode 100644 index 0000000..110abb3 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiConfig.i @@ -0,0 +1,5 @@ +%{ +#include "aiConfig.h" +%} + +%include "aiConfig.h" diff --git a/libs/assimp/port/swig/interface/aiDefines.i b/libs/assimp/port/swig/interface/aiDefines.i new file mode 100644 index 0000000..3a61ea6 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiDefines.i @@ -0,0 +1,5 @@ +%{ +#include "aiDefines.h" +%} + +%include "aiDefines.h" diff --git a/libs/assimp/port/swig/interface/aiFileIO.i b/libs/assimp/port/swig/interface/aiFileIO.i new file mode 100644 index 0000000..5a1e092 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiFileIO.i @@ -0,0 +1,5 @@ +%{ +#include "aiFileIO.h" +%} + +%include "aiFileIO.h" diff --git a/libs/assimp/port/swig/interface/aiLight.i b/libs/assimp/port/swig/interface/aiLight.i new file mode 100644 index 0000000..fbefde7 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiLight.i @@ -0,0 +1,5 @@ +%{ +#include "aiLight.h" +%} + +%include "aiLight.h" diff --git a/libs/assimp/port/swig/interface/aiMaterial.i b/libs/assimp/port/swig/interface/aiMaterial.i new file mode 100644 index 0000000..630e6b7 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiMaterial.i @@ -0,0 +1,33 @@ +%{ +#include "aiMaterial.h" +%} + +ASSIMP_ARRAY(aiMaterial, aiMaterialProperty*, mProperties, $self->mNumProperties) + +%include <typemaps.i> +%apply enum SWIGTYPE *OUTPUT { aiTextureMapping* mapping }; +%apply unsigned int *OUTPUT { unsigned int* uvindex }; +%apply float *OUTPUT { float* blend }; +%apply enum SWIGTYPE *OUTPUT { aiTextureOp* op }; +%apply unsigned int *OUTPUT { unsigned int* flags }; + +%include "aiMaterial.h" + +%clear unsigned int* flags; +%clear aiTextureOp* op; +%clear float *blend; +%clear unsigned int* uvindex; +%clear aiTextureMapping* mapping; + + +%apply int &OUTPUT { int &pOut }; +%apply float &OUTPUT { float &pOut }; + +%template(GetInteger) aiMaterial::Get<int>; +%template(GetFloat) aiMaterial::Get<float>; +%template(GetColor4D) aiMaterial::Get<aiColor4D>; +%template(GetColor3D) aiMaterial::Get<aiColor3D>; +%template(GetString) aiMaterial::Get<aiString>; + +%clear int &pOut; +%clear float &pOut; diff --git a/libs/assimp/port/swig/interface/aiMatrix3x3.i b/libs/assimp/port/swig/interface/aiMatrix3x3.i new file mode 100644 index 0000000..8336d44 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiMatrix3x3.i @@ -0,0 +1,5 @@ +%{ +#include "aiMatrix3x3.h" +%} + +%include "aiMatrix3x3.h" diff --git a/libs/assimp/port/swig/interface/aiMatrix4x4.i b/libs/assimp/port/swig/interface/aiMatrix4x4.i new file mode 100644 index 0000000..976c56b --- /dev/null +++ b/libs/assimp/port/swig/interface/aiMatrix4x4.i @@ -0,0 +1,5 @@ +%{ +#include "aiMatrix4x4.h" +%} + +%include "aiMatrix4x4.h" diff --git a/libs/assimp/port/swig/interface/aiMesh.i b/libs/assimp/port/swig/interface/aiMesh.i new file mode 100644 index 0000000..141366c --- /dev/null +++ b/libs/assimp/port/swig/interface/aiMesh.i @@ -0,0 +1,29 @@ +%{ +#include "aiMesh.h" +%} + + +ASSIMP_ARRAY(aiFace, unsigned int, mIndices, $self->mNumIndices); + +ASSIMP_POINTER_ARRAY(aiBone, aiVertexWeight, mWeights, $self->mNumWeights); + +ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mVertices, $self->mNumVertices); +ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mNormals, $self->mNumVertices); +ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mTangents, $self->mNumVertices); +ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mBitangents, $self->mNumVertices); +ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices); +ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices); + +ASSIMP_ARRAY(aiMesh, aiAnimMesh*, mAnimMeshes, $self->mNumAnimMeshes); +ASSIMP_ARRAY(aiMesh, aiBone*, mBones, $self->mNumBones); +ASSIMP_ARRAY(aiMesh, unsigned int, mNumUVComponents, AI_MAX_NUMBER_OF_TEXTURECOORDS); +ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mVertices, $self->mNumVertices); +ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mNormals, $self->mNumVertices); +ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mTangents, $self->mNumVertices); +ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mBitangents, $self->mNumVertices); +ASSIMP_POINTER_ARRAY(aiMesh, aiFace, mFaces, $self->mNumFaces); +ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices); +ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices); + + +%include "aiMesh.h" diff --git a/libs/assimp/port/swig/interface/aiPostProcess.i b/libs/assimp/port/swig/interface/aiPostProcess.i new file mode 100644 index 0000000..5f64ec5 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiPostProcess.i @@ -0,0 +1,7 @@ +%{ +#include "aiPostProcess.h" +%} + +%feature("d:stripprefix", "aiProcess_") aiPostProcessSteps; + +%include "aiPostProcess.h" diff --git a/libs/assimp/port/swig/interface/aiQuaternion.i b/libs/assimp/port/swig/interface/aiQuaternion.i new file mode 100644 index 0000000..256057a --- /dev/null +++ b/libs/assimp/port/swig/interface/aiQuaternion.i @@ -0,0 +1,5 @@ +%{ +#include "aiQuaternion.h" +%} + +%include "aiQuaternion.h" diff --git a/libs/assimp/port/swig/interface/aiScene.i b/libs/assimp/port/swig/interface/aiScene.i new file mode 100644 index 0000000..7278f33 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiScene.i @@ -0,0 +1,17 @@ +%{ +#include "aiScene.h" +%} + + +ASSIMP_ARRAY(aiScene, aiAnimation*, mAnimations, $self->mNumAnimations); +ASSIMP_ARRAY(aiScene, aiCamera*, mCameras, $self->mNumCameras); +ASSIMP_ARRAY(aiScene, aiLight*, mLights, $self->mNumLights); +ASSIMP_ARRAY(aiScene, aiMaterial*, mMaterials, $self->mNumMaterials); +ASSIMP_ARRAY(aiScene, aiMesh*, mMeshes, $self->mNumMeshes); +ASSIMP_ARRAY(aiScene, aiTexture*, mTextures, $self->mNumTextures); + +ASSIMP_ARRAY(aiNode, aiNode*, mChildren, $self->mNumChildren); +ASSIMP_ARRAY(aiNode, unsigned int, mMeshes, $self->mNumMeshes); + + +%include "aiScene.h" diff --git a/libs/assimp/port/swig/interface/aiTexture.i b/libs/assimp/port/swig/interface/aiTexture.i new file mode 100644 index 0000000..d07d001 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiTexture.i @@ -0,0 +1,5 @@ +%{ +#include "aiTexture.h" +%} + +%include "aiTexture.h" diff --git a/libs/assimp/port/swig/interface/aiTypes.i b/libs/assimp/port/swig/interface/aiTypes.i new file mode 100644 index 0000000..a086dfd --- /dev/null +++ b/libs/assimp/port/swig/interface/aiTypes.i @@ -0,0 +1,8 @@ +%{ +#include "aiTypes.h" +%} + +// The const char* overload is used instead. +%ignore aiString::Set(const std::string& pString); + +%include "aiTypes.h" diff --git a/libs/assimp/port/swig/interface/aiVector2D.i b/libs/assimp/port/swig/interface/aiVector2D.i new file mode 100644 index 0000000..5db15c0 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiVector2D.i @@ -0,0 +1,5 @@ +%{ +#include "aiVector2D.h" +%} + +%include "aiVector2D.h" diff --git a/libs/assimp/port/swig/interface/aiVector3D.i b/libs/assimp/port/swig/interface/aiVector3D.i new file mode 100644 index 0000000..2c83f60 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiVector3D.i @@ -0,0 +1,5 @@ +%{ +#include "aiVector3D.h" +%} + +%include "aiVector3D.h" diff --git a/libs/assimp/port/swig/interface/aiVersion.i b/libs/assimp/port/swig/interface/aiVersion.i new file mode 100644 index 0000000..9ddd532 --- /dev/null +++ b/libs/assimp/port/swig/interface/aiVersion.i @@ -0,0 +1,5 @@ +%{ +#include "aiVersion.h" +%} + +%include "aiVersion.h" diff --git a/libs/assimp/port/swig/interface/assimp.i b/libs/assimp/port/swig/interface/assimp.i new file mode 100644 index 0000000..a1b1404 --- /dev/null +++ b/libs/assimp/port/swig/interface/assimp.i @@ -0,0 +1,45 @@ +%{ +#include "assimp.hpp" +%} + + +namespace Assimp { + +// See docs in assimp.hpp. +%ignore Importer::ReadFile(const std::string& pFile, unsigned int pFlags); +%ignore Importer::GetExtensionList(std::string& szOut); +%ignore Importer::IsExtensionSupported(const std::string& szExtension); + +// These are only necessary for extending Assimp with custom importers or post +// processing steps, which would require wrapping the internal BaseImporter and +// BaseProcess classes. +%ignore Importer::RegisterLoader(BaseImporter* pImp); +%ignore Importer::UnregisterLoader(BaseImporter* pImp); +%ignore Importer::RegisterPPStep(BaseProcess* pImp); +%ignore Importer::UnregisterPPStep(BaseProcess* pImp); +%ignore Importer::FindLoader(const char* szExtension); + +} + + +// Each aiScene has to keep a reference to the Importer to prevent it from +// being garbage collected, whose destructor would release the underlying +// C++ memory the scene is stored in. +%typemap(dcode) aiScene "package Object m_importer;" +%typemap(dout) + aiScene* GetScene, + aiScene* ReadFile, + aiScene* ApplyPostProcessing, + aiScene* ReadFileFromMemory { + void* cPtr = $wcall; + $dclassname ret = (cPtr is null) ? null : new $dclassname(cPtr, $owner);$excode + ret.m_importer = this; + return ret; +} + +%include <typemaps.i> +%apply bool *OUTPUT { bool *bWasExisting }; + +%include "assimp.hpp" + +%clear bool *bWasExisting; |