From cc96f55c6133f0eedb0b8fd5b93cfcea0d880475 Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Sat, 20 Jun 2009 14:49:49 +0000 Subject: [PATCH] Adding samples/SimpleOpenGL. Adding basic math functions to the C API. This functionality is exposed to C++ users via operator overloading of aiMatrix4x4, aiMatrix3x3, aiVector3D. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@442 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- code/Assimp.cpp | 70 +++++- code/ComputeUVMappingProcess.cpp | 38 ++- include/aiDefines.h | 17 +- include/assimp.h | 64 +++++ samples/README | 22 ++ samples/SimpleOpenGL/Sample_SimpleOpenGL.c | 229 ++++++++++++++++++ .../vc8/SimpleOpenGL/SimpleOpenGL.vcproj | 199 +++++++++++++++ samples/workspaces/vc8/samples.sln | 20 ++ 8 files changed, 627 insertions(+), 32 deletions(-) create mode 100644 samples/README create mode 100644 samples/SimpleOpenGL/Sample_SimpleOpenGL.c create mode 100644 samples/workspaces/vc8/SimpleOpenGL/SimpleOpenGL.vcproj create mode 100644 samples/workspaces/vc8/samples.sln diff --git a/code/Assimp.cpp b/code/Assimp.cpp index bb789bda4..ff08efac2 100644 --- a/code/Assimp.cpp +++ b/code/Assimp.cpp @@ -553,7 +553,7 @@ ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x } // ------------------------------------------------------------------------------------------------ -// Affline matrix decomposition +// Matrix decomposition ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, aiQuaternion* rotation, aiVector3D* position) @@ -562,4 +562,72 @@ ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, mat->Decompose(*scaling,*rotation,*position); } +// ------------------------------------------------------------------------------------------------ +// Matrix transpose +ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat) +{ + ai_assert(NULL != mat); + mat->Transpose(); +} + +// ------------------------------------------------------------------------------------------------ +ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat) +{ + ai_assert(NULL != mat); + mat->Transpose(); +} + +// ------------------------------------------------------------------------------------------------ +// Vector transformation +ASSIMP_API void aiTransformVecByMatrix3(C_STRUCT aiVector3D* vec, + const C_STRUCT aiMatrix3x3* mat) +{ + ai_assert(NULL != mat && NULL != vec); + *vec *= (*mat); +} + +// ------------------------------------------------------------------------------------------------ +ASSIMP_API void aiTransformVecByMatrix4(C_STRUCT aiVector3D* vec, + const C_STRUCT aiMatrix4x4* mat) +{ + ai_assert(NULL != mat && NULL != vec); + *vec *= (*mat); +} + +// ------------------------------------------------------------------------------------------------ +// Matrix multiplication +ASSIMP_API void aiMultiplyMatrix4( + C_STRUCT aiMatrix4x4* dst, + const C_STRUCT aiMatrix4x4* src) +{ + ai_assert(NULL != dst && NULL != src); + *dst = (*dst) * (*src); +} + +// ------------------------------------------------------------------------------------------------ +ASSIMP_API void aiMultiplyMatrix3( + C_STRUCT aiMatrix3x3* dst, + const C_STRUCT aiMatrix3x3* src) +{ + ai_assert(NULL != dst && NULL != src); + *dst = (*dst) * (*src); +} + +// ------------------------------------------------------------------------------------------------ +// Matrix identity +ASSIMP_API void aiIdentityMatrix3( + C_STRUCT aiMatrix3x3* mat) +{ + ai_assert(NULL != mat); + *mat = aiMatrix3x3(); +} + +// ------------------------------------------------------------------------------------------------ +ASSIMP_API void aiIdentityMatrix4( + C_STRUCT aiMatrix4x4* mat) +{ + ai_assert(NULL != mat); + *mat = aiMatrix4x4(); +} + diff --git a/code/ComputeUVMappingProcess.cpp b/code/ComputeUVMappingProcess.cpp index 12914541d..8f6d3e593 100644 --- a/code/ComputeUVMappingProcess.cpp +++ b/code/ComputeUVMappingProcess.cpp @@ -184,13 +184,13 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) { aiVector3D center, min, max; + FindMeshCenter(mesh, center, min, max); // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... // currently the mapping axis will always be one of x,y,z, except if the // PretransformVertices step is used (it transforms the meshes into worldspace, // thus changing the mapping axis) if (axis * base_axis_x >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); // For each point get a normalized projection vector in the sphere, // get its longitude and latitude and map them to their respective @@ -204,48 +204,38 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D // Thus we can derive: // lat = arcsin (z) // lon = arctan (y/x) - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) - { + for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + (float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI, - (asin (diff.x) + (float)AI_MATH_HALF_PI) / (float)AI_MATH_PI, 0.f); + out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, + (asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); } } else if (axis * base_axis_y >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) - { + for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + (float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI, - (asin (diff.y) + (float)AI_MATH_HALF_PI) / (float)AI_MATH_PI, 0.f); + out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, + (asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); } } else if (axis * base_axis_z >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) - { + for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + (float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI, - (asin (diff.z) + (float)AI_MATH_HALF_PI) / (float)AI_MATH_PI, 0.f); + out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, + (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); } } // slower code path in case the mapping axis is not one of the coordinate system axes - else - { + else { aiMatrix4x4 mTrafo; aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - FindMeshCenterTransformed(mesh, center, min, max,mTrafo); // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) - { + for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize(); - out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + (float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI, - (asin (diff.z) + (float)AI_MATH_HALF_PI) / (float)AI_MATH_PI, 0.f); + out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, + (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); } } diff --git a/include/aiDefines.h b/include/aiDefines.h index af04c6599..5ae19c704 100644 --- a/include/aiDefines.h +++ b/include/aiDefines.h @@ -208,14 +208,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define ASSIMP_BUILD_DEBUG #endif -/* This is PI. Hi PI. - */ -#define AI_MATH_PI (3.1415926538) -#define AI_MATH_TWO_PI (AI_MATH_PI * 2.0) -#define AI_MATH_HALF_PI (AI_MATH_PI * 0.5) +/* This is PI. Hi PI. */ +#define AI_MATH_PI (3.141592653589793238462643383279 ) +#define AI_MATH_TWO_PI (AI_MATH_PI * 2.0) +#define AI_MATH_HALF_PI (AI_MATH_PI * 0.5) -/* Tiny macro to convert from radians to degrees and the opposite - */ +/* And this is to avoid endless (float) casts */ +#define AI_MATH_PI_F (3.1415926538f) +#define AI_MATH_TWO_PI_F (AI_MATH_PI_F * 2.0f) +#define AI_MATH_HALF_PI_F (AI_MATH_PI_F * 0.5f) + +/* Tiny macro to convert from radians to degrees and back */ #define AI_DEG_TO_RAD(x) (x*0.0174532925f) #define AI_RAD_TO_DEG(x) (x*57.2957795f) diff --git a/include/assimp.h b/include/assimp.h index fc46f8343..1311b4e38 100644 --- a/include/assimp.h +++ b/include/assimp.h @@ -326,6 +326,70 @@ ASSIMP_API void aiDecomposeMatrix( C_STRUCT aiQuaternion* rotation, C_STRUCT aiVector3D* position); +// -------------------------------------------------------------------------------- +/** Transpose a 4x4 matrix. + * @param mat Pointer to the matrix to be transposed + */ +ASSIMP_API void aiTransposeMatrix4( + C_STRUCT aiMatrix4x4* mat); + +// -------------------------------------------------------------------------------- +/** Transpose a 3x3 matrix. + * @param mat Pointer to the matrix to be transposed + */ +ASSIMP_API void aiTransposeMatrix3( + C_STRUCT aiMatrix3x3* mat); + +// -------------------------------------------------------------------------------- +/** Transform a vector by a 3x3 matrix + * @param vec Vector to be transformed. + * @param mat Matrix to transform the vector with. + */ +ASSIMP_API void aiTransformVecByMatrix3( + C_STRUCT aiVector3D* vec, + const C_STRUCT aiMatrix3x3* mat); + +// -------------------------------------------------------------------------------- +/** Transform a vector by a 4x4 matrix + * @param vec Vector to be transformed. + * @param mat Matrix to transform the vector with. + */ +ASSIMP_API void aiTransformVecByMatrix4( + C_STRUCT aiVector3D* vec, + const C_STRUCT aiMatrix4x4* mat); + +// -------------------------------------------------------------------------------- +/** Multiply two 4x4 matrices. + * @param dst First factor, receives result. + * @param src Matrix to be multiplied with 'dst'. + */ +ASSIMP_API void aiMultiplyMatrix4( + C_STRUCT aiMatrix4x4* dst, + const C_STRUCT aiMatrix4x4* src); + +// -------------------------------------------------------------------------------- +/** Multiply two 3x3 matrices. + * @param dst First factor, receives result. + * @param src Matrix to be multiplied with 'dst'. + */ +ASSIMP_API void aiMultiplyMatrix3( + C_STRUCT aiMatrix3x3* dst, + const C_STRUCT aiMatrix3x3* src); + +// -------------------------------------------------------------------------------- +/** Get a 3x3 identity matrix. + * @param mat Matrix to receive its personal identity + */ +ASSIMP_API void aiIdentityMatrix3( + C_STRUCT aiMatrix3x3* mat); + +// -------------------------------------------------------------------------------- +/** Get a 4x4 identity matrix. + * @param mat Matrix to receive its personal identity + */ +ASSIMP_API void aiIdentityMatrix4( + C_STRUCT aiMatrix4x4* mat); + #ifdef __cplusplus } diff --git a/samples/README b/samples/README new file mode 100644 index 000000000..6085aa1f6 --- /dev/null +++ b/samples/README @@ -0,0 +1,22 @@ + +---------------------------------------------------------------------------- +This directory contains various samples to illustrate Assimp's +use in various real-worl environments. Workspaces for all samples +are bundled in ./workspaces, makesfiles can be found in the +respective directories of the samples. + +All GL-based samples depend on GLUT. For use with the VS workspaces, +it's best practice to copy glut right _here_ (./glut/) so the +predefined build configuration will find it. + +Also note that the VS workspaces links against the DLL version of the library, +thus you need to build it first (assimp-release-dll) and copy the dll to the +directory of the sample. + +SimpleOpenGL + + A very simple and streightforward OpenGL sample. It loads a + model (gets the path to it on the command line, default is dwarf.x) + and displays the model as wireframe. Animations and materials are + not evaluated at all. This samples uses the C interface to Assimp. +---------------------------------------------------------------------------- \ No newline at end of file diff --git a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c new file mode 100644 index 000000000..90f1cf778 --- /dev/null +++ b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c @@ -0,0 +1,229 @@ + +// ---------------------------------------------------------------------------- +// Simple sample to prove that Assimp is absolutely easy to use with OpenGL. +// It takes a file name as command line parameter, loads it using standard +// settings and displays it. +// +// If you intend to _use_ this code sample in your app, do yourself a favour +// and replace glVertex3D with VBOs ... +// +// The vc8 solution links against assimp-release-dll_win32 - be sure to +// have this configuration built. +// ---------------------------------------------------------------------------- + +#include "Gl/glut.h" + +// assimp include files. These three are usually needed. +#include "assimp.h" +#include "aiPostProcess.h" +#include "aiScene.h" + +// the global Assimp scene object +const struct aiScene* scene = NULL; +struct aiVector3D scene_min,scene_max; + +// current rotation angle +static float angle = 0.f; + +#define aisgl_min(x,y) (xx?y:x) + +// ---------------------------------------------------------------------------- +void reshape(int width, int height) +{ + const double aspectRatio = (float) width / height, fieldOfView = 45.0; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(fieldOfView, aspectRatio, + 1.0, 1000.0); /* Znear and Zfar */ + glViewport(0, 0, width, height); +} + +// ---------------------------------------------------------------------------- +void get_bounding_box_for_node (const struct aiNode* nd, + struct aiVector3D* min, + struct aiVector3D* max, + struct aiMatrix4x4* trafo +){ + struct aiMatrix4x4 prev; + unsigned int n = 0, t; + + aiMultiplyMatrix4(trafo,&nd->mTransformation); + + for (; n < nd->mNumMeshes; ++n) { + const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; + for (t = 0; t < mesh->mNumVertices; ++t) { + + struct aiVector3D tmp = mesh->mVertices[t]; + aiTransformVecByMatrix4(&tmp,trafo); + + min->x = aisgl_min(min->x,tmp.x); + min->y = aisgl_min(min->y,tmp.y); + min->z = aisgl_min(min->z,tmp.z); + + max->x = aisgl_max(max->x,tmp.x); + max->y = aisgl_max(max->y,tmp.y); + max->z = aisgl_max(max->z,tmp.z); + } + } + + prev = nd->mTransformation; + for (n = 0; n < nd->mNumChildren; ++n) { + get_bounding_box_for_node(nd->mChildren[n],min,max,trafo); + } + *trafo = prev; +} + +// ---------------------------------------------------------------------------- +void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) +{ + struct aiMatrix4x4 trafo; + aiIdentityMatrix4(&trafo); + + min->x = min->y = min->z = 1e10f; + max->x = max->y = max->z = -1e10f; + get_bounding_box_for_node(scene->mRootNode,min,max,&trafo); +} + +// ---------------------------------------------------------------------------- +void recursive_render (const struct aiNode* nd) +{ + unsigned int n = 0, t; + struct aiMatrix4x4 m = nd->mTransformation; + + // update transform + aiTransposeMatrix4(&m); + glMultMatrixf((float*)&m); + + // draw all meshes assigned to this node + for (; n < nd->mNumMeshes; ++n) { + const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; + + glBegin(GL_TRIANGLES); + + for (t = 0; t < mesh->mNumFaces; ++t) { + const struct aiFace* face = &mesh->mFaces[t]; + + glColor3f(1.f,0.f,0.f); + glVertex3fv(&mesh->mVertices[face->mIndices[0]].x); + glVertex3fv(&mesh->mVertices[face->mIndices[1]].x); + glVertex3fv(&mesh->mVertices[face->mIndices[2]].x); + } + + glEnd(); + } + + // draw all children + for (n = 0; n < nd->mNumChildren; ++n) { + recursive_render(nd->mChildren[n]); + } +} + +// ---------------------------------------------------------------------------- +void do_motion (void) +{ + static GLint prev_time = 0; + + int time = glutGet(GLUT_ELAPSED_TIME); + angle += (time-prev_time)*0.01; + prev_time = time; + + glutPostRedisplay (); +} + +// ---------------------------------------------------------------------------- +void display(void) +{ + float tmp; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f); + + // scale the whole asset to fit into our view frustum + tmp = scene_max.x-scene_min.x; + tmp = aisgl_max(scene_max.y-scene_min.y,tmp); + tmp = aisgl_max(scene_max.z-scene_min.z,tmp); + + tmp = 1.f/(tmp); + glScalef(tmp,tmp,tmp); + + // fixme: center around origin + + // rotate it around the y axis + glRotatef(angle,0.f,1.f,0.f); + + // now begin at the root node of the imported data and traverse + // the scenegraph by multipliying subsequent local transforms + // together on GL's matrix stack. + recursive_render(scene->mRootNode); + glutSwapBuffers(); + + do_motion(); +} + +// ---------------------------------------------------------------------------- +int loadasset (const char* path) +{ + // we are taking one of the postprocessing presets to avoid + // writing 20 single postprocessing flags here. + scene = aiImportFile(path,aiProcessPreset_TargetRealtime_Quality); + + if (scene) { + + get_bounding_box(&scene_min,&scene_max); + return 0; + } + return 1; +} + +// ---------------------------------------------------------------------------- +int main(int argc, char **argv) +{ + struct aiLogStream stream; + glutInitWindowSize(900,600); + glutInitWindowPosition(100,100); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); + glutInit(&argc, argv); + + glutCreateWindow("Assimp - Very simple OpenGL sample"); + glutDisplayFunc(display); + glutReshapeFunc(reshape); + + // get a handle to the predefined STDOUT log stream and attach + // it to the logging system. It will be active for all further + // calls to aiImportFile(Ex) and aiApplyPostProcessing. + stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL); + aiAttachLogStream(&stream); + + // ... exactly the same, but this stream will now write the + // log file to assimp_log.txt + stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt"); + aiAttachLogStream(&stream); + + if( 0 != loadasset( argc >= 2 ? argv[1] : "../../test/models/X/dwarf.x")) { + if( argc != 1 || 0 != loadasset( "../../../../test/models/X/dwarf.x")) { + return -1; + } + } + + glPolygonMode(GL_FRONT,GL_LINE); + glPolygonMode(GL_BACK,GL_LINE); + glClearColor(0.1f,0.1f,0.1f,1.f); + + glutGet(GLUT_ELAPSED_TIME); + glutMainLoop(); + + // cleanup - calling 'aiReleaseImport' is important, as the library + // keeps internal resources until the scene is freed again. Not + // doing so can cause severe resource leaking. + aiReleaseImport(scene); + + // We added a log stream to the library, it's our job to disable it + // again. This will definitely release the last resources allocated + // by Assimp. + aiDetachAllLogStreams(); + return 0; +} diff --git a/samples/workspaces/vc8/SimpleOpenGL/SimpleOpenGL.vcproj b/samples/workspaces/vc8/SimpleOpenGL/SimpleOpenGL.vcproj new file mode 100644 index 000000000..a3939fe87 --- /dev/null +++ b/samples/workspaces/vc8/SimpleOpenGL/SimpleOpenGL.vcproj @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/workspaces/vc8/samples.sln b/samples/workspaces/vc8/samples.sln new file mode 100644 index 000000000..934b64680 --- /dev/null +++ b/samples/workspaces/vc8/samples.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleOpenGL", "SimpleOpenGL\SimpleOpenGL.vcproj", "{A53D047C-2C35-44FB-B7DB-2066FE520950}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A53D047C-2C35-44FB-B7DB-2066FE520950}.Debug|Win32.ActiveCfg = Debug|Win32 + {A53D047C-2C35-44FB-B7DB-2066FE520950}.Debug|Win32.Build.0 = Debug|Win32 + {A53D047C-2C35-44FB-B7DB-2066FE520950}.Release|Win32.ActiveCfg = Release|Win32 + {A53D047C-2C35-44FB-B7DB-2066FE520950}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal