summaryrefslogtreecommitdiff
path: root/libs/assimp/tools/assimp_view
diff options
context:
space:
mode:
Diffstat (limited to 'libs/assimp/tools/assimp_view')
-rw-r--r--libs/assimp/tools/assimp_view/AnimEvaluator.cpp180
-rw-r--r--libs/assimp/tools/assimp_view/AnimEvaluator.h92
-rw-r--r--libs/assimp/tools/assimp_view/AssetHelper.h236
-rw-r--r--libs/assimp/tools/assimp_view/Background.cpp463
-rw-r--r--libs/assimp/tools/assimp_view/Background.h128
-rw-r--r--libs/assimp/tools/assimp_view/CMakeLists.txt105
-rw-r--r--libs/assimp/tools/assimp_view/Camera.h85
-rw-r--r--libs/assimp/tools/assimp_view/Display.cpp2302
-rw-r--r--libs/assimp/tools/assimp_view/Display.h542
-rw-r--r--libs/assimp/tools/assimp_view/HUD.pngbin0 -> 40474 bytes
-rw-r--r--libs/assimp/tools/assimp_view/HUDMask.pngbin0 -> 6460 bytes
-rw-r--r--libs/assimp/tools/assimp_view/HelpDialog.cpp103
-rw-r--r--libs/assimp/tools/assimp_view/Input.cpp372
-rw-r--r--libs/assimp/tools/assimp_view/LogDisplay.cpp221
-rw-r--r--libs/assimp/tools/assimp_view/LogDisplay.h99
-rw-r--r--libs/assimp/tools/assimp_view/LogWindow.cpp238
-rw-r--r--libs/assimp/tools/assimp_view/LogWindow.h133
-rw-r--r--libs/assimp/tools/assimp_view/Material.cpp1494
-rw-r--r--libs/assimp/tools/assimp_view/MaterialManager.h195
-rw-r--r--libs/assimp/tools/assimp_view/MeshRenderer.cpp167
-rw-r--r--libs/assimp/tools/assimp_view/MeshRenderer.h99
-rw-r--r--libs/assimp/tools/assimp_view/MessageProc.cpp2434
-rw-r--r--libs/assimp/tools/assimp_view/NOTE@help.rtf.txt2
-rw-r--r--libs/assimp/tools/assimp_view/Normals.cpp155
-rw-r--r--libs/assimp/tools/assimp_view/RenderOptions.h113
-rw-r--r--libs/assimp/tools/assimp_view/SceneAnimator.cpp235
-rw-r--r--libs/assimp/tools/assimp_view/SceneAnimator.h237
-rw-r--r--libs/assimp/tools/assimp_view/Shaders.cpp1397
-rw-r--r--libs/assimp/tools/assimp_view/Shaders.h63
-rw-r--r--libs/assimp/tools/assimp_view/assimp_view.cpp1086
-rw-r--r--libs/assimp/tools/assimp_view/assimp_view.h270
-rw-r--r--libs/assimp/tools/assimp_view/assimp_view.rc468
-rw-r--r--libs/assimp/tools/assimp_view/banner.bmpbin0 -> 144054 bytes
-rw-r--r--libs/assimp/tools/assimp_view/banner_pure.bmpbin0 -> 108054 bytes
-rw-r--r--libs/assimp/tools/assimp_view/base.PNGbin0 -> 1600 bytes
-rw-r--r--libs/assimp/tools/assimp_view/base_anim.bmpbin0 -> 9630 bytes
-rw-r--r--libs/assimp/tools/assimp_view/base_display.bmpbin0 -> 9630 bytes
-rw-r--r--libs/assimp/tools/assimp_view/base_inter.bmpbin0 -> 9630 bytes
-rw-r--r--libs/assimp/tools/assimp_view/base_rendering.bmpbin0 -> 9630 bytes
-rw-r--r--libs/assimp/tools/assimp_view/base_stats.bmpbin0 -> 9630 bytes
-rw-r--r--libs/assimp/tools/assimp_view/fx.bmpbin0 -> 822 bytes
-rw-r--r--libs/assimp/tools/assimp_view/help.rtf418
-rw-r--r--libs/assimp/tools/assimp_view/n.bmpbin0 -> 822 bytes
-rw-r--r--libs/assimp/tools/assimp_view/resource.h235
-rw-r--r--libs/assimp/tools/assimp_view/root.bmpbin0 -> 822 bytes
-rw-r--r--libs/assimp/tools/assimp_view/stdafx.cpp8
-rw-r--r--libs/assimp/tools/assimp_view/stdafx.h73
-rw-r--r--libs/assimp/tools/assimp_view/test.xcfbin0 -> 121875 bytes
-rw-r--r--libs/assimp/tools/assimp_view/text1.bin373
-rw-r--r--libs/assimp/tools/assimp_view/tx.bmpbin0 -> 822 bytes
-rw-r--r--libs/assimp/tools/assimp_view/txi.bmpbin0 -> 822 bytes
51 files changed, 14821 insertions, 0 deletions
diff --git a/libs/assimp/tools/assimp_view/AnimEvaluator.cpp b/libs/assimp/tools/assimp_view/AnimEvaluator.cpp
new file mode 100644
index 0000000..ad8e7f5
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/AnimEvaluator.cpp
@@ -0,0 +1,180 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "AnimEvaluator.h"
+
+#include <assimp/anim.h>
+#include <assimp/ai_assert.h>
+
+using namespace AssimpView;
+
+// ------------------------------------------------------------------------------------------------
+// Constructor on a given animation.
+AnimEvaluator::AnimEvaluator(const aiAnimation *pAnim) :
+ mAnim(pAnim),
+ mLastTime(0.0) {
+ ai_assert(nullptr != pAnim);
+ mLastPositions.resize(pAnim->mNumChannels, std::make_tuple(0, 0, 0));
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor.
+AnimEvaluator::~AnimEvaluator() {
+ // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+// Evaluates the animation tracks for a given time stamp.
+void AnimEvaluator::Evaluate(double pTime) {
+ // extract ticks per second. Assume default value if not given
+ double ticksPerSecond = mAnim->mTicksPerSecond != 0.0 ? mAnim->mTicksPerSecond : 25.0;
+ // every following time calculation happens in ticks
+ pTime *= ticksPerSecond;
+
+ // map into anim's duration
+ double time = 0.0f;
+ if (mAnim->mDuration > 0.0) {
+ time = fmod(pTime, mAnim->mDuration);
+ }
+
+ if (mTransforms.size() != mAnim->mNumChannels) {
+ mTransforms.resize(mAnim->mNumChannels);
+ }
+
+ // calculate the transformations for each animation channel
+ for (unsigned int a = 0; a < mAnim->mNumChannels; ++a) {
+ const aiNodeAnim *channel = mAnim->mChannels[a];
+
+ // ******** Position *****
+ aiVector3D presentPosition(0, 0, 0);
+ if (channel->mNumPositionKeys > 0) {
+ // Look for present frame number. Search from last position if time is after the last time, else from beginning
+ // Should be much quicker than always looking from start for the average use case.
+ unsigned int frame = (time >= mLastTime) ? std::get<0>(mLastPositions[a]) : 0;
+ while (frame < channel->mNumPositionKeys - 1) {
+ if (time < channel->mPositionKeys[frame + 1].mTime) {
+ break;
+ }
+ ++frame;
+ }
+
+ // interpolate between this frame's value and next frame's value
+ unsigned int nextFrame = (frame + 1) % channel->mNumPositionKeys;
+ const aiVectorKey &key = channel->mPositionKeys[frame];
+ const aiVectorKey &nextKey = channel->mPositionKeys[nextFrame];
+ double diffTime = nextKey.mTime - key.mTime;
+ if (diffTime < 0.0) {
+ diffTime += mAnim->mDuration;
+ }
+ if (diffTime > 0) {
+ float factor = float((time - key.mTime) / diffTime);
+ presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor;
+ } else {
+ presentPosition = key.mValue;
+ }
+
+ std::get<0>(mLastPositions[a]) = frame;
+ }
+
+ // ******** Rotation *********
+ aiQuaternion presentRotation(1, 0, 0, 0);
+ if (channel->mNumRotationKeys > 0) {
+ unsigned int frame = (time >= mLastTime) ? std::get<1>(mLastPositions[a]) : 0;
+ while (frame < channel->mNumRotationKeys - 1) {
+ if (time < channel->mRotationKeys[frame + 1].mTime) {
+ break;
+ }
+ ++frame;
+ }
+
+ // interpolate between this frame's value and next frame's value
+ unsigned int nextFrame = (frame + 1) % channel->mNumRotationKeys;
+ const aiQuatKey &key = channel->mRotationKeys[frame];
+ const aiQuatKey &nextKey = channel->mRotationKeys[nextFrame];
+ double diffTime = nextKey.mTime - key.mTime;
+ if (diffTime < 0.0) {
+ diffTime += mAnim->mDuration;
+ }
+ if (diffTime > 0) {
+ float factor = float((time - key.mTime) / diffTime);
+ aiQuaternion::Interpolate(presentRotation, key.mValue, nextKey.mValue, factor);
+ } else {
+ presentRotation = key.mValue;
+ }
+
+ std::get<1>(mLastPositions[a]) = frame;
+ }
+
+ // ******** Scaling **********
+ aiVector3D presentScaling(1, 1, 1);
+ if (channel->mNumScalingKeys > 0) {
+ unsigned int frame = (time >= mLastTime) ? std::get<2>(mLastPositions[a]) : 0;
+ while (frame < channel->mNumScalingKeys - 1) {
+ if (time < channel->mScalingKeys[frame + 1].mTime) {
+ break;
+ }
+ ++frame;
+ }
+
+ // TODO: (thom) interpolation maybe? This time maybe even logarithmic, not linear
+ presentScaling = channel->mScalingKeys[frame].mValue;
+ std::get<2>(mLastPositions[a]) = frame;
+ }
+
+ // build a transformation matrix from it
+ aiMatrix4x4 &mat = mTransforms[a];
+ mat = aiMatrix4x4(presentRotation.GetMatrix());
+ mat.a1 *= presentScaling.x;
+ mat.b1 *= presentScaling.x;
+ mat.c1 *= presentScaling.x;
+ mat.a2 *= presentScaling.y;
+ mat.b2 *= presentScaling.y;
+ mat.c2 *= presentScaling.y;
+ mat.a3 *= presentScaling.z;
+ mat.b3 *= presentScaling.z;
+ mat.c3 *= presentScaling.z;
+ mat.a4 = presentPosition.x;
+ mat.b4 = presentPosition.y;
+ mat.c4 = presentPosition.z;
+ }
+
+ mLastTime = time;
+}
diff --git a/libs/assimp/tools/assimp_view/AnimEvaluator.h b/libs/assimp/tools/assimp_view/AnimEvaluator.h
new file mode 100644
index 0000000..76b22ea
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/AnimEvaluator.h
@@ -0,0 +1,92 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#pragma once
+#ifndef AV_ANIMEVALUATOR_H_INCLUDED
+#define AV_ANIMEVALUATOR_H_INCLUDED
+
+/** Calculates a pose for a given time of an animation */
+
+#include <tuple>
+#include <vector>
+#include <assimp/matrix4x4.h>
+
+struct aiAnimation;
+
+namespace AssimpView {
+
+/**
+ * @brief Calculates transformations for a given timestamp from a set of animation tracks. Not directly useful,
+ * better use the AnimPlayer class.
+ */
+class AnimEvaluator {
+public:
+ /// @brief Constructor on a given animation. The animation is fixed throughout the lifetime of
+ /// the object.
+ /// @param pAnim The animation to calculate poses for. Ownership of the animation object stays
+ /// at the caller, the evaluator just keeps a reference to it as long as it persists.
+ AnimEvaluator(const aiAnimation *pAnim);
+
+ /// @brief The class destructor.
+ ~AnimEvaluator();
+
+ /// @brief Evaluates the animation tracks for a given time stamp.
+ /// The calculated pose can be retrieved as an array of transformation
+ /// matrices afterwards by calling GetTransformations().
+ /// @param pTime The time for which you want to evaluate the animation, in seconds.
+ /// Will be mapped into the animation cycle, so it can get an arbitrary
+ /// value. Best use with ever-increasing time stamps.
+ void Evaluate(double pTime);
+
+ /// @brief Returns the transform matrices calculated at the last Evaluate() call.
+ /// The array matches the mChannels array of the aiAnimation.
+ const std::vector<aiMatrix4x4> &GetTransformations() const { return mTransforms; }
+
+private:
+ const aiAnimation *mAnim;
+ double mLastTime;
+ std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> mLastPositions;
+ std::vector<aiMatrix4x4> mTransforms;
+};
+
+} // end of namespace AssimpView
+
+#endif // AV_ANIMEVALUATOR_H_INCLUDED
diff --git a/libs/assimp/tools/assimp_view/AssetHelper.h b/libs/assimp/tools/assimp_view/AssetHelper.h
new file mode 100644
index 0000000..1ae469f
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/AssetHelper.h
@@ -0,0 +1,236 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_ASSET_HELPER_H_INCLUDED)
+#define AV_ASSET_HELPER_H_INCLUDED
+
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <d3dx9mesh.h>
+
+#include <assimp/scene.h>
+
+namespace AssimpView {
+
+class SceneAnimator;
+
+//-------------------------------------------------------------------------------
+/** \brief Class to wrap ASSIMP's asset output structures
+ */
+//-------------------------------------------------------------------------------
+class AssetHelper {
+public:
+ enum {
+ // the original normal set will be used
+ ORIGINAL = 0x0u,
+
+ // a smoothed normal set will be used
+ SMOOTH = 0x1u,
+
+ // a hard normal set will be used
+ HARD = 0x2u,
+ };
+
+ // default constructor
+ AssetHelper() :
+ iNormalSet(ORIGINAL) {
+ mAnimator = NULL;
+ apcMeshes = NULL;
+ pcScene = NULL;
+ }
+
+ //---------------------------------------------------------------
+ // default vertex data structure
+ // (even if tangents, bitangents or normals aren't
+ // required by the shader they will be committed to the GPU)
+ //---------------------------------------------------------------
+ struct Vertex {
+ aiVector3D vPosition;
+ aiVector3D vNormal;
+
+ D3DCOLOR dColorDiffuse;
+ aiVector3D vTangent;
+ aiVector3D vBitangent;
+ aiVector2D vTextureUV;
+ aiVector2D vTextureUV2;
+ unsigned char mBoneIndices[4];
+ unsigned char mBoneWeights[4]; // last Weight not used, calculated inside the vertex shader
+
+ /** Returns the vertex declaration elements to create a declaration from. */
+ static D3DVERTEXELEMENT9 *GetDeclarationElements() {
+ static D3DVERTEXELEMENT9 decl[] = {
+ { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
+ { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
+ { 0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
+ { 0, 28, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 },
+ { 0, 40, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },
+ { 0, 52, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
+ { 0, 60, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
+ { 0, 68, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 },
+ { 0, 72, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 },
+ D3DDECL_END()
+ };
+
+ return decl;
+ }
+ };
+
+ //---------------------------------------------------------------
+ // FVF vertex structure used for normals
+ //---------------------------------------------------------------
+ struct LineVertex {
+ aiVector3D vPosition;
+ DWORD dColorDiffuse;
+
+ // retrieves the FVF code of the vertex type
+ static DWORD GetFVF() {
+ return D3DFVF_DIFFUSE | D3DFVF_XYZ;
+ }
+ };
+
+ //---------------------------------------------------------------
+ // Helper class to store GPU related resources created for
+ // a given aiMesh
+ //---------------------------------------------------------------
+ class MeshHelper {
+ public:
+ MeshHelper() :
+ eShadingMode(),
+ piVB(NULL),
+ piIB(NULL),
+ piVBNormals(NULL),
+ piEffect(NULL),
+ bSharedFX(false),
+ piDiffuseTexture(NULL),
+ piSpecularTexture(NULL),
+ piAmbientTexture(NULL),
+ piEmissiveTexture(NULL),
+ piNormalTexture(NULL),
+ piOpacityTexture(NULL),
+ piShininessTexture(NULL),
+ piLightmapTexture(NULL),
+ fOpacity(),
+ fShininess(),
+ fSpecularStrength(),
+ twosided(false),
+ pvOriginalNormals(NULL) {}
+
+ ~MeshHelper() {
+ // NOTE: This is done in DeleteAssetData()
+ // TODO: Make this a proper d'tor
+ }
+
+ // shading mode to use. Either Lambert or otherwise phong
+ // will be used in every case
+ aiShadingMode eShadingMode;
+
+ // vertex buffer
+ IDirect3DVertexBuffer9 *piVB;
+
+ // index buffer. For partially transparent meshes
+ // created with dynamic usage to be able to update
+ // the buffer contents quickly
+ IDirect3DIndexBuffer9 *piIB;
+
+ // vertex buffer to be used to draw vertex normals
+ // (vertex normals are generated in every case)
+ IDirect3DVertexBuffer9 *piVBNormals;
+
+ // shader to be used
+ ID3DXEffect *piEffect;
+ bool bSharedFX;
+
+ // material textures
+ IDirect3DTexture9 *piDiffuseTexture;
+ IDirect3DTexture9 *piSpecularTexture;
+ IDirect3DTexture9 *piAmbientTexture;
+ IDirect3DTexture9 *piEmissiveTexture;
+ IDirect3DTexture9 *piNormalTexture;
+ IDirect3DTexture9 *piOpacityTexture;
+ IDirect3DTexture9 *piShininessTexture;
+ IDirect3DTexture9 *piLightmapTexture;
+
+ // material colors
+ D3DXVECTOR4 vDiffuseColor;
+ D3DXVECTOR4 vSpecularColor;
+ D3DXVECTOR4 vAmbientColor;
+ D3DXVECTOR4 vEmissiveColor;
+
+ // opacity for the material
+ float fOpacity;
+
+ // shininess for the material
+ float fShininess;
+
+ // strength of the specular highlight
+ float fSpecularStrength;
+
+ // two-sided?
+ bool twosided;
+
+ // Stores a pointer to the original normal set of the asset
+ aiVector3D *pvOriginalNormals;
+ };
+
+ // One instance per aiMesh in the globally loaded asset
+ MeshHelper **apcMeshes;
+
+ // Scene wrapper instance
+ aiScene *pcScene;
+
+ // Animation player to animate the scene if necessary
+ SceneAnimator *mAnimator;
+
+ // Specifies the normal set to be used
+ unsigned int iNormalSet;
+
+ // ------------------------------------------------------------------
+ // set the normal set to be used
+ void SetNormalSet(unsigned int iSet);
+
+ // ------------------------------------------------------------------
+ // flip all normal vectors
+ void FlipNormals();
+ void FlipNormalsInt();
+};
+} // namespace AssimpView
+
+#endif // !! IG
diff --git a/libs/assimp/tools/assimp_view/Background.cpp b/libs/assimp/tools/assimp_view/Background.cpp
new file mode 100644
index 0000000..e496302
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Background.cpp
@@ -0,0 +1,463 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+#include <assimp/StringUtils.h>
+
+namespace AssimpView {
+
+extern std::string g_szSkyboxShader;
+
+// From: U3D build 1256 (src\kernel\graphic\scenegraph\SkyBox.cpp)
+// ------------------------------------------------------------------------------
+/** \brief Vertex structure for the skybox
+*/
+// ------------------------------------------------------------------------------
+struct SkyBoxVertex {
+ float x, y, z;
+ float u, v, w;
+};
+
+// ------------------------------------------------------------------------------
+/** \brief Vertices for the skybox
+*/
+// ------------------------------------------------------------------------------
+SkyBoxVertex g_cubeVertices_indexed[] = {
+ { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f }, // 0
+ { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f }, // 1
+ { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f }, // 2
+ { 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f }, // 3
+ { -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }, // 4
+ { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f }, // 5
+ { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }, // 6
+ { 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f } // 7
+};
+
+// ------------------------------------------------------------------------------
+/** \brief Indices for the skybox
+*/
+// ------------------------------------------------------------------------------
+unsigned short g_cubeIndices[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 2,
+ 1,
+ 4,
+ 5,
+ 6,
+ 7,
+ 6,
+ 5,
+ 4,
+ 6,
+ 0,
+ 1,
+ 6,
+ 0,
+ 5,
+ 2,
+ 7,
+ 3,
+ 2,
+ 7,
+ 1,
+ 6,
+ 3,
+ 7,
+ 3,
+ 6,
+ 0,
+ 2,
+ 4,
+ 5,
+ 4,
+ 2,
+};
+
+CBackgroundPainter CBackgroundPainter::s_cInstance;
+
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::SetColor(D3DCOLOR p_clrNew) {
+ if (TEXTURE_CUBE == eMode) {
+ RemoveSBDeps();
+ }
+
+ clrColor = p_clrNew;
+ eMode = SIMPLE_COLOR;
+
+ if (pcTexture) {
+ pcTexture->Release();
+ pcTexture = nullptr;
+ }
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::RemoveSBDeps() {
+ MODE e = eMode;
+ eMode = SIMPLE_COLOR;
+ if (g_pcAsset && g_pcAsset->pcScene) {
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
+ if (aiShadingMode_Gouraud != g_pcAsset->apcMeshes[i]->eShadingMode) {
+ CMaterialManager::Instance().DeleteMaterial(g_pcAsset->apcMeshes[i]);
+ CMaterialManager::Instance().CreateMaterial(
+ g_pcAsset->apcMeshes[i], g_pcAsset->pcScene->mMeshes[i]);
+ }
+ }
+ }
+ eMode = e;
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::ResetSB() {
+ mMatrix = aiMatrix4x4();
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::SetCubeMapBG(const char *p_szPath) {
+ bool bHad = false;
+ if (pcTexture) {
+ pcTexture->Release();
+ pcTexture = nullptr;
+ if (TEXTURE_CUBE == eMode) bHad = true;
+ }
+
+ eMode = TEXTURE_CUBE;
+
+ szPath = std::string(p_szPath);
+
+ // ARRRGHH... ugly. TODO: Rewrite this!
+ aiString sz;
+ sz.Set(szPath);
+ CMaterialManager::Instance().FindValidPath(&sz);
+ szPath = std::string(sz.data);
+
+ // now recreate all native resources
+ RecreateNativeResource();
+
+ if (SIMPLE_COLOR != this->eMode) {
+ // this influences all material with specular components
+ if (!bHad) {
+ if (g_pcAsset && g_pcAsset->pcScene) {
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
+ if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode) {
+ CMaterialManager::Instance().DeleteMaterial(g_pcAsset->apcMeshes[i]);
+ CMaterialManager::Instance().CreateMaterial(
+ g_pcAsset->apcMeshes[i], g_pcAsset->pcScene->mMeshes[i]);
+ }
+ }
+ }
+ } else {
+ if (g_pcAsset && g_pcAsset->pcScene) {
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
+ if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode) {
+ g_pcAsset->apcMeshes[i]->piEffect->SetTexture(
+ "lw_tex_envmap", CBackgroundPainter::Instance().GetTexture());
+ }
+ }
+ }
+ }
+ }
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::RotateSB(const aiMatrix4x4 *pm) {
+ this->mMatrix = mMatrix * (*pm);
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::SetTextureBG(const char *p_szPath) {
+ if (TEXTURE_CUBE == this->eMode) this->RemoveSBDeps();
+
+ if (pcTexture) {
+ pcTexture->Release();
+ pcTexture = nullptr;
+ }
+
+ eMode = TEXTURE_2D;
+ szPath = std::string(p_szPath);
+
+ // ARRRGHH... ugly. TODO: Rewrite this!
+ aiString sz;
+ sz.Set(szPath);
+ CMaterialManager::Instance().FindValidPath(&sz);
+ szPath = std::string(sz.data);
+
+ // now recreate all native resources
+ RecreateNativeResource();
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::OnPreRender() {
+ if (SIMPLE_COLOR != eMode) {
+ // clear the z-buffer only (in wireframe mode we must also clear
+ // the color buffer )
+ if (g_sOptions.eDrawMode == RenderOptions::WIREFRAME) {
+ g_piDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET,
+ D3DCOLOR_ARGB(0xff, 100, 100, 100), 1.0f, 0);
+ } else {
+ g_piDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
+ }
+
+ if (TEXTURE_2D == eMode) {
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg, IDC_RT), &sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ struct SVertex {
+ float x, y, z, w, u, v;
+ };
+
+ UINT dw;
+ this->piSkyBoxEffect->Begin(&dw, 0);
+ this->piSkyBoxEffect->BeginPass(0);
+
+ SVertex as[4];
+ as[1].x = 0.0f;
+ as[1].y = 0.0f;
+ as[1].z = 0.2f;
+ as[1].w = 1.0f;
+ as[1].u = 0.0f;
+ as[1].v = 0.0f;
+
+ as[3].x = (float)sRect.right;
+ as[3].y = 0.0f;
+ as[3].z = 0.2f;
+ as[3].w = 1.0f;
+ as[3].u = 1.0f;
+ as[3].v = 0.0f;
+
+ as[0].x = 0.0f;
+ as[0].y = (float)sRect.bottom;
+ as[0].z = 0.2f;
+ as[0].w = 1.0f;
+ as[0].u = 0.0f;
+ as[0].v = 1.0f;
+
+ as[2].x = (float)sRect.right;
+ as[2].y = (float)sRect.bottom;
+ as[2].z = 0.2f;
+ as[2].w = 1.0f;
+ as[2].u = 1.0f;
+ as[2].v = 1.0f;
+
+ as[0].x -= 0.5f;
+ as[1].x -= 0.5f;
+ as[2].x -= 0.5f;
+ as[3].x -= 0.5f;
+ as[0].y -= 0.5f;
+ as[1].y -= 0.5f;
+ as[2].y -= 0.5f;
+ as[3].y -= 0.5f;
+
+ DWORD dw2;
+ g_piDevice->GetFVF(&dw2);
+ g_piDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
+
+ g_piDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2,
+ &as, sizeof(SVertex));
+
+ piSkyBoxEffect->EndPass();
+ piSkyBoxEffect->End();
+
+ g_piDevice->SetFVF(dw2);
+ }
+ return;
+ }
+ // clear both the render target and the z-buffer
+ g_piDevice->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
+ clrColor, 1.0f, 0);
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::OnPostRender() {
+ if (TEXTURE_CUBE == eMode) {
+ aiMatrix4x4 pcProj;
+ GetProjectionMatrix(pcProj);
+
+ aiMatrix4x4 pcCam;
+ aiVector3D vPos = GetCameraMatrix(pcCam);
+
+ aiMatrix4x4 aiMe;
+ aiMe[3][0] = vPos.x;
+ aiMe[3][1] = vPos.y;
+ aiMe[3][2] = vPos.z;
+ aiMe = mMatrix * aiMe;
+
+ pcProj = (aiMe * pcCam) * pcProj;
+
+ piSkyBoxEffect->SetMatrix("WorldViewProjection",
+ (const D3DXMATRIX *)&pcProj);
+
+ UINT dwPasses;
+ piSkyBoxEffect->Begin(&dwPasses, 0);
+ piSkyBoxEffect->BeginPass(0);
+
+ DWORD dw2;
+ g_piDevice->GetFVF(&dw2);
+ g_piDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0));
+
+ g_piDevice->DrawIndexedPrimitiveUP(
+ D3DPT_TRIANGLELIST, 0, 8, 12, g_cubeIndices, D3DFMT_INDEX16,
+ g_cubeVertices_indexed, sizeof(SkyBoxVertex));
+
+ g_piDevice->SetFVF(dw2);
+
+ piSkyBoxEffect->EndPass();
+ piSkyBoxEffect->End();
+ }
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::ReleaseNativeResource() {
+ if (piSkyBoxEffect) {
+ piSkyBoxEffect->Release();
+ piSkyBoxEffect = nullptr;
+ }
+ if (pcTexture) {
+ pcTexture->Release();
+ pcTexture = nullptr;
+ }
+}
+//-------------------------------------------------------------------------------
+void CBackgroundPainter::RecreateNativeResource() {
+ if (SIMPLE_COLOR == eMode) {
+ return;
+ }
+
+ if (TEXTURE_CUBE == eMode) {
+
+ // many skyboxes are 16bit FP format which isn't supported
+ // with bilinear filtering on older cards
+ D3DFORMAT eFmt = D3DFMT_UNKNOWN;
+ if (FAILED(g_piD3D->CheckDeviceFormat(0, D3DDEVTYPE_HAL,
+ D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F))) {
+ eFmt = D3DFMT_A8R8G8B8;
+ }
+
+ if (FAILED(D3DXCreateCubeTextureFromFileEx(
+ g_piDevice,
+ szPath.c_str(),
+ D3DX_DEFAULT,
+ 0,
+ 0,
+ eFmt,
+ D3DPOOL_MANAGED,
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ nullptr,
+ nullptr,
+ (IDirect3DCubeTexture9 **)&pcTexture))) {
+ const char *szEnd = strrchr(szPath.c_str(), '\\');
+ if (!szEnd) szEnd = strrchr(szPath.c_str(), '/');
+ if (!szEnd) szEnd = szPath.c_str() - 1;
+
+ char szTemp[1024];
+ ai_snprintf(szTemp, 1024, "[ERROR] Unable to load background cubemap %s", szEnd + 1);
+
+ CLogDisplay::Instance().AddEntry(szTemp,
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+
+ eMode = SIMPLE_COLOR;
+ return;
+ } else
+ CLogDisplay::Instance().AddEntry("[OK] The skybox has been imported successfully",
+ D3DCOLOR_ARGB(0xFF, 0, 0xFF, 0));
+ } else {
+ if (FAILED(D3DXCreateTextureFromFileEx(
+ g_piDevice,
+ szPath.c_str(),
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ 0,
+ D3DFMT_A8R8G8B8,
+ D3DPOOL_MANAGED,
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ nullptr,
+ nullptr,
+ (IDirect3DTexture9 **)&pcTexture))) {
+ const char *szEnd = strrchr(szPath.c_str(), '\\');
+ if (!szEnd) szEnd = strrchr(szPath.c_str(), '/');
+ if (!szEnd) szEnd = szPath.c_str() - 1;
+
+ char szTemp[1024];
+ ai_snprintf(szTemp, 1024, "[ERROR] Unable to load background texture %s", szEnd + 1);
+
+ CLogDisplay::Instance().AddEntry(szTemp,
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+
+ eMode = SIMPLE_COLOR;
+ return;
+ } else
+ CLogDisplay::Instance().AddEntry("[OK] The background texture has been imported successfully",
+ D3DCOLOR_ARGB(0xFF, 0, 0xFF, 0));
+ }
+ if (!piSkyBoxEffect) {
+ ID3DXBuffer *piBuffer = nullptr;
+ if (FAILED(D3DXCreateEffect(
+ g_piDevice,
+ g_szSkyboxShader.c_str(),
+ (UINT)g_szSkyboxShader.length(),
+ nullptr,
+ nullptr,
+ AI_SHADER_COMPILE_FLAGS,
+ nullptr,
+ &piSkyBoxEffect, &piBuffer))) {
+ // failed to compile the shader
+ if (piBuffer) {
+ MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
+ piBuffer->Release();
+ }
+
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to compile skybox shader",
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+ eMode = SIMPLE_COLOR;
+ return;
+ }
+ }
+ // commit the correct textures to the shader
+ if (TEXTURE_CUBE == eMode) {
+ piSkyBoxEffect->SetTexture("lw_tex_envmap", pcTexture);
+ piSkyBoxEffect->SetTechnique("RenderSkyBox");
+ } else if (TEXTURE_2D == eMode) {
+ piSkyBoxEffect->SetTexture("TEXTURE_2D", pcTexture);
+ piSkyBoxEffect->SetTechnique("RenderImage2D");
+ }
+}
+}; // namespace AssimpView
diff --git a/libs/assimp/tools/assimp_view/Background.h b/libs/assimp/tools/assimp_view/Background.h
new file mode 100644
index 0000000..bbefd10
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Background.h
@@ -0,0 +1,128 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+#pragma once
+
+namespace AssimpView
+{
+
+ class CBackgroundPainter
+ {
+ CBackgroundPainter()
+ :
+ clrColor( D3DCOLOR_ARGB( 0xFF, 100, 100, 100 ) ),
+ pcTexture( NULL ),
+ piSkyBoxEffect( NULL ),
+ eMode( SIMPLE_COLOR )
+ {}
+
+ public:
+
+ // Supported background draw modi
+ enum MODE { SIMPLE_COLOR, TEXTURE_2D, TEXTURE_CUBE };
+
+ // Singleton accessors
+ static CBackgroundPainter s_cInstance;
+ inline static CBackgroundPainter& Instance()
+ {
+ return s_cInstance;
+ }
+
+ // set the current background color
+ // (this removes any textures loaded)
+ void SetColor( D3DCOLOR p_clrNew );
+
+ // Setup a cubemap/a 2d texture as background
+ void SetCubeMapBG( const char* p_szPath );
+ void SetTextureBG( const char* p_szPath );
+
+ // Called by the render loop
+ void OnPreRender();
+ void OnPostRender();
+
+ // Release any native resources associated with the instance
+ void ReleaseNativeResource();
+
+ // Recreate any native resources associated with the instance
+ void RecreateNativeResource();
+
+ // Rotate the skybox
+ void RotateSB( const aiMatrix4x4* pm );
+
+ // Reset the state of the skybox
+ void ResetSB();
+
+ inline MODE GetMode() const
+ {
+ return this->eMode;
+ }
+
+ inline IDirect3DBaseTexture9* GetTexture()
+ {
+ return this->pcTexture;
+ }
+
+ inline ID3DXBaseEffect* GetEffect()
+ {
+ return this->piSkyBoxEffect;
+ }
+
+ private:
+
+ void RemoveSBDeps();
+
+ // current background color
+ D3DCOLOR clrColor;
+
+ // current background texture
+ IDirect3DBaseTexture9* pcTexture;
+ ID3DXEffect* piSkyBoxEffect;
+
+ // current background mode
+ MODE eMode;
+
+ // path to the texture
+ std::string szPath;
+
+ // transformation matrix for the skybox
+ aiMatrix4x4 mMatrix;
+ };
+
+}
diff --git a/libs/assimp/tools/assimp_view/CMakeLists.txt b/libs/assimp/tools/assimp_view/CMakeLists.txt
new file mode 100644
index 0000000..13c4c13
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/CMakeLists.txt
@@ -0,0 +1,105 @@
+# Open Asset Import Library (assimp)
+# ----------------------------------------------------------------------
+#
+# Copyright (c) 2006-2022, 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.
+#
+#----------------------------------------------------------------------
+cmake_minimum_required( VERSION 3.10 )
+
+FIND_PACKAGE(DirectX REQUIRED)
+
+INCLUDE_DIRECTORIES (
+ ${Assimp_SOURCE_DIR}/include
+ ${Assimp_SOURCE_DIR}/code
+ ${DirectX_INCLUDE_DIR}
+)
+
+# Make sure the linker can find the Assimp library once it is built.
+LINK_DIRECTORIES (${Assimp_BINARY_DIR} ${AssetImporter_BINARY_DIR}/lib)
+
+ADD_EXECUTABLE( assimp_viewer WIN32
+ AnimEvaluator.cpp
+ Background.cpp
+ Display.cpp
+ HelpDialog.cpp
+ Input.cpp
+ LogDisplay.cpp
+ LogWindow.cpp
+ Material.cpp
+ MeshRenderer.cpp
+ MessageProc.cpp
+ Normals.cpp
+ SceneAnimator.cpp
+ Shaders.cpp
+ assimp_view.h
+ AnimEvaluator.h
+ SceneAnimator.h
+ MaterialManager.h
+ AssetHelper.h
+ assimp_view.cpp
+ stdafx.cpp
+ assimp_view.rc
+ banner.bmp
+ banner_pure.bmp
+ base_anim.bmp
+ base_display.bmp
+ base_inter.bmp
+ base_rendering.bmp
+ base_stats.bmp
+ fx.bmp
+ n.bmp
+ root.bmp
+ tx.bmp
+ txi.bmp
+)
+
+TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp_viewer)
+
+SET_PROPERTY(TARGET assimp_viewer PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
+
+IF ( MSVC )
+ ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
+ ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
+ # assimp_viewer is ANSI (MBCS) throughout
+ REMOVE_DEFINITIONS( -DUNICODE -D_UNICODE )
+ENDIF ()
+
+# Link the executable to the assimp + dx libs.
+TARGET_LINK_LIBRARIES ( assimp_viewer assimp ${DirectX_LIBRARY} ${DirectX_D3DX9_LIBRARY} comctl32.lib winmm.lib )
+
+INSTALL( TARGETS assimp_viewer
+ DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-dev
+)
diff --git a/libs/assimp/tools/assimp_view/Camera.h b/libs/assimp/tools/assimp_view/Camera.h
new file mode 100644
index 0000000..9c31038
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Camera.h
@@ -0,0 +1,85 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_CAMERA_H_INCLUDED)
+#define AV_CAMERA_H_INCLUDED
+
+//-------------------------------------------------------------------------------
+/** \brief Camera class
+*/
+//-------------------------------------------------------------------------------
+class Camera
+ {
+ public:
+
+
+ Camera ()
+ :
+
+ vPos(0.0f,0.0f,-10.0f),
+ vUp(0.0f,1.0f,0.0f),
+ vLookAt(0.0f,0.0f,1.0f),
+ vRight(0.0f,1.0f,0.0f)
+ {
+
+ }
+ public:
+
+ // position of the camera
+ aiVector3D vPos;
+
+ // up-vector of the camera
+ aiVector3D vUp;
+
+ // camera's looking point is vPos + vLookAt
+ aiVector3D vLookAt;
+
+ // right vector of the camera
+ aiVector3D vRight;
+
+
+ // Equation
+ // (vRight ^ vUp) - vLookAt == 0
+ // needn't apply
+
+ } ;
+
+#endif // !!IG
diff --git a/libs/assimp/tools/assimp_view/Display.cpp b/libs/assimp/tools/assimp_view/Display.cpp
new file mode 100644
index 0000000..95ed416
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Display.cpp
@@ -0,0 +1,2302 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+#include "assimp_view.h"
+#include "AnimEvaluator.h"
+#include "SceneAnimator.h"
+#include <assimp/StringUtils.h>
+
+#include <commdlg.h>
+
+namespace AssimpView {
+
+using namespace Assimp;
+
+extern std::string g_szCheckerBackgroundShader;
+
+struct SVertex
+{
+ float x,y,z,w,u,v;
+};
+
+CDisplay CDisplay::s_cInstance;
+
+extern COLORREF g_aclCustomColors[16] /*= {0}*/;
+extern HKEY g_hRegistry;
+extern float g_fLoadTime;
+
+//-------------------------------------------------------------------------------
+// Table of colors used for normal vectors.
+//-------------------------------------------------------------------------------
+D3DXVECTOR4 g_aclNormalColors[14] =
+{
+ D3DXVECTOR4(0xFF / 255.0f,0xFF / 255.0f,0xFF / 255.0f, 1.0f), // white
+
+ D3DXVECTOR4(0xFF / 255.0f,0x00 / 255.0f,0x00 / 255.0f,1.0f), // red
+ D3DXVECTOR4(0x00 / 255.0f,0xFF / 255.0f,0x00 / 255.0f,1.0f), // green
+ D3DXVECTOR4(0x00 / 255.0f,0x00 / 255.0f,0xFF / 255.0f,1.0f), // blue
+
+ D3DXVECTOR4(0xFF / 255.0f,0xFF / 255.0f,0x00 / 255.0f,1.0f), // yellow
+ D3DXVECTOR4(0xFF / 255.0f,0x00 / 255.0f,0xFF / 255.0f,1.0f), // magenta
+ D3DXVECTOR4(0x00 / 255.0f,0xFF / 255.0f,0xFF / 255.0f,1.0f), // wtf
+
+ D3DXVECTOR4(0xFF / 255.0f,0x60 / 255.0f,0x60 / 255.0f,1.0f), // light red
+ D3DXVECTOR4(0x60 / 255.0f,0xFF / 255.0f,0x60 / 255.0f,1.0f), // light green
+ D3DXVECTOR4(0x60 / 255.0f,0x60 / 255.0f,0xFF / 255.0f,1.0f), // light blue
+
+ D3DXVECTOR4(0xA0 / 255.0f,0x00 / 255.0f,0x00 / 255.0f,1.0f), // dark red
+ D3DXVECTOR4(0x00 / 255.0f,0xA0 / 255.0f,0x00 / 255.0f,1.0f), // dark green
+ D3DXVECTOR4(0x00 / 255.0f,0x00 / 255.0f,0xA0 / 255.0f,1.0f), // dark blue
+
+ D3DXVECTOR4(0x88 / 255.0f,0x88 / 255.0f,0x88 / 255.0f, 1.0f) // gray
+};
+
+
+//-------------------------------------------------------------------------------
+// Recursively count the number of nodes in an asset's node graph
+// Used by LoadAsset()
+//-------------------------------------------------------------------------------
+void GetNodeCount(aiNode* pcNode, unsigned int* piCnt)
+{
+ *piCnt = *piCnt+1;
+ for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
+ GetNodeCount(pcNode->mChildren[i], piCnt);
+ }
+}
+
+//-------------------------------------------------------------------------------
+int CDisplay::EnableAnimTools(BOOL hm) {
+ EnableWindow(GetDlgItem(g_hDlg,IDC_PLAY),hm);
+ EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),hm);
+
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Fill animation combo box
+int CDisplay::FillAnimList(void) {
+ if (0 != g_pcAsset->pcScene->mNumAnimations)
+ {
+ // now fill in all animation names
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumAnimations;++i) {
+ SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_ADDSTRING,0,
+ ( LPARAM ) g_pcAsset->pcScene->mAnimations[i]->mName.data);
+ }
+
+ // also add a dummy - 'none'
+ SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_ADDSTRING,0,(LPARAM)"none");
+
+ // select first
+ SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_SETCURSEL,0,0);
+
+ EnableAnimTools(TRUE);
+ }
+ else // tools remain disabled
+ EnableAnimTools(FALSE);
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Clear the list of animations
+int CDisplay::ClearAnimList(void)
+{
+ // clear the combo box
+ SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_RESETCONTENT,0,0);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Clear the tree view
+int CDisplay::ClearDisplayList(void)
+{
+ // clear the combo box
+ TreeView_DeleteAllItems(GetDlgItem(g_hDlg,IDC_TREE1));
+ this->Reset();
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Add a specific node to the display list
+int CDisplay::AddNodeToDisplayList(
+ unsigned int iIndex,
+ unsigned int iDepth,
+ aiNode* pcNode,
+ HTREEITEM hRoot)
+{
+ ai_assert(nullptr != pcNode);
+ ai_assert(nullptr != hRoot);
+
+ char chTemp[MAXLEN];
+
+ if(0 == pcNode->mName.length) {
+ if (iIndex >= 100) {
+ iIndex += iDepth * 1000;
+ }
+ else if (iIndex >= 10)
+ {
+ iIndex += iDepth * 100;
+ }
+ else
+ iIndex += iDepth * 10;
+ ai_snprintf(chTemp, MAXLEN,"Node %u",iIndex);
+ }
+ else {
+ ai_snprintf(chTemp, MAXLEN,"%s",pcNode->mName.data);
+ }
+ ai_snprintf(chTemp+strlen(chTemp), MAXLEN- strlen(chTemp), iIndex ? " (%i)" : " (%i meshes)",pcNode->mNumMeshes);
+
+ TVITEMEXW tvi;
+ TVINSERTSTRUCTW sNew;
+
+ wchar_t tmp[512];
+ int t = MultiByteToWideChar(CP_UTF8,0,chTemp,-1,tmp,512);
+
+ tvi.pszText = tmp;
+ tvi.cchTextMax = (int)t;
+
+ tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_HANDLE | TVIF_PARAM;
+ tvi.iImage = this->m_aiImageList[AI_VIEW_IMGLIST_NODE];
+ tvi.iSelectedImage = this->m_aiImageList[AI_VIEW_IMGLIST_NODE];
+ tvi.lParam = (LPARAM)5;
+
+ sNew.itemex = tvi;
+ sNew.hInsertAfter = TVI_LAST;
+ sNew.hParent = hRoot;
+
+ // add the item to the list
+ HTREEITEM hTexture = (HTREEITEM)SendMessage(GetDlgItem(g_hDlg,IDC_TREE1),
+ TVM_INSERTITEMW,
+ 0,
+ (LPARAM)(LPTVINSERTSTRUCT)&sNew);
+
+ // recursively add all child nodes
+ ++iDepth;
+ for (unsigned int i = 0; i< pcNode->mNumChildren;++i){
+ AddNodeToDisplayList(i,iDepth,pcNode->mChildren[i],hTexture);
+ }
+
+ // add the node to the list
+ NodeInfo info;
+ info.hTreeItem = hTexture;
+ info.psNode = pcNode;
+ this->AddNode(info);
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+int CDisplay::AddMeshToDisplayList(unsigned int iIndex, HTREEITEM hRoot)
+{
+ aiMesh* pcMesh = g_pcAsset->pcScene->mMeshes[iIndex];
+
+ char chTemp[MAXLEN];
+
+ if(0 == pcMesh->mName.length) {
+ ai_snprintf(chTemp,MAXLEN,"Mesh %u",iIndex);
+ }
+ else {
+ ai_snprintf(chTemp,MAXLEN,"%s",pcMesh->mName.data);
+ }
+ ai_snprintf(chTemp+strlen(chTemp),MAXLEN-strlen(chTemp), iIndex ? " (%i)" : " (%i faces)",pcMesh->mNumFaces);
+
+ TVITEMEXW tvi;
+ TVINSERTSTRUCTW sNew;
+
+ wchar_t tmp[512];
+ int t = MultiByteToWideChar(CP_UTF8,0,chTemp,-1,tmp,512);
+
+ tvi.pszText = tmp;
+ tvi.cchTextMax = (int)t;
+
+ tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_HANDLE | TVIF_PARAM;
+ tvi.iImage = this->m_aiImageList[AI_VIEW_IMGLIST_NODE];
+ tvi.iSelectedImage = this->m_aiImageList[AI_VIEW_IMGLIST_NODE];
+ tvi.lParam = (LPARAM)5;
+
+ sNew.itemex = tvi;
+ sNew.hInsertAfter = TVI_LAST;
+ sNew.hParent = hRoot;
+
+ // add the item to the list
+ HTREEITEM hTexture = (HTREEITEM)SendMessage(GetDlgItem(g_hDlg,IDC_TREE1),
+ TVM_INSERTITEMW,
+ 0,
+ (LPARAM)(LPTVINSERTSTRUCT)&sNew);
+
+ // add the mesh to the list of all mesh entries in the scene browser
+ MeshInfo info;
+ info.hTreeItem = hTexture;
+ info.psMesh = pcMesh;
+ AddMesh(info);
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Replace the currently selected texture by another one
+int CDisplay::ReplaceCurrentTexture(const char* szPath)
+{
+ ai_assert(nullptr != szPath);
+
+ // well ... try to load it
+ IDirect3DTexture9* piTexture = nullptr;
+ aiString szString;
+ strcpy(szString.data,szPath);
+ szString.length = static_cast<ai_uint32>(strlen(szPath));
+ CMaterialManager::Instance().LoadTexture(&piTexture,&szString);
+
+ if (!piTexture) {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to load this texture",
+ D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
+ return 0;
+ }
+
+ // we must also change the icon of the corresponding tree
+ // view item if the default texture was previously set
+ TVITEMEX tvi;
+ tvi.mask = TVIF_SELECTEDIMAGE | TVIF_IMAGE;
+ tvi.iImage = m_aiImageList[AI_VIEW_IMGLIST_MATERIAL];
+ tvi.iSelectedImage = m_aiImageList[AI_VIEW_IMGLIST_MATERIAL];
+
+ TreeView_SetItem(GetDlgItem(g_hDlg,IDC_TREE1),
+ m_pcCurrentTexture->hTreeItem);
+
+ // update all meshes referencing this material
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (this->m_pcCurrentTexture->iMatIndex != g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
+ continue;
+
+ AssetHelper::MeshHelper* pcMesh = g_pcAsset->apcMeshes[i];
+ IDirect3DTexture9** tex = nullptr;
+ const char* tex_string = nullptr;
+
+ switch (this->m_pcCurrentTexture->iType)
+ {
+ case aiTextureType_DIFFUSE:
+ tex = &pcMesh->piDiffuseTexture;
+ tex_string = "DIFFUSE_TEXTURE";
+ break;
+ case aiTextureType_AMBIENT:
+ tex = &pcMesh->piAmbientTexture;
+ tex_string = "AMBIENT_TEXTURE";
+ break;
+ case aiTextureType_SPECULAR:
+ tex = &pcMesh->piSpecularTexture;
+ tex_string = "SPECULAR_TEXTURE";
+ break;
+ case aiTextureType_EMISSIVE:
+ tex = &pcMesh->piEmissiveTexture;
+ tex_string = "EMISSIVE_TEXTURE";
+ break;
+ case aiTextureType_LIGHTMAP:
+ tex = &pcMesh->piLightmapTexture;
+ tex_string = "LIGHTMAP_TEXTURE";
+ break;
+ case aiTextureType_DISPLACEMENT:
+ case aiTextureType_REFLECTION:
+ case aiTextureType_UNKNOWN:
+ break;
+ case aiTextureType_SHININESS:
+ tex = &pcMesh->piShininessTexture;
+ tex_string = "SHININESS_TEXTURE";
+ break;
+ case aiTextureType_NORMALS:
+ case aiTextureType_HEIGHT:
+
+ // special handling here
+ if (pcMesh->piNormalTexture && pcMesh->piNormalTexture != piTexture) {
+ piTexture->AddRef();
+ pcMesh->piNormalTexture->Release();
+ pcMesh->piNormalTexture = piTexture;
+ CMaterialManager::Instance().HMtoNMIfNecessary(pcMesh->piNormalTexture,&pcMesh->piNormalTexture,true);
+ m_pcCurrentTexture->piTexture = &pcMesh->piNormalTexture;
+
+ if (!pcMesh->bSharedFX) {
+ pcMesh->piEffect->SetTexture("NORMAL_TEXTURE",piTexture);
+ }
+ }
+ break;
+ default: //case aiTextureType_OPACITY && case aiTextureType_OPACITY | 0x40000000:
+
+ tex = &pcMesh->piOpacityTexture;
+ tex_string = "OPACITY_TEXTURE";
+ break;
+ };
+ if (tex && *tex && *tex != piTexture)
+ {
+ (**tex).Release();
+ *tex = piTexture;
+ m_pcCurrentTexture->piTexture = tex;
+
+ pcMesh->piEffect->SetTexture(tex_string,piTexture);
+ }
+ }
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::AddTextureToDisplayList(unsigned int iType,
+ unsigned int iIndex,
+ const aiString* szPath,
+ HTREEITEM hFX,
+ unsigned int iUVIndex /*= 0*/,
+ const float fBlendFactor /*= 0.0f*/,
+ aiTextureOp eTextureOp /*= aiTextureOp_Multiply*/,
+ unsigned int iMesh /*= 0*/)
+{
+ ai_assert(nullptr != szPath);
+
+ char chTemp[512];
+ char chTempEmb[256];
+ const char* sz = strrchr(szPath->data,'\\');
+ if (!sz)sz = strrchr(szPath->data,'/');
+ if (!sz)
+ {
+ if ('*' == *szPath->data)
+ {
+ int iIndex2 = atoi(szPath->data+1);
+ ai_snprintf(chTempEmb,256,"Embedded #%i",iIndex2);
+ sz = chTempEmb;
+ }
+ else
+ {
+ sz = szPath->data;
+ }
+ }
+
+ bool bIsExtraOpacity = 0 != (iType & 0x40000000);
+ const char* szType;
+ IDirect3DTexture9** piTexture;
+ switch (iType)
+ {
+ case aiTextureType_DIFFUSE:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piDiffuseTexture;
+ szType = "Diffuse";
+ break;
+ case aiTextureType_SPECULAR:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piSpecularTexture;
+ szType = "Specular";
+ break;
+ case aiTextureType_AMBIENT:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piAmbientTexture;
+ szType = "Ambient";
+ break;
+ case aiTextureType_EMISSIVE:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piEmissiveTexture;
+ szType = "Emissive";
+ break;
+ case aiTextureType_HEIGHT:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture;
+ szType = "Heightmap";
+ break;
+ case aiTextureType_NORMALS:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piNormalTexture;
+ szType = "Normalmap";
+ break;
+ case aiTextureType_SHININESS:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piShininessTexture;
+ szType = "Shininess";
+ break;
+ case aiTextureType_LIGHTMAP:
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piLightmapTexture;
+ szType = "Lightmap";
+ break;
+ case aiTextureType_DISPLACEMENT:
+ piTexture = nullptr;
+ szType = "Displacement";
+ break;
+ case aiTextureType_REFLECTION:
+ piTexture = nullptr;
+ szType = "Reflection";
+ break;
+ case aiTextureType_UNKNOWN:
+ piTexture = nullptr;
+ szType = "Unknown";
+ break;
+ default: // opacity + opacity | mask
+ piTexture = &g_pcAsset->apcMeshes[iMesh]->piOpacityTexture;
+ szType = "Opacity";
+ break;
+ };
+ if (bIsExtraOpacity) {
+ ai_snprintf(chTemp,512,"%s %i (<copy of diffuse #1>)",szType,iIndex+1);
+ }
+ else
+ ai_snprintf(chTemp,512,"%s %i (%s)",szType,iIndex+1,sz);
+
+ TVITEMEX tvi;
+ TVINSERTSTRUCT sNew;
+ tvi.pszText = chTemp;
+ tvi.cchTextMax = (int)strlen(chTemp);
+ tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_HANDLE;
+ tvi.lParam = (LPARAM)20;
+
+ // find out whether this is the default texture or not
+
+ if (piTexture && *piTexture) {
+ // {9785DA94-1D96-426b-B3CB-BADC36347F5E}
+ static const GUID guidPrivateData =
+ { 0x9785da94, 0x1d96, 0x426b,
+ { 0xb3, 0xcb, 0xba, 0xdc, 0x36, 0x34, 0x7f, 0x5e } };
+
+ uint32_t iData = 0;
+ DWORD dwSize = 4;
+ (*piTexture)->GetPrivateData(guidPrivateData,&iData,&dwSize);
+
+ if (0xFFFFFFFF == iData)
+ {
+ tvi.iImage = m_aiImageList[AI_VIEW_IMGLIST_TEXTURE_INVALID];
+ tvi.iSelectedImage = m_aiImageList[AI_VIEW_IMGLIST_TEXTURE_INVALID];
+ }
+ else
+ {
+ tvi.iImage = m_aiImageList[AI_VIEW_IMGLIST_TEXTURE];
+ tvi.iSelectedImage = m_aiImageList[AI_VIEW_IMGLIST_TEXTURE];
+ }
+ }
+ else
+ {
+ tvi.iImage = m_aiImageList[AI_VIEW_IMGLIST_TEXTURE_INVALID];
+ tvi.iSelectedImage = m_aiImageList[AI_VIEW_IMGLIST_TEXTURE_INVALID];
+ }
+
+ sNew.itemex = tvi;
+ sNew.hInsertAfter = TVI_LAST;
+ sNew.hParent = hFX;
+
+ // add the item to the list
+ HTREEITEM hTexture = (HTREEITEM)SendMessage(GetDlgItem(g_hDlg,IDC_TREE1),
+ TVM_INSERTITEM,
+ 0,
+ (LPARAM)(LPTVINSERTSTRUCT)&sNew);
+
+ // add it to the list
+ CDisplay::TextureInfo sInfo;
+ sInfo.iUV = iUVIndex;
+ sInfo.fBlend = fBlendFactor;
+ sInfo.eOp = eTextureOp;
+ sInfo.szPath = szPath->data;
+ sInfo.hTreeItem = hTexture;
+ sInfo.piTexture = piTexture;
+ sInfo.iType = iType;
+ sInfo.iMatIndex = g_pcAsset->pcScene->mMeshes[iMesh]->mMaterialIndex;
+ AddTexture(sInfo);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::AddMaterialToDisplayList(HTREEITEM hRoot,
+ unsigned int iIndex)
+{
+ ai_assert(nullptr != hRoot);
+
+ aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[iIndex];
+
+
+ // find the first mesh using this material index
+ unsigned int iMesh = 0;
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
+ {
+ iMesh = i;
+ break;
+ }
+ }
+
+ // use the name of the material, if possible
+ char chTemp[512];
+ aiString szOut;
+ if (AI_SUCCESS != aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szOut))
+ {
+ ai_snprintf(chTemp,512,"Material %i",iIndex+1);
+ }
+ else
+ {
+ ai_snprintf(chTemp,512,"%s (%i)",szOut.data,iIndex+1);
+ }
+ TVITEMEXW tvi;
+ TVINSERTSTRUCTW sNew;
+
+ wchar_t tmp[512];
+ int t = MultiByteToWideChar(CP_UTF8,0,chTemp,-1,tmp,512);
+
+ tvi.pszText = tmp;
+ tvi.cchTextMax = (int)t;
+ tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_HANDLE | TVIF_PARAM ;
+ tvi.iImage = m_aiImageList[AI_VIEW_IMGLIST_MATERIAL];
+ tvi.iSelectedImage = m_aiImageList[AI_VIEW_IMGLIST_MATERIAL];
+ tvi.lParam = (LPARAM)10;
+
+ sNew.itemex = tvi;
+ sNew.hInsertAfter = TVI_LAST;
+ sNew.hParent = hRoot;
+
+ // add the item to the list
+ HTREEITEM hTexture = (HTREEITEM)SendMessage(GetDlgItem(g_hDlg,IDC_TREE1),
+ TVM_INSERTITEMW,
+ 0,
+ (LPARAM)(LPTVINSERTSTRUCT)&sNew);
+
+ // for each texture in the list ... add it
+ unsigned int iUV;
+ float fBlend;
+ aiTextureOp eOp;
+ aiString szPath;
+ bool bNoOpacity = true;
+ for (unsigned int i = 0; i <= AI_TEXTURE_TYPE_MAX;++i)
+ {
+ unsigned int iNum = 0;
+ while (true)
+ {
+ if (AI_SUCCESS != aiGetMaterialTexture(pcMat,(aiTextureType)i,iNum,
+ &szPath,nullptr, &iUV,&fBlend,&eOp))
+ {
+ break;
+ }
+ if (aiTextureType_OPACITY == i)bNoOpacity = false;
+ AddTextureToDisplayList(i,iNum,&szPath,hTexture,iUV,fBlend,eOp,iMesh);
+ ++iNum;
+ }
+ }
+
+ AssetHelper::MeshHelper* pcMesh = g_pcAsset->apcMeshes[iMesh];
+
+ if (pcMesh->piDiffuseTexture && pcMesh->piDiffuseTexture == pcMesh->piOpacityTexture && bNoOpacity)
+ {
+ // check whether the diffuse texture is not a default texture
+
+ // {9785DA94-1D96-426b-B3CB-BADC36347F5E}
+ static const GUID guidPrivateData =
+ { 0x9785da94, 0x1d96, 0x426b,
+ { 0xb3, 0xcb, 0xba, 0xdc, 0x36, 0x34, 0x7f, 0x5e } };
+
+ uint32_t iData = 0;
+ DWORD dwSize = 4;
+ if(FAILED( pcMesh->piDiffuseTexture->GetPrivateData(guidPrivateData,&iData,&dwSize) ||
+ 0xffffffff == iData))
+ {
+ // seems the diffuse texture contains alpha, therefore it has been
+ // added to the opacity channel, too. Add a special value ...
+ AddTextureToDisplayList(aiTextureType_OPACITY | 0x40000000,
+ 0,&szPath,hTexture,iUV,fBlend,eOp,iMesh);
+ }
+ }
+
+ // add the material to the list
+ MaterialInfo info;
+ info.hTreeItem = hTexture;
+ info.psMaterial = pcMat;
+ info.iIndex = iIndex;
+ info.piEffect = g_pcAsset->apcMeshes[iMesh]->piEffect;
+ this->AddMaterial(info);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Expand all elements in the tree-view
+int CDisplay::ExpandTree()
+{
+ // expand all materials
+ for (std::vector< MaterialInfo >::iterator
+ i = m_asMaterials.begin();
+ i != m_asMaterials.end();++i)
+ {
+ TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),(*i).hTreeItem,TVE_EXPAND);
+ }
+ // expand all nodes
+ for (std::vector< NodeInfo >::iterator
+ i = m_asNodes.begin();
+ i != m_asNodes.end();++i)
+ {
+ TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),(*i).hTreeItem,TVE_EXPAND);
+ }
+ TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),m_hRoot,TVE_EXPAND);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Get image list for tree view
+int CDisplay::LoadImageList(void)
+{
+ if (!m_hImageList)
+ {
+ // First, create the image list we will need.
+ // FIX: Need RGB888 color space to display all colors correctly
+ HIMAGELIST hIml = ImageList_Create( 16,16,ILC_COLOR24, 5, 0 );
+
+ // Load the bitmaps and add them to the image lists.
+ HBITMAP hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BFX));
+ m_aiImageList[AI_VIEW_IMGLIST_MATERIAL] = ImageList_Add(hIml, hBmp, nullptr);
+ DeleteObject(hBmp);
+
+ hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BNODE));
+ m_aiImageList[AI_VIEW_IMGLIST_NODE] = ImageList_Add(hIml, hBmp, nullptr);
+ DeleteObject(hBmp);
+
+ hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BTX));
+ m_aiImageList[AI_VIEW_IMGLIST_TEXTURE] = ImageList_Add(hIml, hBmp, nullptr);
+ DeleteObject(hBmp);
+
+ hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BTXI));
+ m_aiImageList[AI_VIEW_IMGLIST_TEXTURE_INVALID] = ImageList_Add(hIml, hBmp, nullptr);
+ DeleteObject(hBmp);
+
+ hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BROOT));
+ m_aiImageList[AI_VIEW_IMGLIST_MODEL] = ImageList_Add(hIml, hBmp, nullptr);
+ DeleteObject(hBmp);
+
+ // Associate the image list with the tree.
+ TreeView_SetImageList(GetDlgItem(g_hDlg,IDC_TREE1), hIml, TVSIL_NORMAL);
+
+ m_hImageList = hIml;
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Fill tree view
+int CDisplay::FillDisplayList(void)
+{
+ LoadImageList();
+
+ // Initialize the tree view window.
+ // fill in the first entry
+ TVITEMEX tvi;
+ TVINSERTSTRUCT sNew;
+ tvi.pszText = (char*) "Model";
+ tvi.cchTextMax = (int)strlen(tvi.pszText);
+ tvi.mask = TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_HANDLE | TVIF_STATE;
+ tvi.state = TVIS_EXPANDED;
+ tvi.iImage = m_aiImageList[AI_VIEW_IMGLIST_MODEL];
+ tvi.iSelectedImage = m_aiImageList[AI_VIEW_IMGLIST_MODEL];
+ tvi.lParam = (LPARAM)0;
+
+ sNew.itemex = tvi;
+ sNew.hInsertAfter = TVI_ROOT;
+ sNew.hParent = 0;
+
+ // add the root item to the tree
+ m_hRoot = (HTREEITEM)SendMessage(GetDlgItem(g_hDlg,IDC_TREE1),
+ TVM_INSERTITEM,
+ 0,
+ (LPARAM)(LPTVINSERTSTRUCT)&sNew);
+
+ // add each loaded material to the tree
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMaterials;++i)
+ AddMaterialToDisplayList(m_hRoot,i);
+
+ // add each mesh to the tree
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ AddMeshToDisplayList(i,m_hRoot);
+
+ // now add all loaded nodes recursively
+ AddNodeToDisplayList(0,0,g_pcAsset->pcScene->mRootNode,m_hRoot);
+
+ // now expand all parent nodes in the tree
+ ExpandTree();
+
+ // everything reacts a little bit slowly if D3D is rendering,
+ // so give GDI a small hint to leave the couch and work ;-)
+ UpdateWindow(g_hDlg);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Main render loop
+int CDisplay::OnRender()
+{
+ // update possible animation
+ if( g_pcAsset)
+ {
+ static double lastPlaying = 0.;
+
+ ai_assert( g_pcAsset->mAnimator);
+ if (g_bPlay) {
+ g_dCurrent += clock()/ double( CLOCKS_PER_SEC) -lastPlaying;
+
+ double time = g_dCurrent;
+ aiAnimation* mAnim = g_pcAsset->mAnimator->CurrentAnim();
+ if( mAnim && mAnim->mDuration > 0.0) {
+ double tps = mAnim->mTicksPerSecond ? mAnim->mTicksPerSecond : 25.f;
+ time = fmod( time, mAnim->mDuration/tps);
+ SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETPOS,TRUE,LPARAM(10000 * (time/(mAnim->mDuration/tps))));
+ }
+
+ g_pcAsset->mAnimator->Calculate( time );
+ lastPlaying = g_dCurrent;
+ }
+ }
+ // begin the frame
+ g_piDevice->BeginScene();
+
+ switch (m_iViewMode)
+ {
+ case VIEWMODE_FULL:
+ case VIEWMODE_NODE:
+ RenderFullScene();
+ break;
+ case VIEWMODE_MATERIAL:
+ RenderMaterialView();
+ break;
+ case VIEWMODE_TEXTURE:
+ RenderTextureView();
+ break;
+ };
+
+ // Now render the log display in the upper right corner of the window
+ CLogDisplay::Instance().OnRender();
+
+ // present the back-buffer
+ g_piDevice->EndScene();
+ g_piDevice->Present(nullptr,nullptr,nullptr,nullptr);
+
+ // don't remove this, problems on some older machines (AMD timing bug)
+ Sleep(10);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Update UI
+void UpdateColorFieldsInUI()
+{
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR1),nullptr,TRUE);
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR2),nullptr,TRUE);
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR3),nullptr,TRUE);
+
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR1));
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR2));
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR3));
+}
+//-------------------------------------------------------------------------------
+// FIll statistics UI
+int CDisplay::FillDefaultStatistics(void)
+{
+ if (!g_pcAsset)
+ {
+ // clear all stats edit controls
+ SetDlgItemText(g_hDlg,IDC_EVERT,"0");
+ SetDlgItemText(g_hDlg,IDC_EFACE,"0");
+ SetDlgItemText(g_hDlg,IDC_EMAT,"0");
+ SetDlgItemText(g_hDlg,IDC_ENODE,"0");
+ SetDlgItemText(g_hDlg,IDC_ESHADER,"0");
+ SetDlgItemText(g_hDlg,IDC_ETEX,"0");
+ return 1;
+ }
+
+ // get the number of vertices/faces in the model
+ unsigned int iNumVert = 0;
+ unsigned int iNumFaces = 0;
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ iNumVert += g_pcAsset->pcScene->mMeshes[i]->mNumVertices;
+ iNumFaces += g_pcAsset->pcScene->mMeshes[i]->mNumFaces;
+ }
+ // and fill the statistic edit controls
+ char szOut[1024];
+ ai_snprintf(szOut,1024,"%i",(int)iNumVert);
+ SetDlgItemText(g_hDlg,IDC_EVERT,szOut);
+ ai_snprintf(szOut, 1024,"%i",(int)iNumFaces);
+ SetDlgItemText(g_hDlg,IDC_EFACE,szOut);
+ ai_snprintf(szOut, 1024,"%i",(int)g_pcAsset->pcScene->mNumMaterials);
+ SetDlgItemText(g_hDlg,IDC_EMAT,szOut);
+ ai_snprintf(szOut, 1024,"%i",(int)g_pcAsset->pcScene->mNumMeshes);
+ SetDlgItemText(g_hDlg,IDC_EMESH,szOut);
+
+ // need to get the number of nodes
+ iNumVert = 0;
+ GetNodeCount(g_pcAsset->pcScene->mRootNode,&iNumVert);
+ ai_snprintf(szOut, 1024,"%i",(int)iNumVert);
+ SetDlgItemText(g_hDlg,IDC_ENODEWND,szOut);
+
+ // now get the number of unique shaders generated for the asset
+ // (even if the environment changes this number won't change)
+ ai_snprintf(szOut, 1024,"%i", CMaterialManager::Instance().GetShaderCount());
+ SetDlgItemText(g_hDlg,IDC_ESHADER,szOut);
+
+ sprintf(szOut,"%.5f",(float)g_fLoadTime);
+ SetDlgItemText(g_hDlg,IDC_ELOAD,szOut);
+
+ UpdateColorFieldsInUI();
+ UpdateWindow(g_hDlg);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Reset UI
+int CDisplay::Reset(void)
+{
+ // clear all lists
+ m_asMaterials.clear();
+ m_asTextures.clear();
+ m_asNodes.clear();
+ m_asMeshes.clear();
+
+ m_hRoot = nullptr;
+
+ return OnSetupNormalView();
+}
+//-------------------------------------------------------------------------------
+// reset to standard statistics view
+void ShowNormalUIComponents()
+{
+ ShowWindow(GetDlgItem(g_hDlg,IDC_NUMNODES),SW_SHOW);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_ENODEWND),SW_SHOW);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_NUMSHADERS),SW_SHOW);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_LOADTIME),SW_SHOW);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_ESHADER),SW_SHOW);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_ELOAD),SW_SHOW);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_VIEWMATRIX),SW_HIDE);
+}
+//-------------------------------------------------------------------------------
+int CDisplay::OnSetupNormalView()
+{
+ if (VIEWMODE_NODE == m_iViewMode)
+ {
+ ShowNormalUIComponents();
+ }
+
+ // now ... change the meaning of the statistics fields back
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMVERTS),"Vertices:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMNODES),"Nodes:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMFACES),"Faces:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMSHADERS),"Shaders:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMATS),"Materials:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMESHES),"Meshes:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_LOADTIME),"Time:");
+
+ FillDefaultStatistics();
+ SetViewMode(VIEWMODE_FULL);
+
+ // for debugging
+ m_pcCurrentMaterial = nullptr;
+ m_pcCurrentTexture = nullptr;
+ m_pcCurrentNode = nullptr;
+
+ // redraw the color fields in the UI --- their purpose has possibly changed
+ UpdateColorFieldsInUI();
+ UpdateWindow(g_hDlg);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::OnSetupNodeView(NodeInfo* pcNew)
+{
+ ai_assert(nullptr != pcNew);
+
+ if (m_pcCurrentNode == pcNew)return 2;
+
+ // now ... change the meaning of the statistics fields back
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMVERTS),"Vertices:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMFACES),"Faces:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMATS),"Materials:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMESHES),"Meshes:");
+
+ ShowWindow(GetDlgItem(g_hDlg,IDC_NUMNODES),SW_HIDE);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_ENODEWND),SW_HIDE);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_NUMSHADERS),SW_HIDE);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_LOADTIME),SW_HIDE);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_ESHADER),SW_HIDE);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_ELOAD),SW_HIDE);
+ ShowWindow(GetDlgItem(g_hDlg,IDC_VIEWMATRIX),SW_SHOW);
+
+ char szTemp[1024];
+ sprintf(szTemp,
+ "%.2f %.2f %.2f\r\n"
+ "%.2f %.2f %.2f\r\n"
+ "%.2f %.2f %.2f\r\n"
+ "%.2f %.2f %.2f\r\n",
+ pcNew->psNode->mTransformation.a1,
+ pcNew->psNode->mTransformation.b1,
+ pcNew->psNode->mTransformation.c1,
+ pcNew->psNode->mTransformation.a2,
+ pcNew->psNode->mTransformation.b2,
+ pcNew->psNode->mTransformation.c2,
+ pcNew->psNode->mTransformation.a3,
+ pcNew->psNode->mTransformation.b3,
+ pcNew->psNode->mTransformation.c3,
+ pcNew->psNode->mTransformation.a4,
+ pcNew->psNode->mTransformation.b4,
+ pcNew->psNode->mTransformation.c4);
+ SetWindowText(GetDlgItem(g_hDlg,IDC_VIEWMATRIX),szTemp);
+
+
+ m_pcCurrentNode = pcNew;
+ SetViewMode(VIEWMODE_NODE);
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::OnSetupMaterialView(MaterialInfo* pcNew)
+{
+ ai_assert(nullptr != pcNew);
+
+ if (m_pcCurrentMaterial == pcNew)return 2;
+
+ if (VIEWMODE_NODE == m_iViewMode)
+ ShowNormalUIComponents();
+
+ m_pcCurrentMaterial = pcNew;
+ SetViewMode(VIEWMODE_MATERIAL);
+
+ // redraw the color fields in the UI --- their purpose has possibly changed
+ UpdateColorFieldsInUI();
+ UpdateWindow(g_hDlg);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::OnSetupTextureView(TextureInfo* pcNew)
+{
+ ai_assert(nullptr != pcNew);
+
+ if (this->m_pcCurrentTexture == pcNew)return 2;
+
+ if (VIEWMODE_NODE == this->m_iViewMode)
+ {
+ ShowNormalUIComponents();
+ }
+
+ if ((aiTextureType_OPACITY | 0x40000000) == pcNew->iType)
+ {
+ // for opacity textures display a warn message
+ CLogDisplay::Instance().AddEntry("[INFO] This texture is not existing in the "
+ "original mesh",D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ CLogDisplay::Instance().AddEntry("It is a copy of the alpha channel of the first "
+ "diffuse texture",D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ }
+
+ // check whether the pattern background effect is supported
+ if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0))
+ {
+ CLogDisplay::Instance().AddEntry("[WARN] The background shader won't work "
+ "on your system, it required PS 3.0 hardware. A default color is used ...",
+ D3DCOLOR_ARGB(0xFF,0xFF,0x00,0));
+ }
+
+ this->m_fTextureZoom = 1000.0f;
+ this->m_vTextureOffset.x = this->m_vTextureOffset.y = 0.0f;
+
+ this->m_pcCurrentTexture = pcNew;
+ this->SetViewMode(VIEWMODE_TEXTURE);
+
+ // now ... change the meaning of the statistics fields
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMVERTS),"Width:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMNODES),"Height:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMFACES),"Format:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMSHADERS),"MIPs:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMATS),"UV:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMESHES),"Blend:");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_LOADTIME),"Op:");
+
+ // and fill them with data
+ D3DSURFACE_DESC sDesc;
+ if (pcNew->piTexture && *pcNew->piTexture) {
+ (*pcNew->piTexture)->GetLevelDesc(0,&sDesc);
+ char szTemp[128];
+
+ sprintf(szTemp,"%i",sDesc.Width);
+ SetWindowText(GetDlgItem(g_hDlg,IDC_EVERT),szTemp);
+
+ sprintf(szTemp,"%i",sDesc.Height);
+ SetWindowText(GetDlgItem(g_hDlg,IDC_ENODEWND),szTemp);
+
+ sprintf(szTemp,"%i",(*pcNew->piTexture)->GetLevelCount());
+ SetWindowText(GetDlgItem(g_hDlg,IDC_ESHADER),szTemp);
+
+ sprintf(szTemp,"%u",pcNew->iUV);
+ SetWindowText(GetDlgItem(g_hDlg,IDC_EMAT),szTemp);
+
+ sprintf(szTemp,"%f",pcNew->fBlend);
+ SetWindowText(GetDlgItem(g_hDlg,IDC_EMESH),szTemp);
+
+ const char* szOp;
+ switch (pcNew->eOp)
+ {
+ case aiTextureOp_Add:
+ szOp = "add";
+ break;
+ case aiTextureOp_Subtract:
+ szOp = "sub";
+ break;
+ case aiTextureOp_Divide:
+ szOp = "div";
+ break;
+ case aiTextureOp_SignedAdd:
+ szOp = "addsign";
+ break;
+ case aiTextureOp_SmoothAdd:
+ szOp = "addsmooth";
+ break;
+ default:
+ szOp = "mul";
+ break;
+ };
+ SetWindowText(GetDlgItem(g_hDlg,IDC_ELOAD),szOp);
+
+ // NOTE: Format is always ARGB8888 since other formats are
+ // converted to this format ...
+ SetWindowText(GetDlgItem(g_hDlg,IDC_EFACE),"ARGB8");
+
+ // check whether this is the default texture
+ if (pcNew->piTexture)
+ {
+ // {9785DA94-1D96-426b-B3CB-BADC36347F5E}
+ static const GUID guidPrivateData =
+ { 0x9785da94, 0x1d96, 0x426b,
+ { 0xb3, 0xcb, 0xba, 0xdc, 0x36, 0x34, 0x7f, 0x5e } };
+
+ uint32_t iData = 0;
+ DWORD dwSize = 4;
+ (*pcNew->piTexture)->GetPrivateData(guidPrivateData,&iData,&dwSize);
+
+ if (0xFFFFFFFF == iData)
+ {
+ CLogDisplay::Instance().AddEntry("[ERROR] Texture could not be loaded. "
+ "The displayed texture is a default texture",
+ D3DCOLOR_ARGB(0xFF,0xFF,0,0));
+ return 0;
+ }
+ }
+ }
+ // redraw the color fields in the UI --- their purpose has possibly changed
+ UpdateColorFieldsInUI();
+ UpdateWindow(g_hDlg);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::OnSetup(HTREEITEM p_hTreeItem)
+{
+ // search in our list for the item
+ union {
+ TextureInfo* pcNew;
+ NodeInfo* pcNew2;
+ MaterialInfo* pcNew3;
+ };
+
+ pcNew = nullptr;
+ for (std::vector<TextureInfo>::iterator i = m_asTextures.begin();i != m_asTextures.end();++i){
+ if (p_hTreeItem == (*i).hTreeItem) {
+ pcNew = &(*i);
+ break;
+ }
+ }
+ if (pcNew) {
+ return OnSetupTextureView(pcNew);
+ }
+
+ // search the node list
+ for (std::vector<NodeInfo>::iterator i = m_asNodes.begin(); i != m_asNodes.end();++i){
+ if (p_hTreeItem == (*i).hTreeItem) {
+ pcNew2 = &(*i);
+ break;
+ }
+ }
+ if (pcNew2) {
+ return OnSetupNodeView(pcNew2);
+ }
+
+ // search the material list
+ for (std::vector<MaterialInfo>::iterator i = m_asMaterials.begin();i != m_asMaterials.end();++i){
+ if (p_hTreeItem == (*i).hTreeItem){
+ pcNew3 = &(*i);
+ break;
+ }
+ }
+ if (pcNew3) {
+ return OnSetupMaterialView(pcNew3);
+ }
+ return OnSetupNormalView();
+}
+//-------------------------------------------------------------------------------
+int CDisplay::ShowTreeViewContextMenu(HTREEITEM hItem)
+{
+ ai_assert(nullptr != hItem);
+
+ HMENU hDisplay = nullptr;
+
+ // search in our list for the item
+ TextureInfo* pcNew = nullptr;
+ for (std::vector<TextureInfo>::iterator
+ i = m_asTextures.begin();
+ i != m_asTextures.end();++i)
+ {
+ if (hItem == (*i).hTreeItem) {
+ pcNew = &(*i);
+ break;
+ }
+ }
+ if (pcNew)
+ {
+ HMENU hMenu = LoadMenu(g_hInstance,MAKEINTRESOURCE(IDR_TXPOPUP));
+ hDisplay = GetSubMenu(hMenu,0);
+ }
+
+ // search in the material list for the item
+ MaterialInfo* pcNew2 = nullptr;
+ for (std::vector<MaterialInfo>::iterator
+ i = m_asMaterials.begin();
+ i != m_asMaterials.end();++i)
+ {
+ if (hItem == (*i).hTreeItem) {
+ pcNew2 = &(*i);
+ break;
+ }
+ }
+ if (pcNew2)
+ {
+ HMENU hMenu = LoadMenu(g_hInstance,MAKEINTRESOURCE(IDR_MATPOPUP));
+ hDisplay = GetSubMenu(hMenu,0);
+ }
+ if (nullptr != hDisplay)
+ {
+ // select this entry (this should all OnSetup())
+ TreeView_Select(GetDlgItem(g_hDlg,IDC_TREE1),hItem,TVGN_CARET);
+
+ // FIX: Render the scene once that the correct texture/material
+ // is displayed while the context menu is active
+ OnRender();
+
+ POINT sPoint;
+ GetCursorPos(&sPoint);
+ TrackPopupMenu(hDisplay, TPM_LEFTALIGN, sPoint.x, sPoint.y, 0,
+ g_hDlg,nullptr);
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::HandleTreeViewPopup(WPARAM wParam,LPARAM lParam)
+{
+ // get the current selected material
+ std::vector<Info> apclrOut;
+ const char* szMatKey = "";
+
+ switch (LOWORD(wParam))
+ {
+ case ID_SOLONG_CLEARDIFFUSECOLOR:
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (this->m_pcCurrentMaterial->iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
+ {
+ apclrOut.push_back( Info( &g_pcAsset->apcMeshes[i]->vDiffuseColor,
+ g_pcAsset->apcMeshes[i],"DIFFUSE_COLOR"));
+ }
+ }
+ szMatKey = "$clr.diffuse";
+ break;
+ case ID_SOLONG_CLEARSPECULARCOLOR:
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (this->m_pcCurrentMaterial->iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
+ {
+ apclrOut.push_back( Info( &g_pcAsset->apcMeshes[i]->vSpecularColor,
+ g_pcAsset->apcMeshes[i],"SPECULAR_COLOR"));
+ }
+ }
+ szMatKey = "$clr.specular";
+ break;
+ case ID_SOLONG_CLEARAMBIENTCOLOR:
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (this->m_pcCurrentMaterial->iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
+ {
+ apclrOut.push_back( Info( &g_pcAsset->apcMeshes[i]->vAmbientColor,
+ g_pcAsset->apcMeshes[i],"AMBIENT_COLOR"));
+ }
+ }
+ szMatKey = "$clr.ambient";
+ break;
+ case ID_SOLONG_CLEAREMISSIVECOLOR:
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (this->m_pcCurrentMaterial->iIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
+ {
+ apclrOut.push_back( Info( &g_pcAsset->apcMeshes[i]->vEmissiveColor,
+ g_pcAsset->apcMeshes[i],"EMISSIVE_COLOR"));
+ }
+ }
+ szMatKey = "$clr.emissive";
+ break;
+ default:
+
+ // let the next function do this ... no spaghetti code ;-)
+ HandleTreeViewPopup2(wParam,lParam);
+ };
+ if (!apclrOut.empty())
+ {
+ aiColor4D clrOld = *((aiColor4D*)(apclrOut.front().pclrColor));
+
+ CHOOSECOLOR clr;
+ clr.lStructSize = sizeof(CHOOSECOLOR);
+ clr.hwndOwner = g_hDlg;
+ clr.Flags = CC_RGBINIT | CC_FULLOPEN;
+ clr.rgbResult = RGB(
+ clamp<unsigned char>(clrOld.r * 255.0f),
+ clamp<unsigned char>(clrOld.g * 255.0f),
+ clamp<unsigned char>(clrOld.b * 255.0f));
+ clr.lpCustColors = g_aclCustomColors;
+ clr.lpfnHook = nullptr;
+ clr.lpTemplateName = nullptr;
+ clr.lCustData = 0;
+
+ ChooseColor(&clr);
+
+ clrOld.r = (float)(((unsigned int)clr.rgbResult) & 0xFF) / 255.0f;
+ clrOld.g = (float)(((unsigned int)clr.rgbResult >> 8) & 0xFF) / 255.0f;
+ clrOld.b = (float)(((unsigned int)clr.rgbResult >> 16) & 0xFF) / 255.0f;
+
+ // update the color values in the mesh instances and
+ // update all shaders ...
+ for (std::vector<Info>::iterator
+ i = apclrOut.begin();
+ i != apclrOut.end();++i)
+ {
+ *((*i).pclrColor) = *((D3DXVECTOR4*)&clrOld);
+ if (!(*i).pMesh->bSharedFX)
+ {
+ (*i).pMesh->piEffect->SetVector((*i).szShaderParam,(*i).pclrColor);
+ }
+ }
+
+ // change the material key ...
+ aiMaterial* pcMat = (aiMaterial*)g_pcAsset->pcScene->mMaterials[
+ this->m_pcCurrentMaterial->iIndex];
+ pcMat->AddProperty<aiColor4D>(&clrOld,1,szMatKey,0,0);
+
+ if (ID_SOLONG_CLEARSPECULARCOLOR == LOWORD(wParam) &&
+ aiShadingMode_Gouraud == apclrOut.front().pMesh->eShadingMode)
+ {
+ CLogDisplay::Instance().AddEntry("[INFO] You have just changed the specular "
+ "material color",D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ CLogDisplay::Instance().AddEntry(
+ "This is great, especially since there is currently no specular shading",
+ D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ }
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CALLBACK TreeViewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ if (lParamSort == lParam1)return -1;
+ if (lParamSort == lParam2)return 1;
+ return 0;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::HandleTreeViewPopup2(WPARAM wParam,LPARAM /*lParam*/)
+{
+ char szFileName[MAX_PATH];
+ DWORD dwTemp = MAX_PATH;
+
+ switch (LOWORD(wParam))
+ {
+ case ID_HEY_REPLACE:
+ {
+ // get a path to a new texture
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"ReplaceTextureSrc",nullptr,nullptr,
+ (BYTE*)szFileName,&dwTemp))
+ {
+ // Key was not found. Use C:
+ strcpy(szFileName,"");
+ }
+ else
+ {
+ // need to remove the file name
+ char* sz = strrchr(szFileName,'\\');
+ if (!sz)
+ sz = strrchr(szFileName,'/');
+ if (sz)
+ *sz = 0;
+ }
+ OPENFILENAME sFilename1 = {
+ sizeof(OPENFILENAME),
+ g_hDlg,GetModuleHandle(nullptr),
+ "Textures\0*.png;*.dds;*.tga;*.bmp;*.tif;*.ppm;*.ppx;*.jpg;*.jpeg;*.exr\0*.*\0",
+ nullptr, 0, 1,
+ szFileName, MAX_PATH, nullptr, 0, nullptr,
+ "Replace this texture",
+ OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
+ 0, 1, ".jpg", 0, nullptr, nullptr
+ };
+ if(GetOpenFileName(&sFilename1) == 0) return 0;
+
+ // Now store the file in the registry
+ RegSetValueExA(g_hRegistry,"ReplaceTextureSrc",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+ this->ReplaceCurrentTexture(szFileName);
+ }
+ return 1;
+
+ case ID_HEY_EXPORT:
+ {
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"TextureExportDest",nullptr,nullptr,
+ (BYTE*)szFileName,&dwTemp))
+ {
+ // Key was not found. Use C:
+ strcpy(szFileName,"");
+ }
+ else
+ {
+ // need to remove the file name
+ char* sz = strrchr(szFileName,'\\');
+ if (!sz)
+ sz = strrchr(szFileName,'/');
+ if (sz)
+ *sz = 0;
+ }
+ OPENFILENAME sFilename1 = {
+ sizeof(OPENFILENAME),
+ g_hDlg,GetModuleHandle(nullptr),
+ "Textures\0*.png;*.dds;*.bmp;*.tif;*.pfm;*.jpg;*.jpeg;*.hdr\0*.*\0", nullptr, 0, 1,
+ szFileName, MAX_PATH, nullptr, 0, nullptr,
+ "Export texture to file",
+ OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
+ 0, 1, ".png", 0, nullptr, nullptr
+ };
+ if(GetSaveFileName(&sFilename1) == 0) return 0;
+
+ // Now store the file in the registry
+ RegSetValueExA(g_hRegistry,"TextureExportDest",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+
+ // determine the file format ...
+ D3DXIMAGE_FILEFORMAT eFormat = D3DXIFF_PNG;
+ const char* sz = strrchr(szFileName,'.');
+ if (sz)
+ {
+ ++sz;
+ if (0 == Assimp::ASSIMP_stricmp(sz,"pfm"))eFormat = D3DXIFF_PFM;
+ else if (0 == Assimp::ASSIMP_stricmp(sz,"dds"))eFormat = D3DXIFF_DDS;
+ else if (0 == Assimp::ASSIMP_stricmp(sz,"jpg"))eFormat = D3DXIFF_JPG;
+ else if (0 == Assimp::ASSIMP_stricmp(sz,"jpeg"))eFormat = D3DXIFF_JPG;
+ else if (0 == Assimp::ASSIMP_stricmp(sz,"hdr"))eFormat = D3DXIFF_HDR;
+ else if (0 == Assimp::ASSIMP_stricmp(sz,"bmp"))eFormat = D3DXIFF_BMP;
+ }
+
+ // get a pointer to the first surface of the current texture
+ IDirect3DSurface9* pi = nullptr;
+ (*this->m_pcCurrentTexture->piTexture)->GetSurfaceLevel(0,&pi);
+ if(!pi || FAILED(D3DXSaveSurfaceToFile(szFileName,eFormat,pi,nullptr,nullptr)))
+ {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to export texture",
+ D3DCOLOR_ARGB(0xFF,0xFF,0,0));
+ }
+ else
+ {
+ CLogDisplay::Instance().AddEntry("[INFO] The texture has been exported",
+ D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ }
+ if(pi)pi->Release();
+ }
+ return 1;
+
+ case ID_HEY_REMOVE:
+ {
+
+ if(IDYES != MessageBox(g_hDlg,"To recover the texture you need to reload the model. Do you wish to continue?",
+ "Remove texture",MB_YESNO)) {
+ return 1;
+ }
+
+ aiMaterial* pcMat = (aiMaterial*)g_pcAsset->pcScene->mMaterials[
+ m_pcCurrentTexture->iMatIndex];
+
+ unsigned int s;
+ if (m_pcCurrentTexture->iType == (aiTextureType_OPACITY | 0x40000000))
+ {
+ // set a special property to indicate that no alpha channel is required
+ int iVal = 1;
+ pcMat->AddProperty<int>(&iVal,1,"no_a_from_d",0,0);
+ s = aiTextureType_OPACITY;
+ }
+ else s = m_pcCurrentTexture->iType;
+ pcMat->RemoveProperty(AI_MATKEY_TEXTURE(m_pcCurrentTexture->iType,0));
+
+ // need to update all meshes associated with this material
+ for (unsigned int i = 0;i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (m_pcCurrentTexture->iMatIndex == g_pcAsset->pcScene->mMeshes[i]->mMaterialIndex)
+ {
+ CMaterialManager::Instance().DeleteMaterial(g_pcAsset->apcMeshes[i]);
+ CMaterialManager::Instance().CreateMaterial(g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]);
+ }
+ }
+ // find the corresponding MaterialInfo structure
+ const unsigned int iMatIndex = m_pcCurrentTexture->iMatIndex;
+ for (std::vector<MaterialInfo>::iterator
+ a = m_asMaterials.begin();
+ a != m_asMaterials.end();++a)
+ {
+ if (iMatIndex == (*a).iIndex)
+ {
+ // good news. we will also need to find all other textures
+ // associated with this item ...
+ for (std::vector<TextureInfo>::iterator
+ n = m_asTextures.begin();
+ n != m_asTextures.end();++n)
+ {
+ if ((*n).iMatIndex == iMatIndex)
+ {
+ n = m_asTextures.erase(n);
+ if (m_asTextures.end() == n)break;
+ }
+ }
+ // delete this material from all lists ...
+ TreeView_DeleteItem(GetDlgItem(g_hDlg,IDC_TREE1),(*a).hTreeItem);
+ this->m_asMaterials.erase(a);
+ break;
+ }
+ }
+
+ // add the new material to the list and make sure it will be fully expanded
+ AddMaterialToDisplayList(m_hRoot,iMatIndex);
+ HTREEITEM hNewItem = m_asMaterials.back().hTreeItem;
+ TreeView_Expand(GetDlgItem(g_hDlg,IDC_TREE1),hNewItem,TVE_EXPAND);
+
+ // we need to sort the list, materials come first, then nodes
+ TVSORTCB sSort;
+ sSort.hParent = m_hRoot;
+ sSort.lParam = 10;
+ sSort.lpfnCompare = &TreeViewCompareFunc;
+ TreeView_SortChildrenCB(GetDlgItem(g_hDlg,IDC_TREE1),&sSort,0);
+
+ // the texture was selected, but the silly user has just deleted it
+ // ... go back to normal viewing mode
+ TreeView_Select(GetDlgItem(g_hDlg,IDC_TREE1),m_hRoot,TVGN_CARET);
+ return 1;
+ }
+ }
+ return 0;
+}
+//-------------------------------------------------------------------------------
+// Setup stereo view
+int CDisplay::SetupStereoView()
+{
+ if (nullptr != g_pcAsset && nullptr != g_pcAsset->pcScene->mRootNode)
+ {
+ // enable the RED, GREEN and ALPHA channels
+ g_piDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
+ D3DCOLORWRITEENABLE_RED |
+ D3DCOLORWRITEENABLE_ALPHA |
+ D3DCOLORWRITEENABLE_GREEN);
+
+ // move the camera a little bit to the left
+ g_sCamera.vPos -= g_sCamera.vRight * 0.03f;
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Do the actual rendering pass for the stereo view
+int CDisplay::RenderStereoView(const aiMatrix4x4& m)
+{
+ // and rerender the scene
+ if (nullptr != g_pcAsset && nullptr != g_pcAsset->pcScene->mRootNode)
+ {
+ // enable the BLUE, GREEN and ALPHA channels
+ g_piDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
+ D3DCOLORWRITEENABLE_GREEN |
+ D3DCOLORWRITEENABLE_ALPHA |
+ D3DCOLORWRITEENABLE_BLUE);
+
+ // clear the z-buffer
+ g_piDevice->Clear(0,nullptr,D3DCLEAR_ZBUFFER,0,1.0f,0);
+
+ // move the camera a little bit to the right
+ g_sCamera.vPos += g_sCamera.vRight * 0.06f;
+
+ RenderNode(g_pcAsset->pcScene->mRootNode,m,false);
+ g_piDevice->SetRenderState(D3DRS_ZWRITEENABLE,FALSE);
+ RenderNode(g_pcAsset->pcScene->mRootNode,m,true);
+ g_piDevice->SetRenderState(D3DRS_ZWRITEENABLE,TRUE);
+
+ // (move back to the original position)
+ g_sCamera.vPos -= g_sCamera.vRight * 0.03f;
+
+ // re-enable all channels
+ g_piDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
+ D3DCOLORWRITEENABLE_RED |
+ D3DCOLORWRITEENABLE_GREEN |
+ D3DCOLORWRITEENABLE_ALPHA |
+ D3DCOLORWRITEENABLE_BLUE);
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Process input for the texture view
+int CDisplay::HandleInputTextureView()
+{
+ HandleMouseInputTextureView();
+ HandleKeyboardInputTextureView();
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Get input for the current state
+int CDisplay::HandleInput()
+{
+ if(CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
+ HandleMouseInputSkyBox();
+
+ // handle input commands
+ HandleMouseInputLightRotate();
+ HandleMouseInputLightIntensityAndColor();
+ if(g_bFPSView)
+ {
+ HandleMouseInputFPS();
+ HandleKeyboardInputFPS();
+ }
+ else HandleMouseInputLocal();
+
+ // compute auto rotation depending on the time which has passed
+ if (g_sOptions.bRotate)
+ {
+ aiMatrix4x4 mMat;
+ D3DXMatrixRotationYawPitchRoll((D3DXMATRIX*)&mMat,
+ g_vRotateSpeed.x * g_fElpasedTime,
+ g_vRotateSpeed.y * g_fElpasedTime,
+ g_vRotateSpeed.z * g_fElpasedTime);
+ g_mWorldRotate = g_mWorldRotate * mMat;
+ }
+
+ // Handle rotations of light source(s)
+ if (g_sOptions.bLightRotate)
+ {
+ aiMatrix4x4 mMat;
+ D3DXMatrixRotationYawPitchRoll((D3DXMATRIX*)&mMat,
+ g_vRotateSpeed.x * g_fElpasedTime * 0.5f,
+ g_vRotateSpeed.y * g_fElpasedTime * 0.5f,
+ g_vRotateSpeed.z * g_fElpasedTime * 0.5f);
+
+ D3DXVec3TransformNormal((D3DXVECTOR3*)&g_avLightDirs[0],
+ (D3DXVECTOR3*)&g_avLightDirs[0],(D3DXMATRIX*)&mMat);
+
+ g_avLightDirs[0].Normalize();
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Process input for an empty scene view to allow for sky-box rotations
+int CDisplay::HandleInputEmptyScene()
+{
+ if(CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
+ {
+ if (g_bFPSView)
+ {
+ HandleMouseInputFPS();
+ HandleKeyboardInputFPS();
+ }
+ HandleMouseInputSkyBox();
+
+ // need to store the last mouse position in the global variable
+ // HandleMouseInputFPS() is doing this internally
+ if (!g_bFPSView)
+ {
+ g_LastmousePos.x = g_mousePos.x;
+ g_LastmousePos.y = g_mousePos.y;
+ }
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Draw the HUD on top of the scene
+int CDisplay::DrawHUD()
+{
+ // HACK: (thom) can't get the effect to work on non-shader cards, therefore deactivated for the moment
+ if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
+ return 1;
+
+ // get the dimension of the back buffer
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ // commit the texture to the shader
+ // FIX: Necessary because the texture view is also using this shader
+ g_piPassThroughEffect->SetTexture("TEXTURE_2D",g_pcTexture);
+
+ // NOTE: The shader might be used for other purposes, too.
+ // So ensure the right technique is there
+ if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
+ g_piPassThroughEffect->SetTechnique( "PassThrough_FF");
+ else
+ g_piPassThroughEffect->SetTechnique("PassThrough");
+
+ // build vertices for drawing from system memory
+ UINT dw;
+ g_piPassThroughEffect->Begin(&dw,0);
+ g_piPassThroughEffect->BeginPass(0);
+
+ D3DSURFACE_DESC sDesc;
+ g_pcTexture->GetLevelDesc(0,&sDesc);
+ SVertex as[4];
+ float fHalfX = ((float)sRect.right-(float)sDesc.Width) / 2.0f;
+ float fHalfY = ((float)sRect.bottom-(float)sDesc.Height) / 2.0f;
+ as[1].x = fHalfX;
+ as[1].y = fHalfY;
+ as[1].z = 0.2f;
+ as[1].w = 1.0f;
+ as[1].u = 0.0f;
+ as[1].v = 0.0f;
+
+ as[3].x = (float)sRect.right-fHalfX;
+ as[3].y = fHalfY;
+ as[3].z = 0.2f;
+ as[3].w = 1.0f;
+ as[3].u = 1.0f;
+ as[3].v = 0.0f;
+
+ as[0].x = fHalfX;
+ as[0].y = (float)sRect.bottom-fHalfY;
+ as[0].z = 0.2f;
+ as[0].w = 1.0f;
+ as[0].u = 0.0f;
+ as[0].v = 1.0f;
+
+ as[2].x = (float)sRect.right-fHalfX;
+ as[2].y = (float)sRect.bottom-fHalfY;
+ as[2].z = 0.2f;
+ as[2].w = 1.0f;
+ as[2].u = 1.0f;
+ as[2].v = 1.0f;
+
+ as[0].x -= 0.5f;as[1].x -= 0.5f;as[2].x -= 0.5f;as[3].x -= 0.5f;
+ as[0].y -= 0.5f;as[1].y -= 0.5f;as[2].y -= 0.5f;as[3].y -= 0.5f;
+
+ g_piDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
+ g_piDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
+
+ // draw the screen-filling squad
+ DWORD dw2;g_piDevice->GetFVF(&dw2);
+ g_piDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
+ g_piDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,
+ &as,sizeof(SVertex));
+
+ // end the effect and recover the old vertex format
+ g_piPassThroughEffect->EndPass();
+ g_piPassThroughEffect->End();
+
+ g_piDevice->SetFVF(dw2);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Render the full scene, all nodes
+int CDisplay::RenderFullScene()
+{
+ // reset the color index used for drawing normals
+ g_iCurrentColor = 0;
+
+ aiMatrix4x4 pcProj;
+ GetProjectionMatrix(pcProj);
+
+ vPos = GetCameraMatrix(mViewProjection);
+ mViewProjection = mViewProjection * pcProj;
+
+ // setup wireframe/solid rendering mode
+ if (g_sOptions.eDrawMode == RenderOptions::WIREFRAME)
+ g_piDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
+ else g_piDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID);
+
+ if (g_sOptions.bCulling)
+ g_piDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
+ else g_piDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
+
+ // for high-quality mode, enable anisotropic texture filtering
+ if (g_sOptions.bLowQuality) {
+ for (DWORD d = 0; d < 8;++d) {
+ g_piDevice->SetSamplerState(d,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
+ g_piDevice->SetSamplerState(d,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
+ g_piDevice->SetSamplerState(d,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR);
+ }
+ }
+ else {
+ for (DWORD d = 0; d < 8;++d) {
+ g_piDevice->SetSamplerState(d,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
+ g_piDevice->SetSamplerState(d,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
+ g_piDevice->SetSamplerState(d,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR);
+
+ g_piDevice->SetSamplerState(d,D3DSAMP_MAXANISOTROPY,g_sCaps.MaxAnisotropy);
+ }
+ }
+
+ // draw the scene background (clear and texture 2d)
+ CBackgroundPainter::Instance().OnPreRender();
+
+ // setup the stereo view if necessary
+ if (g_sOptions.bStereoView)
+ SetupStereoView();
+
+
+ // draw all opaque objects in the scene
+ aiMatrix4x4 m;
+ if (nullptr != g_pcAsset && nullptr != g_pcAsset->pcScene->mRootNode)
+ {
+ HandleInput();
+ m = g_mWorld * g_mWorldRotate;
+ RenderNode(g_pcAsset->pcScene->mRootNode,m,false);
+ }
+
+ // if a cube texture is loaded as background image, the user
+ // should be able to rotate it even if no asset is loaded
+ HandleInputEmptyScene();
+
+ // draw the scene background
+ CBackgroundPainter::Instance().OnPostRender();
+
+ // draw all non-opaque objects in the scene
+ if (nullptr != g_pcAsset && nullptr != g_pcAsset->pcScene->mRootNode)
+ {
+ // disable the z-buffer
+ if (!g_sOptions.bNoAlphaBlending) {
+ g_piDevice->SetRenderState(D3DRS_ZWRITEENABLE,FALSE);
+ }
+ RenderNode(g_pcAsset->pcScene->mRootNode,m,true);
+
+ if (!g_sOptions.bNoAlphaBlending) {
+ g_piDevice->SetRenderState(D3DRS_ZWRITEENABLE,TRUE);
+ }
+ }
+
+ // setup the stereo view if necessary
+ if (g_sOptions.bStereoView)
+ RenderStereoView(m);
+
+ // render the skeleton if necessary
+ if (g_sOptions.bSkeleton && nullptr != g_pcAsset && nullptr != g_pcAsset->pcScene->mRootNode) {
+ // disable the z-buffer
+ g_piDevice->SetRenderState(D3DRS_ZWRITEENABLE,FALSE);
+
+ if (g_sOptions.eDrawMode != RenderOptions::WIREFRAME) {
+ g_piDevice->SetRenderState(D3DRS_ZENABLE,FALSE);
+ }
+
+ g_piDevice->SetVertexDeclaration( gDefaultVertexDecl);
+ // this is very similar to the code in SetupMaterial()
+ ID3DXEffect* piEnd = g_piNormalsEffect;
+ aiMatrix4x4 pcProj2 = m * mViewProjection;
+
+ D3DXVECTOR4 vVector(1.f,0.f,0.f,1.f);
+ piEnd->SetVector("OUTPUT_COLOR",&vVector);
+ piEnd->SetMatrix("WorldViewProjection", (const D3DXMATRIX*)&pcProj2);
+
+ UINT dwPasses = 0;
+ piEnd->Begin(&dwPasses,0);
+ piEnd->BeginPass(0);
+
+ RenderSkeleton(g_pcAsset->pcScene->mRootNode,m,m);
+
+ piEnd->EndPass();piEnd->End();
+ g_piDevice->SetRenderState(D3DRS_ZWRITEENABLE,TRUE);
+ g_piDevice->SetRenderState(D3DRS_ZENABLE,TRUE);
+ }
+
+ // draw the HUD texture on top of the rendered scene using
+ // pre-projected vertices
+ if (!g_bFPSView && g_pcAsset && g_pcTexture)
+ DrawHUD();
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::RenderMaterialView()
+{
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Render animation skeleton
+int CDisplay::RenderSkeleton (aiNode* piNode,const aiMatrix4x4& piMatrix, const aiMatrix4x4& parent)
+{
+ aiMatrix4x4 me = g_pcAsset->mAnimator->GetGlobalTransform( piNode);
+
+ me.Transpose();
+ //me *= piMatrix;
+
+ if (piNode->mParent) {
+ AssetHelper::LineVertex data[2];
+ data[0].dColorDiffuse = data[1].dColorDiffuse = D3DCOLOR_ARGB(0xff,0xff,0,0);
+
+ data[0].vPosition.x = parent.d1;
+ data[0].vPosition.y = parent.d2;
+ data[0].vPosition.z = parent.d3;
+
+ data[1].vPosition.x = me.d1;
+ data[1].vPosition.y = me.d2;
+ data[1].vPosition.z = me.d3;
+
+ g_piDevice->DrawPrimitiveUP(D3DPT_LINELIST,1,&data,sizeof(AssetHelper::LineVertex));
+ }
+
+ // render all child nodes
+ for (unsigned int i = 0; i < piNode->mNumChildren;++i)
+ RenderSkeleton(piNode->mChildren[i],piMatrix, me );
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Render a single node
+int CDisplay::RenderNode (aiNode* piNode,const aiMatrix4x4& piMatrix,
+ bool bAlpha /*= false*/)
+{
+ aiMatrix4x4 aiMe = g_pcAsset->mAnimator->GetGlobalTransform( piNode);
+
+ aiMe.Transpose();
+ aiMe *= piMatrix;
+
+ bool bChangedVM = false;
+ if (VIEWMODE_NODE == m_iViewMode && m_pcCurrentNode)
+ {
+ if (piNode != m_pcCurrentNode->psNode)
+ {
+ // directly call our children
+ for (unsigned int i = 0; i < piNode->mNumChildren;++i)
+ RenderNode(piNode->mChildren[i],piMatrix,bAlpha );
+
+ return 1;
+ }
+ m_iViewMode = VIEWMODE_FULL;
+ bChangedVM = true;
+ }
+
+ aiMatrix4x4 pcProj = aiMe * mViewProjection;
+
+ aiMatrix4x4 pcCam = aiMe;
+ pcCam.Inverse().Transpose();
+
+ // VERY UNOPTIMIZED, much stuff is redundant. Who cares?
+ if (!g_sOptions.bRenderMats && !bAlpha)
+ {
+ // this is very similar to the code in SetupMaterial()
+ ID3DXEffect* piEnd = g_piDefaultEffect;
+
+ // commit transformation matrices to the shader
+ piEnd->SetMatrix("WorldViewProjection",
+ (const D3DXMATRIX*)&pcProj);
+
+ piEnd->SetMatrix("World",(const D3DXMATRIX*)&aiMe);
+ piEnd->SetMatrix("WorldInverseTranspose",
+ (const D3DXMATRIX*)&pcCam);
+
+ if ( CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
+ {
+ pcCam = pcCam * pcProj;
+ piEnd->SetMatrix("ViewProj",(const D3DXMATRIX*)&pcCam);
+ pcCam.Inverse();
+ piEnd->SetMatrix("InvViewProj",(const D3DXMATRIX*)&pcCam);
+ }
+
+ // commit light colors and direction to the shader
+ D3DXVECTOR4 apcVec[5];
+ apcVec[0].x = g_avLightDirs[0].x;
+ apcVec[0].y = g_avLightDirs[0].y;
+ apcVec[0].z = g_avLightDirs[0].z;
+ apcVec[0].w = 0.0f;
+ apcVec[1].x = g_avLightDirs[0].x * -1.0f;
+ apcVec[1].y = g_avLightDirs[0].y * -1.0f;
+ apcVec[1].z = g_avLightDirs[0].z * -1.0f;
+ apcVec[1].w = 0.0f;
+
+ D3DXVec4Normalize(&apcVec[0],&apcVec[0]);
+ D3DXVec4Normalize(&apcVec[1],&apcVec[1]);
+ piEnd->SetVectorArray("afLightDir",apcVec,5);
+
+ apcVec[0].x = ((g_avLightColors[0] >> 16) & 0xFF) / 255.0f;
+ apcVec[0].y = ((g_avLightColors[0] >> 8) & 0xFF) / 255.0f;
+ apcVec[0].z = ((g_avLightColors[0]) & 0xFF) / 255.0f;
+ apcVec[0].w = 1.0f;
+
+ if( g_sOptions.b3Lights)
+ {
+ apcVec[1].x = ((g_avLightColors[1] >> 16) & 0xFF) / 255.0f;
+ apcVec[1].y = ((g_avLightColors[1] >> 8) & 0xFF) / 255.0f;
+ apcVec[1].z = ((g_avLightColors[1]) & 0xFF) / 255.0f;
+ apcVec[1].w = 0.0f;
+ } else
+ {
+ apcVec[1].x = 0.0f;
+ apcVec[1].y = 0.0f;
+ apcVec[1].z = 0.0f;
+ apcVec[1].w = 0.0f;
+ }
+
+ apcVec[0] *= g_fLightIntensity;
+ apcVec[1] *= g_fLightIntensity;
+ piEnd->SetVectorArray("afLightColor",apcVec,5);
+
+ apcVec[0].x = vPos.x;
+ apcVec[0].y = vPos.y;
+ apcVec[0].z = vPos.z;
+ piEnd->SetVector( "vCameraPos",&apcVec[0]);
+
+ // setup the best technique
+ if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
+ {
+ g_piDefaultEffect->SetTechnique( "DefaultFXSpecular_FF");
+ } else
+ if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0) || g_sOptions.bLowQuality)
+ {
+ if (g_sOptions.b3Lights)
+ piEnd->SetTechnique("DefaultFXSpecular_PS20_D2");
+ else piEnd->SetTechnique("DefaultFXSpecular_PS20_D1");
+ }
+ else
+ {
+ if (g_sOptions.b3Lights)
+ piEnd->SetTechnique("DefaultFXSpecular_D2");
+ else piEnd->SetTechnique("DefaultFXSpecular_D1");
+ }
+
+ // setup the default material
+ UINT dwPasses = 0;
+ piEnd->Begin(&dwPasses,0);
+ piEnd->BeginPass(0);
+ }
+ D3DXVECTOR4 vVector = g_aclNormalColors[g_iCurrentColor];
+ if (++g_iCurrentColor == 14)
+ {
+ g_iCurrentColor = 0;
+ }
+ if (! (!g_sOptions.bRenderMats && bAlpha ))
+ {
+ for (unsigned int i = 0; i < piNode->mNumMeshes;++i)
+ {
+ const aiMesh* mesh = g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]];
+ AssetHelper::MeshHelper* helper = g_pcAsset->apcMeshes[piNode->mMeshes[i]];
+
+ // don't render the mesh if the render pass is incorrect
+ if (g_sOptions.bRenderMats && (helper->piOpacityTexture || helper->fOpacity != 1.0f) && !mesh->HasBones())
+ {
+ if (!bAlpha)continue;
+ }
+ else if (bAlpha)continue;
+
+ // Upload bone matrices. This maybe is the wrong place to do it, but for the heck of it I don't understand this code flow
+ if( mesh->HasBones())
+ {
+ if( helper->piEffect)
+ {
+ static float matrices[4*4*60];
+ float* tempmat = matrices;
+ const std::vector<aiMatrix4x4>& boneMats = g_pcAsset->mAnimator->GetBoneMatrices( piNode, i);
+ ai_assert( boneMats.size() == mesh->mNumBones);
+
+ for( unsigned int a = 0; a < mesh->mNumBones; a++)
+ {
+ const aiMatrix4x4& mat = boneMats[a];
+ *tempmat++ = mat.a1; *tempmat++ = mat.a2; *tempmat++ = mat.a3; *tempmat++ = mat.a4;
+ *tempmat++ = mat.b1; *tempmat++ = mat.b2; *tempmat++ = mat.b3; *tempmat++ = mat.b4;
+ *tempmat++ = mat.c1; *tempmat++ = mat.c2; *tempmat++ = mat.c3; *tempmat++ = mat.c4;
+ *tempmat++ = mat.d1; *tempmat++ = mat.d2; *tempmat++ = mat.d3; *tempmat++ = mat.d4;
+ //tempmat += 4;
+ }
+
+ if( g_sOptions.bRenderMats)
+ {
+ helper->piEffect->SetMatrixTransposeArray( "gBoneMatrix", (D3DXMATRIX*)matrices, 60);
+ } else
+ {
+ g_piDefaultEffect->SetMatrixTransposeArray( "gBoneMatrix", (D3DXMATRIX*)matrices, 60);
+ g_piDefaultEffect->CommitChanges();
+ }
+ }
+ } else
+ {
+ // upload identity matrices instead. Only the first is ever going to be used in meshes without bones
+ if( !g_sOptions.bRenderMats)
+ {
+ D3DXMATRIX identity( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ g_piDefaultEffect->SetMatrixTransposeArray( "gBoneMatrix", &identity, 1);
+ g_piDefaultEffect->CommitChanges();
+ }
+ }
+
+ // now setup the material
+ if (g_sOptions.bRenderMats)
+ {
+ CMaterialManager::Instance().SetupMaterial( helper, pcProj, aiMe, pcCam, vPos);
+ }
+ g_piDevice->SetVertexDeclaration( gDefaultVertexDecl);
+
+ if (g_sOptions.bNoAlphaBlending) {
+ // manually disable alpha-blending
+ g_piDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);
+ }
+
+ if (bAlpha)CMeshRenderer::Instance().DrawSorted(piNode->mMeshes[i],aiMe);
+ else CMeshRenderer::Instance().DrawUnsorted(piNode->mMeshes[i]);
+
+ // now end the material
+ if (g_sOptions.bRenderMats)
+ {
+ CMaterialManager::Instance().EndMaterial( helper);
+ }
+
+ // render normal vectors?
+ if (g_sOptions.bRenderNormals && helper->piVBNormals)
+ {
+ // this is very similar to the code in SetupMaterial()
+ ID3DXEffect* piEnd = g_piNormalsEffect;
+
+ piEnd->SetVector("OUTPUT_COLOR",&vVector);
+ piEnd->SetMatrix("WorldViewProjection", (const D3DXMATRIX*)&pcProj);
+
+ UINT dwPasses = 0;
+ piEnd->Begin(&dwPasses,0);
+ piEnd->BeginPass(0);
+
+ g_piDevice->SetStreamSource(0, helper->piVBNormals, 0, sizeof(AssetHelper::LineVertex));
+ g_piDevice->DrawPrimitive(D3DPT_LINELIST,0, g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]]->mNumVertices);
+
+ piEnd->EndPass();
+ piEnd->End();
+ }
+ }
+ // end the default material
+ if (!g_sOptions.bRenderMats)
+ {
+ g_piDefaultEffect->EndPass();
+ g_piDefaultEffect->End();
+ }
+ }
+ // render all child nodes
+ for (unsigned int i = 0; i < piNode->mNumChildren;++i)
+ RenderNode(piNode->mChildren[i],piMatrix,bAlpha );
+
+ // need to reset the viewmode?
+ if (bChangedVM)
+ m_iViewMode = VIEWMODE_NODE;
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::RenderPatternBG()
+{
+ if (!g_piPatternEffect)
+ {
+ // the pattern effect won't work on ps_2_0 cards
+ if (g_sCaps.PixelShaderVersion >= D3DPS_VERSION(3,0))
+ {
+ // seems we have not yet compiled this shader.
+ // and NOW is the best time to do that ...
+ ID3DXBuffer* piBuffer = nullptr;
+ if(FAILED( D3DXCreateEffect(g_piDevice,
+ g_szCheckerBackgroundShader.c_str(),
+ (UINT)g_szCheckerBackgroundShader.length(),
+ nullptr,
+ nullptr,
+ D3DXSHADER_USE_LEGACY_D3DX9_31_DLL,
+ nullptr,
+ &g_piPatternEffect,&piBuffer)))
+ {
+ if( piBuffer)
+ {
+ MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
+ piBuffer->Release();
+ }
+ return 0;
+ }
+ if( piBuffer)
+ {
+ piBuffer->Release();
+ piBuffer = nullptr;
+ }
+ }
+ else
+ {
+ // clear the color buffer in magenta
+ // (hopefully this is ugly enough that every ps_2_0 cards owner
+ // runs to the next shop to buy himself a new card ...)
+ g_piDevice->Clear(0,nullptr,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
+ D3DCOLOR_ARGB(0xFF,0xFF,0,0xFF), 1.0f,0 );
+ return 1;
+ }
+ }
+
+ // clear the depth buffer only
+ g_piDevice->Clear(0,nullptr,D3DCLEAR_ZBUFFER,
+ D3DCOLOR_ARGB(0xFF,0xFF,0,0xFF), 1.0f,0 );
+
+ // setup the colors to be used ...
+ g_piPatternEffect->SetVector("COLOR_ONE",&m_avCheckerColors[0]);
+ g_piPatternEffect->SetVector("COLOR_TWO",&m_avCheckerColors[1]);
+
+ // setup the shader
+ UINT dw;
+ g_piPatternEffect->Begin(&dw,0);
+ g_piPatternEffect->BeginPass(0);
+
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ struct SVertex
+ {
+ float x,y,z,w;
+ };
+ // build the screen-filling rectangle
+ SVertex as[4];
+ as[1].x = 0.0f;
+ as[1].y = 0.0f;
+ as[1].z = 0.2f;
+ as[3].x = (float)sRect.right;
+ as[3].y = 0.0f;
+ as[3].z = 0.2f;
+ as[0].x = 0.0f;
+ as[0].y = (float)sRect.bottom;
+ as[0].z = 0.2f;
+ as[2].x = (float)sRect.right;
+ as[2].y = (float)sRect.bottom;
+ as[2].z = 0.2f;
+
+ as[0].w = 1.0f;
+ as[1].w = 1.0f;
+ as[2].w = 1.0f;
+ as[3].w = 1.0f;
+
+ as[0].x -= 0.5f;as[1].x -= 0.5f;as[2].x -= 0.5f;as[3].x -= 0.5f;
+ as[0].y -= 0.5f;as[1].y -= 0.5f;as[2].y -= 0.5f;as[3].y -= 0.5f;
+
+ // draw the rectangle
+ DWORD dw2;g_piDevice->GetFVF(&dw2);
+ g_piDevice->SetFVF(D3DFVF_XYZRHW);
+ g_piDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,
+ &as,sizeof(SVertex));
+ g_piDevice->SetFVF(dw2);
+
+ // cleanup
+ g_piPatternEffect->EndPass();
+ g_piPatternEffect->End();
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CDisplay::RenderTextureView()
+{
+ if (!g_pcAsset || !g_pcAsset->pcScene)return 0;
+
+ // handle input
+ this->HandleInputTextureView();
+
+ // render the background
+ RenderPatternBG();
+
+ // it might be that there is no texture ...
+ if (!m_pcCurrentTexture->piTexture)
+ {
+ return 0;
+ }
+
+
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ // commit the texture to the shader
+ g_piPassThroughEffect->SetTexture("TEXTURE_2D",*m_pcCurrentTexture->piTexture);
+
+ if (aiTextureType_OPACITY == m_pcCurrentTexture->iType)
+ {
+ g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromR");
+ }
+ else if ((aiTextureType_OPACITY | 0x40000000) == m_pcCurrentTexture->iType)
+ {
+ g_piPassThroughEffect->SetTechnique("PassThroughAlphaFromA");
+ }
+ else if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
+ g_piPassThroughEffect->SetTechnique( "PassThrough_FF");
+ else
+ g_piPassThroughEffect->SetTechnique("PassThrough");
+
+ UINT dw;
+ g_piPassThroughEffect->Begin(&dw,0);
+ g_piPassThroughEffect->BeginPass(0);
+
+ if (aiTextureType_HEIGHT == m_pcCurrentTexture->iType ||
+ aiTextureType_NORMALS == m_pcCurrentTexture->iType || g_sOptions.bNoAlphaBlending)
+ {
+ // manually disable alpha blending
+ g_piDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);
+ }
+
+ // build a rectangle which centers the texture
+ // scaling is OK, but no stretching
+ D3DSURFACE_DESC sDesc;
+ if ( m_pcCurrentTexture->piTexture && *m_pcCurrentTexture->piTexture) { /* just a dirty fix */
+ (*m_pcCurrentTexture->piTexture)->GetLevelDesc(0,&sDesc);
+
+ struct SVertex{float x,y,z,w,u,v;};
+ SVertex as[4];
+
+ const float nx = (float)sRect.right;
+ const float ny = (float)sRect.bottom;
+ const float x = (float)sDesc.Width;
+ const float y = (float)sDesc.Height;
+ float f = std::min((nx-30) / x,(ny-30) / y) * (m_fTextureZoom/1000.0f);
+
+ float fHalfX = (nx - (f * x)) / 2.0f;
+ float fHalfY = (ny - (f * y)) / 2.0f;
+ as[1].x = fHalfX + m_vTextureOffset.x;
+ as[1].y = fHalfY + m_vTextureOffset.y;
+ as[1].z = 0.2f;
+ as[1].w = 1.0f;
+ as[1].u = 0.0f;
+ as[1].v = 0.0f;
+ as[3].x = nx-fHalfX + m_vTextureOffset.x;
+ as[3].y = fHalfY + m_vTextureOffset.y;
+ as[3].z = 0.2f;
+ as[3].w = 1.0f;
+ as[3].u = 1.0f;
+ as[3].v = 0.0f;
+ as[0].x = fHalfX + m_vTextureOffset.x;
+ as[0].y = ny-fHalfY + m_vTextureOffset.y;
+ as[0].z = 0.2f;
+ as[0].w = 1.0f;
+ as[0].u = 0.0f;
+ as[0].v = 1.0f;
+ as[2].x = nx-fHalfX + m_vTextureOffset.x;
+ as[2].y = ny-fHalfY + m_vTextureOffset.y;
+ as[2].z = 0.2f;
+ as[2].w = 1.0f;
+ as[2].u = 1.0f;
+ as[2].v = 1.0f;
+ as[0].x -= 0.5f;as[1].x -= 0.5f;as[2].x -= 0.5f;as[3].x -= 0.5f;
+ as[0].y -= 0.5f;as[1].y -= 0.5f;as[2].y -= 0.5f;as[3].y -= 0.5f;
+
+ // draw the rectangle
+ DWORD dw2;g_piDevice->GetFVF(&dw2);
+ g_piDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
+ g_piDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,
+ &as,sizeof(SVertex));
+ g_piDevice->SetFVF(dw2);
+ }
+
+ g_piPassThroughEffect->EndPass();
+ g_piPassThroughEffect->End();
+
+ // do we need to draw UV coordinates?
+ return 1;
+}
+
+}
+
diff --git a/libs/assimp/tools/assimp_view/Display.h b/libs/assimp/tools/assimp_view/Display.h
new file mode 100644
index 0000000..1ca29f4
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Display.h
@@ -0,0 +1,542 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_DISPLAY_H_INCLUDED)
+#define AV_DISPLAY_H_INCLUDE
+
+#include <windows.h>
+#include <shellapi.h>
+#include <commctrl.h>
+
+// see CDisplay::m_aiImageList
+#define AI_VIEW_IMGLIST_NODE 0x0
+#define AI_VIEW_IMGLIST_MATERIAL 0x1
+#define AI_VIEW_IMGLIST_TEXTURE 0x2
+#define AI_VIEW_IMGLIST_TEXTURE_INVALID 0x3
+#define AI_VIEW_IMGLIST_MODEL 0x4
+
+namespace AssimpView
+{
+
+ //-------------------------------------------------------------------------------
+ /* Corresponds to the "Display" combobox in the UI
+ */
+ //-------------------------------------------------------------------------------
+ class CDisplay
+ {
+ private:
+
+ // helper class
+ struct Info
+ {
+ Info( D3DXVECTOR4* p1,
+ AssetHelper::MeshHelper* p2,
+ const char* p3 )
+ : pclrColor( p1 ), pMesh( p2 ), szShaderParam( p3 ) {}
+
+ D3DXVECTOR4* pclrColor;
+ AssetHelper::MeshHelper* pMesh;
+ const char* szShaderParam;
+ };
+
+ // default constructor
+ CDisplay()
+ : m_iViewMode( VIEWMODE_FULL ),
+ m_pcCurrentTexture( NULL ),
+ m_pcCurrentNode( NULL ),
+ m_pcCurrentMaterial( NULL ),
+ m_hImageList( NULL ),
+ m_hRoot( NULL ),
+ m_fTextureZoom( 1000.0f )
+ {
+ this->m_aiImageList[ 0 ] = 0;
+ this->m_aiImageList[ 1 ] = 1;
+ this->m_aiImageList[ 2 ] = 2;
+ this->m_aiImageList[ 3 ] = 3;
+ this->m_aiImageList[ 4 ] = 4;
+
+ this->m_avCheckerColors[ 0 ].x = this->m_avCheckerColors[ 0 ].y = this->m_avCheckerColors[ 0 ].z = 0.4f;
+ this->m_avCheckerColors[ 1 ].x = this->m_avCheckerColors[ 1 ].y = this->m_avCheckerColors[ 1 ].z = 0.6f;
+ }
+
+ public:
+
+
+ //------------------------------------------------------------------
+ enum
+ {
+ // the full model is displayed
+ VIEWMODE_FULL,
+
+ // a material is displayed on a simple spjere as model
+ VIEWMODE_MATERIAL,
+
+ // a texture with an UV set mapped on it is displayed
+ VIEWMODE_TEXTURE,
+
+ // a single node in the scenegraph is displayed
+ VIEWMODE_NODE,
+ };
+
+
+ //------------------------------------------------------------------
+ // represents a texture in the tree view
+ struct TextureInfo
+ {
+ // texture info
+ IDirect3DTexture9** piTexture;
+
+ // Blend factor of the texture
+ float fBlend;
+
+ // blend operation for the texture
+ aiTextureOp eOp;
+
+ // UV index for the texture
+ unsigned int iUV;
+
+ // Associated tree item
+ HTREEITEM hTreeItem;
+
+ // Original path to the texture
+ std::string szPath;
+
+ // index of the corresponding material
+ unsigned int iMatIndex;
+
+ // type of the texture
+ unsigned int iType;
+ };
+
+ //------------------------------------------------------------------
+ // represents a node in the tree view
+ struct NodeInfo
+ {
+ // node object
+ aiNode* psNode;
+
+ // corresponding tree view item
+ HTREEITEM hTreeItem;
+ };
+
+ //------------------------------------------------------------------
+ // represents a mesh in the tree view
+ struct MeshInfo
+ {
+ // the mesh object
+ aiMesh* psMesh;
+
+ // corresponding tree view item
+ HTREEITEM hTreeItem;
+ };
+
+ //------------------------------------------------------------------
+ // represents a material in the tree view
+ struct MaterialInfo
+ {
+ // material index
+ unsigned int iIndex;
+
+ // material object
+ aiMaterial* psMaterial;
+
+ // ID3DXEffect interface
+ ID3DXEffect* piEffect;
+
+ // corresponding tree view item
+ HTREEITEM hTreeItem;
+ };
+
+ //------------------------------------------------------------------
+ // Singleton accessors
+ static CDisplay s_cInstance;
+ inline static CDisplay& Instance()
+ {
+ return s_cInstance;
+ }
+
+
+ //------------------------------------------------------------------
+ // Called during the render loop. Renders the scene (including the
+ // HUD etc) in the current view mode
+ int OnRender();
+
+ //------------------------------------------------------------------
+ // called when the user selects another item in the "Display" tree
+ // view the method determines the new view mode and performs all
+ // required operations
+ // \param p_hTreeItem Selected tree view item
+ int OnSetup( HTREEITEM p_hTreeItem );
+
+ //------------------------------------------------------------------
+ // Variant 1: Render the full scene with the asset
+ int RenderFullScene();
+
+#if 0
+ //------------------------------------------------------------------
+ // Variant 2: Render only a part of the scene. One node to
+ // be exact
+ int RenderScenePart();
+#endif
+
+ //------------------------------------------------------------------
+ // Variant 3: Render a large sphere and map a given material on it
+ int RenderMaterialView();
+
+ //------------------------------------------------------------------
+ // Variant 4: Render a flat plane, map a texture on it and
+ // display the UV wire on it
+ int RenderTextureView();
+
+ //------------------------------------------------------------------
+ // Fill the UI combobox with a list of all supported view modi
+ //
+ // The display modes are added in order
+ int FillDisplayList( void );
+
+ //------------------------------------------------------------------
+ // Add a material and all sub textures to the display mode list
+ // hRoot - Handle to the root of the tree view
+ // iIndex - Material index
+ int AddMaterialToDisplayList( HTREEITEM hRoot,
+ unsigned int iIndex );
+
+ //------------------------------------------------------------------
+ // Add a texture to the display list
+ // pcMat - material containing the texture
+ // hTexture - Handle to the material tree item
+ // szPath - Path to the texture
+ // iUVIndex - UV index to be used for the texture
+ // fBlendFactor - Blend factor to be used for the texture
+ // eTextureOp - texture operation to be used for the texture
+ int AddTextureToDisplayList( unsigned int iType,
+ unsigned int iIndex,
+ const aiString* szPath,
+ HTREEITEM hFX,
+ unsigned int iUVIndex = 0,
+ const float fBlendFactor = 0.0f,
+ aiTextureOp eTextureOp = aiTextureOp_Multiply,
+ unsigned int iMesh = 0 );
+
+ //------------------------------------------------------------------
+ // Add a node to the display list
+ // Recusrivly adds all subnodes as well
+ // iIndex - Index of the node in the parent's child list
+ // iDepth - Current depth of the node
+ // pcNode - Node object
+ // hRoot - Parent tree view node
+ int AddNodeToDisplayList(
+ unsigned int iIndex,
+ unsigned int iDepth,
+ aiNode* pcNode,
+ HTREEITEM hRoot );
+
+ //------------------------------------------------------------------
+ // Add a mesh to the display list
+ // iIndex - Index of the mesh in the scene's mesh list
+ // hRoot - Parent tree view node
+ int AddMeshToDisplayList(
+ unsigned int iIndex,
+ HTREEITEM hRoot );
+
+ //------------------------------------------------------------------
+ // Load the image list for the tree view item
+ int LoadImageList( void );
+
+ //------------------------------------------------------------------
+ // Expand all nodes in the tree
+ int ExpandTree();
+
+ //------------------------------------------------------------------
+ // Fill the UI combobox with a list of all supported animations
+ // The animations are added in order
+ int FillAnimList( void );
+
+ //------------------------------------------------------------------
+ // Clear the combox box containing the list of animations
+ int ClearAnimList( void );
+
+ //------------------------------------------------------------------
+ // Clear the combox box containing the list of scenegraph items
+ int ClearDisplayList( void );
+
+ //------------------------------------------------------------------
+ // Fill in the default statistics
+ int FillDefaultStatistics( void );
+
+ //------------------------------------------------------------------
+ // Called by LoadAsset()
+ // reset the class instance to the default values
+ int Reset( void );
+
+ //------------------------------------------------------------------
+ // Replace the texture that is current selected with
+ // a new texture
+ int ReplaceCurrentTexture( const char* szPath );
+
+ //------------------------------------------------------------------
+ // Display the context menu (if there) for the specified tree item
+ // hItem Valid tree view item handle
+ int ShowTreeViewContextMenu( HTREEITEM hItem );
+
+ //------------------------------------------------------------------
+ // Event handling for pop-up menus displayed by th tree view
+ int HandleTreeViewPopup( WPARAM wParam, LPARAM lParam );
+
+ //------------------------------------------------------------------
+ // Enable animation-related parts of the UI
+ int EnableAnimTools( BOOL hm );
+
+ //------------------------------------------------------------------
+ // setter for m_iViewMode
+ inline void SetViewMode( unsigned int p_iNew )
+ {
+ this->m_iViewMode = p_iNew;
+ }
+
+ //------------------------------------------------------------------
+ // getter for m_iViewMode
+ inline unsigned int GetViewMode()
+ {
+ return m_iViewMode;
+ }
+
+ //------------------------------------------------------------------
+ // change the texture view's zoom factor
+ inline void SetTextureViewZoom( float f )
+ {
+ // FIX: Removed log(), seems to make more problems than it fixes
+ this->m_fTextureZoom += f * 15;
+ if( this->m_fTextureZoom < 0.05f )this->m_fTextureZoom = 0.05f;
+ }
+
+ //------------------------------------------------------------------
+ // change the texture view's offset on the x axis
+ inline void SetTextureViewOffsetX( float f )
+ {
+ this->m_vTextureOffset.x += f;
+ }
+
+ //------------------------------------------------------------------
+ // change the texture view's offset on the y axis
+ inline void SetTextureViewOffsetY( float f )
+ {
+ this->m_vTextureOffset.y += f;
+ }
+
+ //------------------------------------------------------------------
+ // add a new texture to the list
+ inline void AddTexture( const TextureInfo& info )
+ {
+ this->m_asTextures.push_back( info );
+ }
+
+ //------------------------------------------------------------------
+ // add a new node to the list
+ inline void AddNode( const NodeInfo& info )
+ {
+ this->m_asNodes.push_back( info );
+ }
+
+ //------------------------------------------------------------------
+ // add a new mesh to the list
+ inline void AddMesh( const MeshInfo& info )
+ {
+ this->m_asMeshes.push_back( info );
+ }
+
+ //------------------------------------------------------------------
+ // add a new material to the list
+ inline void AddMaterial( const MaterialInfo& info )
+ {
+ this->m_asMaterials.push_back( info );
+ }
+
+ //------------------------------------------------------------------
+ // set the primary color of the checker pattern background
+ inline void SetFirstCheckerColor( D3DXVECTOR4 c )
+ {
+ this->m_avCheckerColors[ 0 ] = c;
+ }
+
+ //------------------------------------------------------------------
+ // set the secondary color of the checker pattern background
+ inline void SetSecondCheckerColor( D3DXVECTOR4 c )
+ {
+ this->m_avCheckerColors[ 1 ] = c;
+ }
+
+ //------------------------------------------------------------------
+ // get the primary color of the checker pattern background
+ inline const D3DXVECTOR4* GetFirstCheckerColor() const
+ {
+ return &this->m_avCheckerColors[ 0 ];
+ }
+
+ //------------------------------------------------------------------
+ // get the secondary color of the checker pattern background
+ inline const D3DXVECTOR4* GetSecondCheckerColor() const
+ {
+ return &this->m_avCheckerColors[ 1 ];
+ }
+
+ private:
+
+ //------------------------------------------------------------------
+ // Render a screen-filling square using the checker pattern shader
+ int RenderPatternBG();
+
+ //------------------------------------------------------------------
+ // Render a given node in the scenegraph
+ // piNode Node to be rendered
+ // piMatrix Current transformation matrix
+ // bAlpha Render alpha or opaque objects only?
+ int RenderNode( aiNode* piNode, const aiMatrix4x4& piMatrix,
+ bool bAlpha = false );
+
+ //------------------------------------------------------------------
+ // Setup the camera for the stereo view rendering mode
+ int SetupStereoView();
+
+ //------------------------------------------------------------------
+ // Render the second view (for the right eye) in stereo mod
+ // m - World matrix
+ int RenderStereoView( const aiMatrix4x4& m );
+
+ //------------------------------------------------------------------
+ // Handle user input
+ int HandleInput();
+
+ //------------------------------------------------------------------
+ // Handle user input for the texture viewer
+ int HandleInputTextureView();
+
+ //------------------------------------------------------------------
+ // Handle user input if no asset is loaded
+ int HandleInputEmptyScene();
+
+ //------------------------------------------------------------------
+ // Draw the HUD (call only if FPS mode isn't active)
+ int DrawHUD();
+
+ //------------------------------------------------------------------
+ // Used by OnSetup().
+ // Do everything necessary to switch to texture view mode
+ int OnSetupTextureView( TextureInfo* pcNew );
+
+ //------------------------------------------------------------------
+ // Used by OnSetup().
+ // Do everything necessary to switch to material view mode
+ int OnSetupMaterialView( MaterialInfo* pcNew );
+
+ //------------------------------------------------------------------
+ // Used by OnSetup().
+ // Do everything necessary to switch to node view mode
+ int OnSetupNodeView( NodeInfo* pcNew );
+
+ //------------------------------------------------------------------
+ // Used by OnSetup().
+ // Do everything necessary to switch back to normal view mode
+ int OnSetupNormalView();
+
+ //------------------------------------------------------------------
+ // Used by HandleTreeViewPopup().
+ int HandleTreeViewPopup2( WPARAM wParam, LPARAM lParam );
+
+ //------------------------------------------------------------------
+ // Render skeleton
+ int RenderSkeleton( aiNode* piNode, const aiMatrix4x4& piMatrix,
+ const aiMatrix4x4& parent );
+
+
+
+ private:
+
+ // view mode
+ unsigned int m_iViewMode;
+
+ // List of all textures in the display CB
+ std::vector<TextureInfo> m_asTextures;
+
+ // current texture or NULL if no texture is active
+ TextureInfo* m_pcCurrentTexture;
+
+ // List of all node in the display CB
+ std::vector<NodeInfo> m_asNodes;
+
+ // List of all node in the display CB
+ std::vector<MeshInfo> m_asMeshes;
+
+ // current Node or NULL if no Node is active
+ NodeInfo* m_pcCurrentNode;
+
+ // List of all materials in the display CB
+ std::vector<MaterialInfo> m_asMaterials;
+
+ // current material or NULL if no material is active
+ MaterialInfo* m_pcCurrentMaterial;
+
+ // indices into the image list of the "display" tree view control
+ unsigned int m_aiImageList[ 5 ]; /* = {0,1,2,3,4};*/
+
+ // Image list
+ HIMAGELIST m_hImageList;
+
+ // Root node of the tree, "Model"
+ HTREEITEM m_hRoot;
+
+ // Current zoom factor of the texture viewer
+ float m_fTextureZoom;
+
+ // Current offset (in pixels) of the texture viewer
+ aiVector2D m_vTextureOffset;
+
+ // Colors used to draw the checker pattern (for the
+ // texture viewer as background )
+ D3DXVECTOR4 m_avCheckerColors[ 2 ];
+
+ // View projection matrix
+ aiMatrix4x4 mViewProjection;
+ aiVector3D vPos;
+ };
+
+}
+#endif // AV_DISPLAY_H_INCLUDE
diff --git a/libs/assimp/tools/assimp_view/HUD.png b/libs/assimp/tools/assimp_view/HUD.png
new file mode 100644
index 0000000..fe649fc
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/HUD.png
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/HUDMask.png b/libs/assimp/tools/assimp_view/HUDMask.png
new file mode 100644
index 0000000..98578dc
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/HUDMask.png
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/HelpDialog.cpp b/libs/assimp/tools/assimp_view/HelpDialog.cpp
new file mode 100644
index 0000000..fde4e1c
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/HelpDialog.cpp
@@ -0,0 +1,103 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+
+#include "richedit.h"
+
+namespace AssimpView {
+
+//-------------------------------------------------------------------------------
+// Message procedure for the help dialog
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM ) {
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ {
+ // load the help file ...
+ HRSRC res = FindResource(nullptr,MAKEINTRESOURCE(IDR_TEXT1),"TEXT");
+ HGLOBAL hg = LoadResource(nullptr,res);
+ void* pData = LockResource(hg);
+
+ SETTEXTEX sInfo;
+ sInfo.flags = ST_DEFAULT;
+ sInfo.codepage = CP_ACP;
+
+ SendDlgItemMessage(hwndDlg,IDC_RICHEDIT21,
+ EM_SETTEXTEX,(WPARAM)&sInfo,( LPARAM) pData);
+
+ FreeResource(hg);
+ return TRUE;
+ }
+
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return TRUE;
+
+ case WM_COMMAND:
+ if (IDOK == LOWORD(wParam)) {
+ EndDialog(hwndDlg,0);
+ return TRUE;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT sPaint;
+ HDC hdc = BeginPaint(hwndDlg,&sPaint);
+
+ HBRUSH hBrush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF));
+
+ RECT sRect;
+ sRect.left = 0;
+ sRect.top = 26;
+ sRect.right = 1000;
+ sRect.bottom = 507;
+ FillRect(hdc, &sRect, hBrush);
+
+ EndPaint(hwndDlg,&sPaint);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+}
diff --git a/libs/assimp/tools/assimp_view/Input.cpp b/libs/assimp/tools/assimp_view/Input.cpp
new file mode 100644
index 0000000..b8572d7
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Input.cpp
@@ -0,0 +1,372 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+
+namespace AssimpView {
+
+//-------------------------------------------------------------------------------
+// Handle mouse input for the FPS input behaviour
+//
+// Movement in x and y axis is possible
+//-------------------------------------------------------------------------------
+void HandleMouseInputFPS( void )
+ {
+ POINT mousePos;
+ GetCursorPos( &mousePos );
+ ScreenToClient( GetDlgItem(g_hDlg,IDC_RT), &mousePos );
+
+ g_mousePos.x = mousePos.x;
+ g_mousePos.y = mousePos.y;
+
+ D3DXMATRIX matRotation;
+
+ if (g_bMousePressed)
+ {
+ int nXDiff = (g_mousePos.x - g_LastmousePos.x);
+ int nYDiff = (g_mousePos.y - g_LastmousePos.y);
+
+ if( 0 != nYDiff)
+ {
+ D3DXMatrixRotationAxis( &matRotation, (D3DXVECTOR3*)& g_sCamera.vRight, D3DXToRadian((float)nYDiff / 6.0f));
+ D3DXVec3TransformCoord( (D3DXVECTOR3*)&g_sCamera.vLookAt, (D3DXVECTOR3*)& g_sCamera.vLookAt, &matRotation );
+ D3DXVec3TransformCoord( (D3DXVECTOR3*)&g_sCamera.vUp, (D3DXVECTOR3*)&g_sCamera.vUp, &matRotation );
+ }
+
+ if( 0 != nXDiff )
+ {
+ D3DXVECTOR3 v(0,1,0);
+ D3DXMatrixRotationAxis( &matRotation, (D3DXVECTOR3*)&g_sCamera.vUp, D3DXToRadian((float)nXDiff / 6.0f) );
+ D3DXVec3TransformCoord( (D3DXVECTOR3*)&g_sCamera.vLookAt, (D3DXVECTOR3*)&g_sCamera.vLookAt, &matRotation );
+ D3DXVec3TransformCoord( (D3DXVECTOR3*)&g_sCamera.vRight,(D3DXVECTOR3*) &g_sCamera.vRight, &matRotation );
+ }
+ }
+
+ g_LastmousePos.x = g_mousePos.x;
+ g_LastmousePos.y = g_mousePos.y;
+ }
+
+
+//-------------------------------------------------------------------------------
+// Handle mouse input for the FPS input behaviour
+//
+// Movement in x and y axis is possible
+//-------------------------------------------------------------------------------
+void HandleMouseInputTextureView( void )
+ {
+ POINT mousePos;
+ GetCursorPos( &mousePos );
+ ScreenToClient( GetDlgItem(g_hDlg,IDC_RT), &mousePos );
+
+ g_mousePos.x = mousePos.x;
+ g_mousePos.y = mousePos.y;
+
+ D3DXMATRIX matRotation;
+
+ if (g_bMousePressed)
+ {
+ CDisplay::Instance().SetTextureViewOffsetX((float)(g_mousePos.x - g_LastmousePos.x));
+ CDisplay::Instance().SetTextureViewOffsetY((float)(g_mousePos.y - g_LastmousePos.y));
+ }
+
+ g_LastmousePos.x = g_mousePos.x;
+ g_LastmousePos.y = g_mousePos.y;
+ }
+
+//-------------------------------------------------------------------------------
+// handle mouse input for the light rotation
+//
+// Axes: global x/y axis
+//-------------------------------------------------------------------------------
+void HandleMouseInputLightRotate( void )
+ {
+ POINT mousePos;
+ GetCursorPos( &mousePos );
+ ScreenToClient( GetDlgItem(g_hDlg,IDC_RT), &mousePos );
+
+ g_mousePos.x = mousePos.x;
+ g_mousePos.y = mousePos.y;
+
+ if (g_bMousePressedR)
+ {
+ int nXDiff = -(g_mousePos.x - g_LastmousePos.x);
+ int nYDiff = -(g_mousePos.y - g_LastmousePos.y);
+
+ aiVector3D v = aiVector3D(1.0f,0.0f,0.0f);
+ aiMatrix4x4 mTemp;
+ D3DXMatrixRotationAxis( (D3DXMATRIX*) &mTemp, (D3DXVECTOR3*)&v, D3DXToRadian((float)nYDiff / 2.0f));
+ D3DXVec3TransformCoord((D3DXVECTOR3*)&g_avLightDirs[0],
+ (const D3DXVECTOR3*)&g_avLightDirs[0],(const D3DXMATRIX*)&mTemp);
+
+ v = aiVector3D(0.0f,1.0f,0.0f);
+ D3DXMatrixRotationAxis( (D3DXMATRIX*) &mTemp, (D3DXVECTOR3*)&v, D3DXToRadian((float)nXDiff / 2.0f));
+ D3DXVec3TransformCoord((D3DXVECTOR3*)&g_avLightDirs[0],
+ (const D3DXVECTOR3*)&g_avLightDirs[0],(const D3DXMATRIX*)&mTemp);
+ }
+ return;
+ }
+
+
+//-------------------------------------------------------------------------------
+// Handle mouse input for movements of the skybox
+//
+// The skybox can be moved by holding both the left and the right mouse button
+// pressed. Rotation is possible in x and y direction.
+//-------------------------------------------------------------------------------
+void HandleMouseInputSkyBox( void )
+ {
+ POINT mousePos;
+ GetCursorPos( &mousePos );
+ ScreenToClient( GetDlgItem(g_hDlg,IDC_RT), &mousePos );
+
+ g_mousePos.x = mousePos.x;
+ g_mousePos.y = mousePos.y;
+
+ aiMatrix4x4 matRotation;
+
+ if (g_bMousePressedBoth )
+ {
+ int nXDiff = -(g_mousePos.x - g_LastmousePos.x);
+ int nYDiff = -(g_mousePos.y - g_LastmousePos.y);
+
+ aiMatrix4x4 matWorld;
+
+ if( 0 != nYDiff)
+ {
+ aiVector3D v = aiVector3D(1.0f,0.0f,0.0f);
+ D3DXMatrixRotationAxis( (D3DXMATRIX*) &matWorld, (D3DXVECTOR3*)&v, D3DXToRadian((float)nYDiff / 2.0f));
+ CBackgroundPainter::Instance().RotateSB(&matWorld);
+ }
+
+ if( 0 != nXDiff)
+ {
+ aiMatrix4x4 matWorldOld;
+ if( 0 != nYDiff)
+ {
+ matWorldOld = matWorld;
+ }
+
+ aiVector3D v = aiVector3D(0.0f,1.0f,0.0f);
+ D3DXMatrixRotationAxis( (D3DXMATRIX*)&matWorld, (D3DXVECTOR3*)&v, D3DXToRadian((float)nXDiff / 2.0f) );
+ matWorld = matWorldOld * matWorld;
+ CBackgroundPainter::Instance().RotateSB(&matWorld);
+ }
+ }
+ }
+
+//-------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------
+void HandleMouseInputLightIntensityAndColor()
+ {
+ POINT mousePos;
+ GetCursorPos( &mousePos );
+ ScreenToClient( GetDlgItem(g_hDlg,IDC_RT), &mousePos );
+
+ g_mousePos.x = mousePos.x;
+ g_mousePos.y = mousePos.y;
+
+ if (g_bMousePressedM)
+ {
+ int nXDiff = -(g_mousePos.x - g_LastmousePos.x);
+ int nYDiff = -(g_mousePos.y - g_LastmousePos.y);
+
+ g_fLightIntensity -= (float)nXDiff / 400.0f;
+ if ((nYDiff > 2 || nYDiff < -2) && (nXDiff < 20 && nXDiff > -20))
+ {
+ if (!g_bFPSView)
+ {
+ g_sCamera.vPos.z += nYDiff / 120.0f;
+ }
+ else
+ {
+ g_sCamera.vPos += (nYDiff / 120.0f) * g_sCamera.vLookAt.Normalize();
+ }
+ }
+ }
+ return;
+ }
+
+//-------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------
+void HandleMouseInputLocal( void )
+ {
+ POINT mousePos;
+ GetCursorPos( &mousePos );
+ ScreenToClient( GetDlgItem(g_hDlg,IDC_RT), &mousePos );
+
+ g_mousePos.x = mousePos.x;
+ g_mousePos.y = mousePos.y;
+
+ aiMatrix4x4 matRotation;
+
+ if (g_bMousePressed)
+ {
+ int nXDiff = -(g_mousePos.x - g_LastmousePos.x);
+ int nYDiff = -(g_mousePos.y - g_LastmousePos.y);
+
+ aiMatrix4x4 matWorld;
+ if (g_eClick != EClickPos_Outside)
+ {
+ if( 0 != nYDiff && g_eClick != EClickPos_CircleHor)
+ {
+ aiVector3D v = aiVector3D(1.0f,0.0f,0.0f);
+ D3DXMatrixRotationAxis( (D3DXMATRIX*) &matWorld, (D3DXVECTOR3*)&v, D3DXToRadian((float)nYDiff / 2.0f));
+ g_mWorldRotate = g_mWorldRotate * matWorld;
+ }
+
+ if( 0 != nXDiff && g_eClick != EClickPos_CircleVert)
+ {
+ aiVector3D v = aiVector3D(0.0f,1.0f,0.0f);
+ D3DXMatrixRotationAxis( (D3DXMATRIX*)&matWorld, (D3DXVECTOR3*)&v, D3DXToRadian((float)nXDiff / 2.0f) );
+ g_mWorldRotate = g_mWorldRotate * matWorld;
+ }
+ }
+ else
+ {
+ if(0 != nYDiff || 0 != nXDiff)
+ {
+ // rotate around the z-axis
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ int xPos = g_mousePos.x - sRect.right/2;
+ int yPos = g_mousePos.y - sRect.bottom/2;
+ float fXDist = (float)xPos;
+ float fYDist = (float)yPos / sqrtf((float)(yPos * yPos + xPos * xPos));
+
+ bool bSign1;
+ if (fXDist < 0.0f)bSign1 = false;
+ else bSign1 = true;
+ float fAngle = asin(fYDist);
+
+ xPos = g_LastmousePos.x - sRect.right/2;
+ yPos = g_LastmousePos.y - sRect.bottom/2;
+
+ fXDist = (float)xPos;
+ fYDist = (float)yPos / sqrtf((float)(yPos * yPos + xPos * xPos));
+
+ bool bSign2;
+ if (fXDist < 0.0f)bSign2 = false;
+ else bSign2 = true;
+ float fAngle2 = asin(fYDist);
+ fAngle -= fAngle2;
+
+ if (bSign1 != bSign2)
+ {
+ g_bInvert = !g_bInvert;
+ }
+ if (g_bInvert)fAngle *= -1.0f;
+
+ aiVector3D v = aiVector3D(0.0f,0.0f,1.0f);
+ D3DXMatrixRotationAxis( (D3DXMATRIX*)&matWorld, (D3DXVECTOR3*)&v, (float) (fAngle * 1.2) );
+ g_mWorldRotate = g_mWorldRotate * matWorld;
+ }
+ }
+ }
+
+ g_LastmousePos.x = g_mousePos.x;
+ g_LastmousePos.y = g_mousePos.y;
+ }
+
+//-------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------
+void HandleKeyboardInputFPS( void )
+ {
+ unsigned char keys[256];
+ GetKeyboardState( keys );
+
+ aiVector3D tmpLook = g_sCamera.vLookAt;
+ aiVector3D tmpRight = g_sCamera.vRight;
+
+ aiVector3D vOldPos = g_sCamera.vPos;
+
+ // Up Arrow Key - View moves forward
+ if( keys[VK_UP] & 0x80 )
+ g_sCamera.vPos -= (tmpLook*-MOVE_SPEED)*g_fElpasedTime;
+
+ // Down Arrow Key - View moves backward
+ if( keys[VK_DOWN] & 0x80 )
+ g_sCamera.vPos += (tmpLook*-MOVE_SPEED)*g_fElpasedTime;
+
+ // Left Arrow Key - View side-steps or strafes to the left
+ if( keys[VK_LEFT] & 0x80 )
+ g_sCamera.vPos -= (tmpRight*MOVE_SPEED)*g_fElpasedTime;
+
+ // Right Arrow Key - View side-steps or strafes to the right
+ if( keys[VK_RIGHT] & 0x80 )
+ g_sCamera.vPos += (tmpRight*MOVE_SPEED)*g_fElpasedTime;
+
+ // Home Key - View elevates up
+ if( keys[VK_HOME] & 0x80 )
+ g_sCamera.vPos .y += MOVE_SPEED*g_fElpasedTime;
+
+ // End Key - View elevates down
+ if( keys[VK_END] & 0x80 )
+ g_sCamera.vPos.y -= MOVE_SPEED*g_fElpasedTime;
+ }
+
+
+//-------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------
+void HandleKeyboardInputTextureView( void )
+ {
+ unsigned char keys[256];
+ GetKeyboardState( keys );
+
+ // Up Arrow Key
+ if( keys[VK_UP] & 0x80 )
+ CDisplay::Instance().SetTextureViewOffsetY ( g_fElpasedTime * 150.0f );
+
+ // Down Arrow Key
+ if( keys[VK_DOWN] & 0x80 )
+ CDisplay::Instance().SetTextureViewOffsetY ( -g_fElpasedTime * 150.0f );
+
+ // Left Arrow Key
+ if( keys[VK_LEFT] & 0x80 )
+ CDisplay::Instance().SetTextureViewOffsetX ( g_fElpasedTime * 150.0f );
+
+ // Right Arrow Key
+ if( keys[VK_RIGHT] & 0x80 )
+ CDisplay::Instance().SetTextureViewOffsetX ( -g_fElpasedTime * 150.0f );
+ }
+};
diff --git a/libs/assimp/tools/assimp_view/LogDisplay.cpp b/libs/assimp/tools/assimp_view/LogDisplay.cpp
new file mode 100644
index 0000000..1bd650c
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/LogDisplay.cpp
@@ -0,0 +1,221 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+
+namespace AssimpView {
+
+CLogDisplay CLogDisplay::s_cInstance;
+
+//-------------------------------------------------------------------------------
+void CLogDisplay::AddEntry(const std::string& szText, const D3DCOLOR clrColor) {
+ SEntry sNew;
+ sNew.clrColor = clrColor;
+ sNew.szText = szText;
+ sNew.dwStartTicks = (DWORD)GetTickCount();
+
+ this->asEntries.push_back(sNew);
+}
+
+//-------------------------------------------------------------------------------
+void CLogDisplay::ReleaseNativeResource() {
+ if (this->piFont) {
+ this->piFont->Release();
+ this->piFont = nullptr;
+ }
+}
+
+//-------------------------------------------------------------------------------
+void CLogDisplay::RecreateNativeResource() {
+ if (!this->piFont) {
+ if (FAILED(D3DXCreateFont(g_piDevice,
+ 16, //Font height
+ 0, //Font width
+ FW_BOLD, //Font Weight
+ 1, //MipLevels
+ false, //Italic
+ DEFAULT_CHARSET, //CharSet
+ OUT_DEFAULT_PRECIS, //OutputPrecision
+ //CLEARTYPE_QUALITY, //Quality
+ 5, //Quality
+ DEFAULT_PITCH|FF_DONTCARE, //PitchAndFamily
+ "Verdana", //pFacename,
+ &this->piFont))) {
+ CLogDisplay::Instance().AddEntry("Unable to load font",D3DCOLOR_ARGB(0xFF,0xFF,0,0));
+
+ this->piFont = nullptr;
+ return;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------
+void CLogDisplay::OnRender() {
+ DWORD dwTick = (DWORD) GetTickCount();
+ DWORD dwLimit = dwTick - 8000;
+ DWORD dwLimit2 = dwLimit + 3000;
+
+ unsigned int iCnt = 0;
+ RECT sRect;
+ sRect.left = 10;
+ sRect.top = 10;
+
+ RECT sWndRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sWndRect);
+ sWndRect.right -= sWndRect.left;
+ sWndRect.bottom -= sWndRect.top;
+ sWndRect.left = sWndRect.top = 0;
+
+ sRect.right = sWndRect.right - 30;
+ sRect.bottom = sWndRect.bottom;
+
+ // if no asset is loaded draw a "no asset loaded" text in the center
+ if (!g_pcAsset) {
+ const char* szText = "Nothing to display ... \r\nTry [Viewer | Open asset] to load an asset";
+
+ // shadow
+ RECT sCopy;
+ sCopy.left = sWndRect.left+1;
+ sCopy.top = sWndRect.top+1;
+ sCopy.bottom = sWndRect.bottom+1;
+ sCopy.right = sWndRect.right+1;
+ this->piFont->DrawText(nullptr,szText ,
+ -1,&sCopy,DT_CENTER | DT_VCENTER,D3DCOLOR_ARGB(100,0x0,0x0,0x0));
+ sCopy.left = sWndRect.left+1;
+ sCopy.top = sWndRect.top+1;
+ sCopy.bottom = sWndRect.bottom-1;
+ sCopy.right = sWndRect.right-1;
+ this->piFont->DrawText(nullptr,szText ,
+ -1,&sCopy,DT_CENTER | DT_VCENTER,D3DCOLOR_ARGB(100,0x0,0x0,0x0));
+ sCopy.left = sWndRect.left-1;
+ sCopy.top = sWndRect.top-1;
+ sCopy.bottom = sWndRect.bottom+1;
+ sCopy.right = sWndRect.right+1;
+ this->piFont->DrawText(nullptr,szText ,
+ -1,&sCopy,DT_CENTER | DT_VCENTER,D3DCOLOR_ARGB(100,0x0,0x0,0x0));
+ sCopy.left = sWndRect.left-1;
+ sCopy.top = sWndRect.top-1;
+ sCopy.bottom = sWndRect.bottom-1;
+ sCopy.right = sWndRect.right-1;
+ this->piFont->DrawText(nullptr,szText ,
+ -1,&sCopy,DT_CENTER | DT_VCENTER,D3DCOLOR_ARGB(100,0x0,0x0,0x0));
+
+ // text
+ this->piFont->DrawText(nullptr,szText ,
+ -1,&sWndRect,DT_CENTER | DT_VCENTER,D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0xFF));
+ }
+
+ // update all elements in the queue and render them
+ for (std::list<SEntry>::iterator
+ i = this->asEntries.begin();
+ i != this->asEntries.end();++i,++iCnt) {
+ if ((*i).dwStartTicks < dwLimit) {
+ i = this->asEntries.erase(i);
+
+ if (i == this->asEntries.end()) {
+ break;
+ }
+ } else if (nullptr != this->piFont) {
+ float fAlpha = 1.0f;
+ if ((*i).dwStartTicks <= dwLimit2) {
+ // linearly interpolate to create the fade out effect
+ fAlpha = 1.0f - (float)(dwLimit2 - (*i).dwStartTicks) / 3000.0f;
+ }
+ D3DCOLOR& clrColor = (*i).clrColor;
+ clrColor &= ~(0xFFu << 24);
+ clrColor |= (((unsigned char)(fAlpha * 255.0f)) & 0xFFu) << 24;
+
+ const char* szText = (*i).szText.c_str();
+ if (sRect.top + 30 > sWndRect.bottom) {
+ // end of window. send a special message
+ szText = "... too many errors";
+ clrColor = D3DCOLOR_ARGB(0xFF,0xFF,100,0x0);
+ }
+
+ // draw the black shadow
+ RECT sCopy;
+ sCopy.left = sRect.left+1;
+ sCopy.top = sRect.top+1;
+ sCopy.bottom = sRect.bottom+1;
+ sCopy.right = sRect.right+1;
+ this->piFont->DrawText(nullptr,szText,
+ -1,&sCopy,DT_RIGHT | DT_TOP,D3DCOLOR_ARGB(
+ (unsigned char)(fAlpha * 100.0f),0x0,0x0,0x0));
+
+ sCopy.left = sRect.left-1;
+ sCopy.top = sRect.top-1;
+ sCopy.bottom = sRect.bottom-1;
+ sCopy.right = sRect.right-1;
+ this->piFont->DrawText(nullptr,szText,
+ -1,&sCopy,DT_RIGHT | DT_TOP,D3DCOLOR_ARGB(
+ (unsigned char)(fAlpha * 100.0f),0x0,0x0,0x0));
+
+ sCopy.left = sRect.left-1;
+ sCopy.top = sRect.top-1;
+ sCopy.bottom = sRect.bottom+1;
+ sCopy.right = sRect.right+1;
+ this->piFont->DrawText(nullptr,szText,
+ -1,&sCopy,DT_RIGHT | DT_TOP,D3DCOLOR_ARGB(
+ (unsigned char)(fAlpha * 100.0f),0x0,0x0,0x0));
+
+ sCopy.left = sRect.left+1;
+ sCopy.top = sRect.top+1;
+ sCopy.bottom = sRect.bottom-1;
+ sCopy.right = sRect.right-1;
+ this->piFont->DrawText(nullptr,szText,
+ -1,&sCopy,DT_RIGHT | DT_TOP,D3DCOLOR_ARGB(
+ (unsigned char)(fAlpha * 100.0f),0x0,0x0,0x0));
+
+ // draw the text itself
+ int iPX = this->piFont->DrawText(nullptr,szText,
+ -1,&sRect,DT_RIGHT | DT_TOP,clrColor);
+
+ sRect.top += iPX;
+ sRect.bottom += iPX;
+
+ if (szText != (*i).szText.c_str()) {
+ break;
+ }
+ }
+ }
+}
+
+}
diff --git a/libs/assimp/tools/assimp_view/LogDisplay.h b/libs/assimp/tools/assimp_view/LogDisplay.h
new file mode 100644
index 0000000..e0878b8
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/LogDisplay.h
@@ -0,0 +1,99 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+#pragma once
+
+#include <list>
+
+namespace AssimpView
+{
+
+ //-------------------------------------------------------------------------------
+ /** \brief Class to display log strings in the upper right corner of the view
+ */
+ //-------------------------------------------------------------------------------
+ class CLogDisplay
+ {
+ private:
+
+ CLogDisplay() {}
+
+ public:
+
+ // data structure for an entry in the log queue
+ struct SEntry
+ {
+ SEntry()
+ :
+ clrColor( D3DCOLOR_ARGB( 0xFF, 0xFF, 0xFF, 0x00 ) ), dwStartTicks( 0 )
+ {}
+
+ std::string szText;
+ D3DCOLOR clrColor;
+ DWORD dwStartTicks;
+ };
+
+ // Singleton accessors
+ static CLogDisplay s_cInstance;
+ inline static CLogDisplay& Instance()
+ {
+ return s_cInstance;
+ }
+
+ // Add an entry to the log queue
+ void AddEntry( const std::string& szText,
+ const D3DCOLOR clrColor = D3DCOLOR_ARGB( 0xFF, 0xFF, 0xFF, 0x00 ) );
+
+ // Release any native resources associated with the instance
+ void ReleaseNativeResource();
+
+ // Recreate any native resources associated with the instance
+ void RecreateNativeResource();
+
+ // Called during the render loop
+ void OnRender();
+
+ private:
+
+ std::list<SEntry> asEntries;
+ ID3DXFont* piFont;
+ };
+
+}
diff --git a/libs/assimp/tools/assimp_view/LogWindow.cpp b/libs/assimp/tools/assimp_view/LogWindow.cpp
new file mode 100644
index 0000000..8e80bf5
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/LogWindow.cpp
@@ -0,0 +1,238 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+#include "richedit.h"
+#include <commdlg.h>
+#include <commoncontrols.h>
+
+namespace AssimpView {
+
+CLogWindow CLogWindow::s_cInstance;
+
+extern HKEY g_hRegistry;
+
+// header for the RTF log file
+static const char *AI_VIEW_RTF_LOG_HEADER =
+ "{\\rtf1"
+ "\\ansi"
+ "\\deff0"
+ "{"
+ "\\fonttbl{\\f0 Courier New;}"
+ "}"
+ "{\\colortbl;"
+ "\\red255\\green0\\blue0;" // red for errors
+ "\\red255\\green120\\blue0;" // orange for warnings
+ "\\red0\\green150\\blue0;" // green for infos
+ "\\red0\\green0\\blue180;" // blue for debug messages
+ "\\red0\\green0\\blue0;" // black for everything else
+ "}}";
+
+//-------------------------------------------------------------------------------
+// Message procedure for the log window
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK LogDialogProc(HWND hwndDlg, UINT uMsg, WPARAM /*wParam*/, LPARAM lParam) {
+ (void)lParam;
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ return TRUE;
+
+ case WM_SIZE: {
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_EDIT1), nullptr, 0, 0,
+ x - 10, y - 12, SWP_NOMOVE | SWP_NOZORDER);
+
+ return TRUE;
+ }
+ case WM_CLOSE:
+ EndDialog(hwndDlg, 0);
+
+ CLogWindow::Instance().bIsVisible = false;
+ return TRUE;
+ };
+ return FALSE;
+}
+
+//-------------------------------------------------------------------------------
+void CLogWindow::Init() {
+ this->hwnd = ::CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_LOGVIEW),
+ nullptr, &LogDialogProc);
+
+ if (!this->hwnd) {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to create logger window",
+ D3DCOLOR_ARGB(0xFF, 0, 0xFF, 0));
+ }
+
+ // setup the log text
+ this->szText = AI_VIEW_RTF_LOG_HEADER;
+
+ this->szPlainText = "";
+}
+
+//-------------------------------------------------------------------------------
+void CLogWindow::Show() {
+ if (this->hwnd) {
+ ShowWindow(this->hwnd, SW_SHOW);
+ this->bIsVisible = true;
+
+ // contents aren't updated while the logger isn't displayed
+ this->Update();
+ }
+}
+
+//-------------------------------------------------------------------------------
+void CMyLogStream::write(const char *message) {
+ CLogWindow::Instance().WriteLine(message);
+}
+
+//-------------------------------------------------------------------------------
+void CLogWindow::Clear() {
+ this->szText = AI_VIEW_RTF_LOG_HEADER;
+ this->szPlainText = "";
+ this->Update();
+}
+
+//-------------------------------------------------------------------------------
+void CLogWindow::Update() {
+ if (this->bIsVisible) {
+ SETTEXTEX sInfo = {};
+ sInfo.flags = ST_DEFAULT;
+ sInfo.codepage = CP_ACP;
+
+ SendDlgItemMessage(this->hwnd, IDC_EDIT1,
+ EM_SETTEXTEX, (WPARAM)&sInfo, (LPARAM)this->szText.c_str());
+ }
+}
+
+//-------------------------------------------------------------------------------
+void CLogWindow::Save() {
+ char szFileName[MAX_PATH] = {};
+
+ DWORD dwTemp = MAX_PATH;
+ if (ERROR_SUCCESS != RegQueryValueEx(g_hRegistry, "LogDestination", nullptr, nullptr, (BYTE *)szFileName, &dwTemp)) {
+ // Key was not found. Use C:
+ strcpy(szFileName, "");
+ } else {
+ // need to remove the file name
+ char *sz = strrchr(szFileName, '\\');
+ if (!sz)
+ sz = strrchr(szFileName, '/');
+ if (sz)
+ *sz = 0;
+ }
+ OPENFILENAME sFilename1 = {
+ sizeof(OPENFILENAME),
+ g_hDlg, GetModuleHandle(nullptr),
+ "Log files\0*.txt", nullptr, 0, 1,
+ szFileName, MAX_PATH, nullptr, 0, nullptr,
+ "Save log to file",
+ OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
+ 0, 1, ".txt", 0, nullptr, nullptr
+ };
+ if (GetSaveFileName(&sFilename1) == 0) return;
+
+ // Now store the file in the registry
+ RegSetValueExA(g_hRegistry, "LogDestination", 0, REG_SZ, (const BYTE *)szFileName, MAX_PATH);
+
+ FILE *pFile = fopen(szFileName, "wt");
+ fprintf(pFile, this->szPlainText.c_str());
+ fclose(pFile);
+
+ CLogDisplay::Instance().AddEntry("[INFO] The log file has been saved",
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0));
+}
+
+//-------------------------------------------------------------------------------
+void CLogWindow::WriteLine(const char *message) {
+ this->szPlainText.append(message);
+ this->szPlainText.append("\r\n");
+
+ if (0 != this->szText.length()) {
+ this->szText.resize(this->szText.length() - 1);
+ }
+
+ switch (message[0]) {
+ case 'e':
+ case 'E':
+ this->szText.append("{\\pard \\cf1 \\b \\fs18 ");
+ break;
+ case 'w':
+ case 'W':
+ this->szText.append("{\\pard \\cf2 \\b \\fs18 ");
+ break;
+ case 'i':
+ case 'I':
+ this->szText.append("{\\pard \\cf3 \\b \\fs18 ");
+ break;
+ case 'd':
+ case 'D':
+ this->szText.append("{\\pard \\cf4 \\b \\fs18 ");
+ break;
+ default:
+ this->szText.append("{\\pard \\cf5 \\b \\fs18 ");
+ break;
+ }
+
+ std::string _message = message;
+ for (unsigned int i = 0; i < _message.length(); ++i) {
+ if ('\\' == _message[i] ||
+ '}' == _message[i] ||
+ '{' == _message[i]) {
+ _message.insert(i++, "\\");
+ }
+ }
+
+ this->szText.append(_message);
+ this->szText.append("\\par}}");
+
+ if (this->bIsVisible && this->bUpdate) {
+ SETTEXTEX sInfo = {};
+ sInfo.flags = ST_DEFAULT;
+ sInfo.codepage = CP_ACP;
+
+ SendDlgItemMessage(this->hwnd, IDC_EDIT1,
+ EM_SETTEXTEX, (WPARAM)&sInfo, (LPARAM)this->szText.c_str());
+ }
+}
+
+} // namespace AssimpView
diff --git a/libs/assimp/tools/assimp_view/LogWindow.h b/libs/assimp/tools/assimp_view/LogWindow.h
new file mode 100644
index 0000000..5b2a3d2
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/LogWindow.h
@@ -0,0 +1,133 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_LOG_WINDOW_H_INCLUDED)
+#define AV_LOG_WINDOW_H_INCLUDE
+
+namespace AssimpView
+{
+
+
+ //-------------------------------------------------------------------------------
+ /** \brief Subclass of Assimp::LogStream used to add all log messages to the
+ * log window.
+ */
+ //-------------------------------------------------------------------------------
+ class CMyLogStream : public Assimp::LogStream
+ {
+ public:
+ /** @brief Implementation of the abstract method */
+ void write( const char* message );
+ };
+
+
+ //-------------------------------------------------------------------------------
+ /** \brief Class to display log strings in a separate window
+ */
+ //-------------------------------------------------------------------------------
+ class CLogWindow
+ {
+ private:
+
+ friend class CMyLogStream;
+ friend INT_PTR CALLBACK LogDialogProc( HWND hwndDlg, UINT uMsg,
+ WPARAM wParam, LPARAM lParam );
+
+ CLogWindow() : hwnd( NULL ), bIsVisible( false ), bUpdate( true ) {}
+
+ public:
+
+
+ // Singleton accessors
+ static CLogWindow s_cInstance;
+ inline static CLogWindow& Instance()
+ {
+ return s_cInstance;
+ }
+
+ // initializes the log window
+ void Init();
+
+ // Shows the log window
+ void Show();
+
+ // Clears the log window
+ void Clear();
+
+ // Save the log window to an user-defined file
+ void Save();
+
+ // write a line to the log window
+ void WriteLine( const char* message );
+
+ // Set the bUpdate member
+ inline void SetAutoUpdate( bool b )
+ {
+ this->bUpdate = b;
+ }
+
+ // updates the log file
+ void Update();
+
+ private:
+
+ // Window handle
+ HWND hwnd;
+
+ // current text of the window (contains RTF tags)
+ std::string szText;
+ std::string szPlainText;
+
+ // is the log window currently visible?
+ bool bIsVisible;
+
+ // Specified whether each new log message updates the log automatically
+ bool bUpdate;
+
+
+ public:
+ // associated log stream
+ CMyLogStream* pcStream;
+ };
+
+}
+
+#endif // AV_LOG_DISPLA
diff --git a/libs/assimp/tools/assimp_view/Material.cpp b/libs/assimp/tools/assimp_view/Material.cpp
new file mode 100644
index 0000000..e3c023b
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Material.cpp
@@ -0,0 +1,1494 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+#include "assimp_view.h"
+
+#include "MaterialManager.h"
+#include "AssetHelper.h"
+
+#include <assimp/cimport.h>
+#include <assimp/Importer.hpp>
+#include <assimp/ai_assert.h>
+#include <assimp/cfileio.h>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
+#include <assimp/IOSystem.hpp>
+#include <assimp/IOStream.hpp>
+#include <assimp/LogStream.hpp>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/StringComparison.h>
+
+#include <vector>
+#include <algorithm>
+
+namespace AssimpView {
+
+using namespace Assimp;
+
+extern std::string g_szMaterialShader;
+extern HINSTANCE g_hInstance /*= NULL*/;
+extern HWND g_hDlg /*= NULL*/;
+extern IDirect3D9* g_piD3D /*= NULL*/;
+extern IDirect3DDevice9* g_piDevice /*= NULL*/;
+extern IDirect3DVertexDeclaration9* gDefaultVertexDecl /*= NULL*/;
+extern double g_fFPS /*= 0.0f*/;
+extern char g_szFileName[ MAX_PATH ];
+extern ID3DXEffect* g_piDefaultEffect /*= NULL*/;
+extern ID3DXEffect* g_piNormalsEffect /*= NULL*/;
+extern ID3DXEffect* g_piPassThroughEffect /*= NULL*/;
+extern ID3DXEffect* g_piPatternEffect /*= NULL*/;
+extern bool g_bMousePressed /*= false*/;
+extern bool g_bMousePressedR /*= false*/;
+extern bool g_bMousePressedM /*= false*/;
+extern bool g_bMousePressedBoth /*= false*/;
+extern float g_fElpasedTime /*= 0.0f*/;
+extern D3DCAPS9 g_sCaps;
+extern bool g_bLoadingFinished /*= false*/;
+extern HANDLE g_hThreadHandle /*= NULL*/;
+extern float g_fWheelPos /*= -10.0f*/;
+extern bool g_bLoadingCanceled /*= false*/;
+extern IDirect3DTexture9* g_pcTexture /*= NULL*/;
+
+extern aiMatrix4x4 g_mWorld;
+extern aiMatrix4x4 g_mWorldRotate;
+extern aiVector3D g_vRotateSpeed /*= aiVector3D(0.5f,0.5f,0.5f)*/;
+
+extern aiVector3D g_avLightDirs[ 1 ] /* =
+ { aiVector3D(-0.5f,0.6f,0.2f) ,
+ aiVector3D(-0.5f,0.5f,0.5f)} */;
+
+
+extern POINT g_mousePos /*= {0,0};*/;
+extern POINT g_LastmousePos /*= {0,0}*/;
+extern bool g_bFPSView /*= false*/;
+extern bool g_bInvert /*= false*/;
+extern EClickPos g_eClick;
+extern unsigned int g_iCurrentColor /*= 0*/;
+
+// NOTE: The light intensity is separated from the color, it can
+// directly be manipulated using the middle mouse button.
+// When the user chooses a color from the palette the intensity
+// is reset to 1.0
+// index[2] is the ambient color
+extern float g_fLightIntensity /*=0.0f*/;
+extern D3DCOLOR g_avLightColors[ 3 ];
+
+extern RenderOptions g_sOptions;
+extern Camera g_sCamera;
+extern AssetHelper *g_pcAsset /*= NULL*/;
+
+
+//
+// Contains the mask image for the HUD
+// (used to determine the position of a click)
+//
+// The size of the image is identical to the size of the main
+// HUD texture
+//
+extern unsigned char* g_szImageMask /*= NULL*/;
+
+
+extern float g_fACMR /*= 3.0f*/;
+extern IDirect3DQuery9* g_piQuery;
+
+extern bool g_bPlay /*= false*/;
+
+extern double g_dCurrent;
+extern float g_smoothAngle /*= 80.f*/;
+
+extern unsigned int ppsteps, ppstepsdefault;
+extern bool nopointslines;
+
+CMaterialManager CMaterialManager::s_cInstance;
+
+//-------------------------------------------------------------------------------
+// D3DX callback function to fill a texture with a checkers pattern
+//
+// This pattern is used to mark textures which could not be loaded
+//-------------------------------------------------------------------------------
+VOID WINAPI FillFunc(D3DXVECTOR4* pOut,
+ CONST D3DXVECTOR2* pTexCoord,
+ CONST D3DXVECTOR2* pTexelSize,
+ LPVOID pData)
+{
+ UNREFERENCED_PARAMETER(pData);
+ UNREFERENCED_PARAMETER(pTexelSize);
+
+ // generate a nice checker pattern (yellow/black)
+ // size of a square: 32 * 32 px
+ unsigned int iX = (unsigned int)(pTexCoord->x * 256.0f);
+ unsigned int iY = (unsigned int)(pTexCoord->y * 256.0f);
+
+ bool bBlack = false;
+ if ((iX / 32) % 2 == 0)
+ {
+ if ((iY / 32) % 2 == 0)bBlack = true;
+ }
+ else
+ {
+ if ((iY / 32) % 2 != 0)bBlack = true;
+ }
+ pOut->w = 1.0f;
+ if (bBlack)
+ {
+ pOut->x = pOut->y = pOut->z = 0.0f;
+ }
+ else
+ {
+ pOut->x = pOut->y = 1.0f;
+ pOut->z = 0.0f;
+ }
+ return;
+}
+
+//-------------------------------------------------------------------------------
+int CMaterialManager::UpdateSpecularMaterials()
+ {
+ if (g_pcAsset && g_pcAsset->pcScene)
+ {
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (aiShadingMode_Phong == g_pcAsset->apcMeshes[i]->eShadingMode)
+ {
+ this->DeleteMaterial(g_pcAsset->apcMeshes[i]);
+ this->CreateMaterial(g_pcAsset->apcMeshes[i],g_pcAsset->pcScene->mMeshes[i]);
+ }
+ }
+ }
+ return 1;
+ }
+//-------------------------------------------------------------------------------
+int CMaterialManager::SetDefaultTexture(IDirect3DTexture9** p_ppiOut)
+{
+ if (sDefaultTexture) {
+ sDefaultTexture->AddRef();
+ *p_ppiOut = sDefaultTexture;
+ return 1;
+ }
+ if(FAILED(g_piDevice->CreateTexture(
+ 256,
+ 256,
+ 0,
+ 0,
+ D3DFMT_A8R8G8B8,
+ D3DPOOL_MANAGED,
+ p_ppiOut,
+ nullptr)))
+ {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to create default texture",
+ D3DCOLOR_ARGB(0xFF,0xFF,0,0));
+
+ *p_ppiOut = nullptr;
+ return 0;
+ }
+ D3DXFillTexture(*p_ppiOut,&FillFunc,nullptr);
+ sDefaultTexture = *p_ppiOut;
+ sDefaultTexture->AddRef();
+
+ // {9785DA94-1D96-426b-B3CB-BADC36347F5E}
+ static const GUID guidPrivateData =
+ { 0x9785da94, 0x1d96, 0x426b,
+ { 0xb3, 0xcb, 0xba, 0xdc, 0x36, 0x34, 0x7f, 0x5e } };
+
+ uint32_t iData = 0xFFFFFFFF;
+ (*p_ppiOut)->SetPrivateData(guidPrivateData,&iData,4,0);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+bool CMaterialManager::TryLongerPath(char* szTemp,aiString* p_szString)
+{
+ char szTempB[MAX_PATH];
+ strcpy(szTempB,szTemp);
+
+ // go to the beginning of the file name
+ char* szFile = strrchr(szTempB,'\\');
+ if (!szFile)szFile = strrchr(szTempB,'/');
+
+ char* szFile2 = szTemp + (szFile - szTempB)+1;
+ szFile++;
+ char* szExt = strrchr(szFile,'.');
+ if (!szExt)return false;
+ szExt++;
+ *szFile = 0;
+
+ strcat(szTempB,"*.*");
+ const unsigned int iSize = (const unsigned int) ( szExt - 1 - szFile );
+
+ HANDLE h;
+ WIN32_FIND_DATA info;
+
+ // build a list of files
+ h = FindFirstFile(szTempB, &info);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (!(strcmp(info.cFileName, ".") == 0 || strcmp(info.cFileName, "..") == 0))
+ {
+ char* szExtFound = strrchr(info.cFileName, '.');
+ if (szExtFound)
+ {
+ ++szExtFound;
+ if (0 == ASSIMP_stricmp(szExtFound,szExt))
+ {
+ const unsigned int iSizeFound = (const unsigned int) (
+ szExtFound - 1 - info.cFileName);
+
+ for (unsigned int i = 0; i < iSizeFound;++i)
+ info.cFileName[i] = (CHAR)tolower((unsigned char)info.cFileName[i]);
+
+ if (0 == memcmp(info.cFileName,szFile2, std::min(iSizeFound,iSize)))
+ {
+ // we have it. Build the full path ...
+ char* sz = strrchr(szTempB,'*');
+ *(sz-2) = 0x0;
+
+ strcat(szTempB,info.cFileName);
+
+ // copy the result string back to the aiString
+ const size_t iLen = strlen(szTempB);
+ size_t iLen2 = iLen+1;
+ iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
+ memcpy(p_szString->data,szTempB,iLen2);
+ p_szString->length = static_cast<ai_uint32>(iLen);
+ return true;
+ }
+ }
+ // check whether the 8.3 DOS name is matching
+ if (0 == ASSIMP_stricmp(info.cAlternateFileName,p_szString->data))
+ {
+ strcat(szTempB,info.cAlternateFileName);
+
+ // copy the result string back to the aiString
+ const size_t iLen = strlen(szTempB);
+ size_t iLen2 = iLen+1;
+ iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
+ memcpy(p_szString->data,szTempB,iLen2);
+ p_szString->length = static_cast<ai_uint32>(iLen);
+ return true;
+ }
+ }
+ }
+ }
+ while (FindNextFile(h, &info));
+
+ FindClose(h);
+ }
+ return false;
+}
+//-------------------------------------------------------------------------------
+int CMaterialManager::FindValidPath(aiString* p_szString)
+{
+ ai_assert(nullptr != p_szString);
+ aiString pcpy = *p_szString;
+ if ('*' == p_szString->data[0]) {
+ // '*' as first character indicates an embedded file
+ return 5;
+ }
+
+ // first check whether we can directly load the file
+ FILE* pFile = fopen(p_szString->data,"rb");
+ if (pFile) {
+ fclose(pFile);
+ }
+ else {
+ // check whether we can use the directory of the asset as relative base
+ char szTemp[MAX_PATH*2], tmp2[MAX_PATH*2];
+ strcpy(szTemp, g_szFileName);
+ strcpy(tmp2,szTemp);
+
+ char* szData = p_szString->data;
+ if (*szData == '\\' || *szData == '/')++szData;
+
+ char* szEnd = strrchr(szTemp,'\\');
+ if (!szEnd)
+ {
+ szEnd = strrchr(szTemp,'/');
+ if (!szEnd)szEnd = szTemp;
+ }
+ szEnd++;
+ *szEnd = 0;
+ strcat(szEnd,szData);
+
+
+ pFile = fopen(szTemp,"rb");
+ if (!pFile)
+ {
+ // convert the string to lower case
+ for (unsigned int i = 0;;++i)
+ {
+ if ('\0' == szTemp[i])break;
+ szTemp[i] = (char)tolower((unsigned char)szTemp[i]);
+ }
+
+ if(TryLongerPath(szTemp,p_szString))return 1;
+ *szEnd = 0;
+
+ // search common sub directories
+ strcat(szEnd,"tex\\");
+ strcat(szEnd,szData);
+
+ pFile = fopen(szTemp,"rb");
+ if (!pFile)
+ {
+ if(TryLongerPath(szTemp,p_szString))return 1;
+
+ *szEnd = 0;
+
+ strcat(szEnd,"textures\\");
+ strcat(szEnd,szData);
+
+ pFile = fopen(szTemp,"rb");
+ if (!pFile)
+ {
+ if(TryLongerPath(szTemp, p_szString))return 1;
+ }
+
+ // patch by mark sibly to look for textures files in the asset's base directory.
+ const char *path=pcpy.data;
+ const char *p=strrchr( path,'/' );
+ if( !p ) p=strrchr( path,'\\' );
+ if( p ){
+ char *q=strrchr( tmp2,'/' );
+ if( !q ) q=strrchr( tmp2,'\\' );
+ if( q ){
+ strcpy( q+1,p+1 );
+ if((pFile=fopen( tmp2,"r" )) != nullptr){
+ fclose( pFile );
+ strcpy(p_szString->data,tmp2);
+ p_szString->length = static_cast<ai_uint32>(strlen(tmp2));
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+ }
+ fclose(pFile);
+
+ // copy the result string back to the aiStr
+ const size_t len = strlen(szTemp);
+ size_t len2 = len+1;
+ len2 = len2 > MAXLEN ? MAXLEN : len2;
+ memcpy(p_szString->data, szTemp, len2);
+ p_szString->length = static_cast<ai_uint32>(len);
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CMaterialManager::LoadTexture(IDirect3DTexture9** p_ppiOut,aiString* szPath)
+{
+ ai_assert(nullptr != p_ppiOut);
+ ai_assert(nullptr != szPath);
+
+ *p_ppiOut = nullptr;
+
+ const std::string s = szPath->data;
+ TextureCache::iterator ff;
+ if ((ff = sCachedTextures.find(s)) != sCachedTextures.end()) {
+ *p_ppiOut = (*ff).second;
+ (*p_ppiOut)->AddRef();
+ return 1;
+ }
+
+ // first get a valid path to the texture
+ if( 5 == FindValidPath(szPath))
+ {
+ // embedded file. Find its index
+ unsigned int iIndex = atoi(szPath->data+1);
+ if (iIndex < g_pcAsset->pcScene->mNumTextures)
+ {
+ if (0 == g_pcAsset->pcScene->mTextures[iIndex]->mHeight)
+ {
+ // it is an embedded file ... don't need the file format hint,
+ // simply let D3DX load the file
+ D3DXIMAGE_INFO info;
+ if (FAILED(D3DXCreateTextureFromFileInMemoryEx(g_piDevice,
+ g_pcAsset->pcScene->mTextures[iIndex]->pcData,
+ g_pcAsset->pcScene->mTextures[iIndex]->mWidth,
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 1,
+ D3DUSAGE_AUTOGENMIPMAP,
+ D3DFMT_UNKNOWN,
+ D3DPOOL_MANAGED,
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ &info,
+ nullptr,
+ p_ppiOut)))
+ {
+ std::string sz = "[ERROR] Unable to load embedded texture (#1): ";
+ sz.append(szPath->data);
+ CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
+
+ this->SetDefaultTexture(p_ppiOut);
+ return 1;
+ }
+ }
+ else
+ {
+ // fill a new texture ...
+ if(FAILED(g_piDevice->CreateTexture(
+ g_pcAsset->pcScene->mTextures[iIndex]->mWidth,
+ g_pcAsset->pcScene->mTextures[iIndex]->mHeight,
+ 0,D3DUSAGE_AUTOGENMIPMAP,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,p_ppiOut,nullptr)))
+ {
+ std::string sz = "[ERROR] Unable to load embedded texture (#2): ";
+ sz.append(szPath->data);
+ CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
+
+ this->SetDefaultTexture(p_ppiOut);
+ return 1;
+ }
+
+ // now copy the data to it ... (assume non pow2 to be supported)
+ D3DLOCKED_RECT sLock;
+ (*p_ppiOut)->LockRect(0,&sLock,nullptr,0);
+
+ const aiTexel* pcData = g_pcAsset->pcScene->mTextures[iIndex]->pcData;
+
+ for (unsigned int y = 0; y < g_pcAsset->pcScene->mTextures[iIndex]->mHeight;++y)
+ {
+ memcpy(sLock.pBits,pcData,g_pcAsset->pcScene->mTextures[iIndex]->
+ mWidth *sizeof(aiTexel));
+ sLock.pBits = (char*)sLock.pBits + sLock.Pitch;
+ pcData += g_pcAsset->pcScene->mTextures[iIndex]->mWidth;
+ }
+ (*p_ppiOut)->UnlockRect(0);
+ (*p_ppiOut)->GenerateMipSubLevels();
+ }
+ sCachedTextures[s] = *p_ppiOut;
+ (*p_ppiOut)->AddRef();
+ return 1;
+ }
+ else
+ {
+ std::string sz = "[ERROR] Invalid index for embedded texture: ";
+ sz.append(szPath->data);
+ CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
+
+ SetDefaultTexture(p_ppiOut);
+ return 1;
+ }
+ }
+
+ // then call D3DX to load the texture
+ if (FAILED(D3DXCreateTextureFromFileEx(
+ g_piDevice,
+ szPath->data,
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ 0,
+ D3DFMT_A8R8G8B8,
+ D3DPOOL_MANAGED,
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ nullptr,
+ nullptr,
+ p_ppiOut)))
+ {
+ // error ... use the default texture instead
+ std::string sz = "[ERROR] Unable to load texture: ";
+ sz.append(szPath->data);
+ CLogDisplay::Instance().AddEntry(sz,D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
+
+ this->SetDefaultTexture(p_ppiOut);
+ }
+ sCachedTextures[s] = *p_ppiOut;
+ (*p_ppiOut)->AddRef();
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+void CMaterialManager::DeleteMaterial(AssetHelper::MeshHelper* pcIn)
+{
+ if (!pcIn || !pcIn->piEffect)return;
+ pcIn->piEffect->Release();
+
+ // release all textures associated with the material
+ if (pcIn->piDiffuseTexture)
+ {
+ pcIn->piDiffuseTexture->Release();
+ pcIn->piDiffuseTexture = nullptr;
+ }
+ if (pcIn->piSpecularTexture)
+ {
+ pcIn->piSpecularTexture->Release();
+ pcIn->piSpecularTexture = nullptr;
+ }
+ if (pcIn->piEmissiveTexture)
+ {
+ pcIn->piEmissiveTexture->Release();
+ pcIn->piEmissiveTexture = nullptr;
+ }
+ if (pcIn->piAmbientTexture)
+ {
+ pcIn->piAmbientTexture->Release();
+ pcIn->piAmbientTexture = nullptr;
+ }
+ if (pcIn->piOpacityTexture)
+ {
+ pcIn->piOpacityTexture->Release();
+ pcIn->piOpacityTexture = nullptr;
+ }
+ if (pcIn->piNormalTexture)
+ {
+ pcIn->piNormalTexture->Release();
+ pcIn->piNormalTexture = nullptr;
+ }
+ if (pcIn->piShininessTexture)
+ {
+ pcIn->piShininessTexture->Release();
+ pcIn->piShininessTexture = nullptr;
+ }
+ if (pcIn->piLightmapTexture)
+ {
+ pcIn->piLightmapTexture->Release();
+ pcIn->piLightmapTexture = nullptr;
+ }
+ pcIn->piEffect = nullptr;
+}
+//-------------------------------------------------------------------------------
+void CMaterialManager::HMtoNMIfNecessary(
+ IDirect3DTexture9* piTexture,
+ IDirect3DTexture9** piTextureOut,
+ bool bWasOriginallyHM)
+{
+ ai_assert(nullptr != piTexture);
+ ai_assert(nullptr != piTextureOut);
+
+ bool bMustConvert = false;
+ uintptr_t iElement = 3;
+
+ *piTextureOut = piTexture;
+
+ // Lock the input texture and try to determine its type.
+ // Criteria:
+ // - If r,g,b channel are identical it MUST be a height map
+ // - If one of the rgb channels is used and the others are empty it
+ // must be a height map, too.
+ // - If the average color of the whole image is something inside the
+ // purple range we can be sure it is a normal map
+ //
+ // - Otherwise we assume it is a normal map
+ // To increase performance we take not every pixel
+
+ D3DLOCKED_RECT sRect;
+ D3DSURFACE_DESC sDesc;
+ piTexture->GetLevelDesc(0,&sDesc);
+ if (FAILED(piTexture->LockRect(0,&sRect,nullptr,D3DLOCK_READONLY)))
+ {
+ return;
+ }
+ const int iPitchDiff = (int)sRect.Pitch - (int)(sDesc.Width * 4);
+
+ struct SColor
+ {
+ union
+ {
+ struct {unsigned char b,g,r,a;} data;
+ char _array[4];
+ };
+ };
+ const SColor* pcData = (const SColor*)sRect.pBits;
+
+ union
+ {
+ const SColor* pcPointer;
+ const unsigned char* pcCharPointer;
+ };
+ pcPointer = pcData;
+
+ // 1. If r,g,b channel are identical it MUST be a height map
+ bool bIsEqual = true;
+ for (unsigned int y = 0; y < sDesc.Height;++y)
+ {
+ for (unsigned int x = 0; x < sDesc.Width;++x)
+ {
+ if (pcPointer->data.b != pcPointer->data.r || pcPointer->data.b != pcPointer->data.g)
+ {
+ bIsEqual = false;
+ break;
+ }
+ pcPointer++;
+ }
+ pcCharPointer += iPitchDiff;
+ }
+ if (bIsEqual)bMustConvert = true;
+ else
+ {
+ // 2. If one of the rgb channels is used and the others are empty it
+ // must be a height map, too.
+ pcPointer = pcData;
+ while (*pcCharPointer == 0)pcCharPointer++;
+
+ iElement = (uintptr_t)(pcCharPointer - (unsigned char*)pcData) % 4;
+ unsigned int aiIndex[3] = {0,1,2};
+ if (3 != iElement)aiIndex[iElement] = 3;
+
+ pcPointer = pcData;
+
+ bIsEqual = true;
+ if (3 != iElement)
+ {
+ for (unsigned int y = 0; y < sDesc.Height;++y)
+ {
+ for (unsigned int x = 0; x < sDesc.Width;++x)
+ {
+ for (unsigned int ii = 0; ii < 3;++ii)
+ {
+ // don't take the alpha channel into account.
+ // if the texture was stored n RGB888 format D3DX has
+ // converted it to ARGB8888 format with a fixed alpha channel
+ if (aiIndex[ii] != 3 && pcPointer->_array[aiIndex[ii]] != 0)
+ {
+ bIsEqual = false;
+ break;
+ }
+ }
+ pcPointer++;
+ }
+ pcCharPointer += iPitchDiff;
+ }
+ if (bIsEqual)bMustConvert = true;
+ else
+ {
+ // If the average color of the whole image is something inside the
+ // purple range we can be sure it is a normal map
+
+ // (calculate the average color line per line to prevent overflows!)
+ pcPointer = pcData;
+ aiColor3D clrColor;
+ for (unsigned int y = 0; y < sDesc.Height;++y)
+ {
+ aiColor3D clrColorLine;
+ for (unsigned int x = 0; x < sDesc.Width;++x)
+ {
+ clrColorLine.r += pcPointer->data.r;
+ clrColorLine.g += pcPointer->data.g;
+ clrColorLine.b += pcPointer->data.b;
+ pcPointer++;
+ }
+ clrColor.r += clrColorLine.r /= (float)sDesc.Width;
+ clrColor.g += clrColorLine.g /= (float)sDesc.Width;
+ clrColor.b += clrColorLine.b /= (float)sDesc.Width;
+ pcCharPointer += iPitchDiff;
+ }
+ clrColor.r /= (float)sDesc.Height;
+ clrColor.g /= (float)sDesc.Height;
+ clrColor.b /= (float)sDesc.Height;
+
+ if (!(clrColor.b > 215 &&
+ clrColor.r > 100 && clrColor.r < 140 &&
+ clrColor.g > 100 && clrColor.g < 140))
+ {
+ // Unable to detect. Believe the original value obtained from the loader
+ if (bWasOriginallyHM)
+ {
+ bMustConvert = true;
+ }
+ }
+ }
+ }
+ }
+
+ piTexture->UnlockRect(0);
+
+ // if the input data is assumed to be a height map we'll
+ // need to convert it NOW
+ if (bMustConvert)
+ {
+ D3DSURFACE_DESC sDesc2;
+ piTexture->GetLevelDesc(0, &sDesc2);
+
+ IDirect3DTexture9* piTempTexture;
+ if(FAILED(g_piDevice->CreateTexture(
+ sDesc2.Width,
+ sDesc2.Height,
+ piTexture->GetLevelCount(),
+ sDesc2.Usage,
+ sDesc2.Format,
+ sDesc2.Pool, &piTempTexture, nullptr)))
+ {
+ CLogDisplay::Instance().AddEntry(
+ "[ERROR] Unable to create normal map texture",
+ D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
+ return;
+ }
+
+ DWORD dwFlags;
+ if (3 == iElement)dwFlags = D3DX_CHANNEL_LUMINANCE;
+ else if (2 == iElement)dwFlags = D3DX_CHANNEL_RED;
+ else if (1 == iElement)dwFlags = D3DX_CHANNEL_GREEN;
+ else /*if (0 == iElement)*/dwFlags = D3DX_CHANNEL_BLUE;
+
+ if(FAILED(D3DXComputeNormalMap(piTempTexture,
+ piTexture,nullptr,0,dwFlags,1.0f)))
+ {
+ CLogDisplay::Instance().AddEntry(
+ "[ERROR] Unable to compute normal map from height map",
+ D3DCOLOR_ARGB(0xFF,0xFF,0x0,0x0));
+
+ piTempTexture->Release();
+ return;
+ }
+ *piTextureOut = piTempTexture;
+ piTexture->Release();
+ }
+}
+//-------------------------------------------------------------------------------
+bool CMaterialManager::HasAlphaPixels(IDirect3DTexture9* piTexture)
+{
+ ai_assert(nullptr != piTexture);
+
+ D3DLOCKED_RECT sRect;
+ D3DSURFACE_DESC sDesc;
+ piTexture->GetLevelDesc(0,&sDesc);
+ if (FAILED(piTexture->LockRect(0,&sRect,nullptr,D3DLOCK_READONLY)))
+ {
+ return false;
+ }
+ const int iPitchDiff = (int)sRect.Pitch - (int)(sDesc.Width * 4);
+
+ struct SColor
+ {
+ unsigned char b,g,r,a;;
+ };
+ const SColor* pcData = (const SColor*)sRect.pBits;
+
+ union
+ {
+ const SColor* pcPointer;
+ const unsigned char* pcCharPointer;
+ };
+ pcPointer = pcData;
+ for (unsigned int y = 0; y < sDesc.Height;++y)
+ {
+ for (unsigned int x = 0; x < sDesc.Width;++x)
+ {
+ if (pcPointer->a != 0xFF)
+ {
+ piTexture->UnlockRect(0);
+ return true;
+ }
+ pcPointer++;
+ }
+ pcCharPointer += iPitchDiff;
+ }
+ piTexture->UnlockRect(0);
+ return false;
+}
+//-------------------------------------------------------------------------------
+int CMaterialManager::CreateMaterial(
+ AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSource)
+{
+ ai_assert(nullptr != pcMesh);
+ ai_assert(nullptr != pcSource);
+
+ ID3DXBuffer* piBuffer;
+
+ D3DXMACRO sMacro[64];
+
+ // extract all properties from the ASSIMP material structure
+ const aiMaterial* pcMat = g_pcAsset->pcScene->mMaterials[pcSource->mMaterialIndex];
+
+ //
+ // DIFFUSE COLOR --------------------------------------------------
+ //
+ if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_DIFFUSE,
+ (aiColor4D*)&pcMesh->vDiffuseColor))
+ {
+ pcMesh->vDiffuseColor.x = 1.0f;
+ pcMesh->vDiffuseColor.y = 1.0f;
+ pcMesh->vDiffuseColor.z = 1.0f;
+ pcMesh->vDiffuseColor.w = 1.0f;
+ }
+ //
+ // SPECULAR COLOR --------------------------------------------------
+ //
+ if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_SPECULAR,
+ (aiColor4D*)&pcMesh->vSpecularColor))
+ {
+ pcMesh->vSpecularColor.x = 1.0f;
+ pcMesh->vSpecularColor.y = 1.0f;
+ pcMesh->vSpecularColor.z = 1.0f;
+ pcMesh->vSpecularColor.w = 1.0f;
+ }
+ //
+ // AMBIENT COLOR --------------------------------------------------
+ //
+ if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_AMBIENT,
+ (aiColor4D*)&pcMesh->vAmbientColor))
+ {
+ pcMesh->vAmbientColor.x = 0.0f;
+ pcMesh->vAmbientColor.y = 0.0f;
+ pcMesh->vAmbientColor.z = 0.0f;
+ pcMesh->vAmbientColor.w = 1.0f;
+ }
+ //
+ // EMISSIVE COLOR -------------------------------------------------
+ //
+ if(AI_SUCCESS != aiGetMaterialColor(pcMat,AI_MATKEY_COLOR_EMISSIVE,
+ (aiColor4D*)&pcMesh->vEmissiveColor))
+ {
+ pcMesh->vEmissiveColor.x = 0.0f;
+ pcMesh->vEmissiveColor.y = 0.0f;
+ pcMesh->vEmissiveColor.z = 0.0f;
+ pcMesh->vEmissiveColor.w = 1.0f;
+ }
+
+ //
+ // Opacity --------------------------------------------------------
+ //
+ if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_OPACITY,&pcMesh->fOpacity))
+ {
+ pcMesh->fOpacity = 1.0f;
+ }
+
+ //
+ // Shading Model --------------------------------------------------
+ //
+ bool bDefault = false;
+ if(AI_SUCCESS != aiGetMaterialInteger(pcMat,AI_MATKEY_SHADING_MODEL,(int*)&pcMesh->eShadingMode ))
+ {
+ bDefault = true;
+ pcMesh->eShadingMode = aiShadingMode_Gouraud;
+ }
+
+
+ //
+ // Shininess ------------------------------------------------------
+ //
+ if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_SHININESS,&pcMesh->fShininess))
+ {
+ // assume 15 as default shininess
+ pcMesh->fShininess = 15.0f;
+ }
+ else if (bDefault)pcMesh->eShadingMode = aiShadingMode_Phong;
+
+
+ //
+ // Shininess strength ------------------------------------------------------
+ //
+ if(AI_SUCCESS != aiGetMaterialFloat(pcMat,AI_MATKEY_SHININESS_STRENGTH,&pcMesh->fSpecularStrength))
+ {
+ // assume 1.0 as default shininess strength
+ pcMesh->fSpecularStrength = 1.0f;
+ }
+
+ aiString szPath;
+
+ aiTextureMapMode mapU(aiTextureMapMode_Wrap),mapV(aiTextureMapMode_Wrap);
+
+ bool bib =false;
+ if (pcSource->mTextureCoords[0])
+ {
+
+ //
+ // DIFFUSE TEXTURE ------------------------------------------------
+ //
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_DIFFUSE(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piDiffuseTexture,&szPath);
+
+ aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0),(int*)&mapU);
+ aiGetMaterialInteger(pcMat,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0),(int*)&mapV);
+ }
+
+ //
+ // SPECULAR TEXTURE ------------------------------------------------
+ //
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SPECULAR(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piSpecularTexture,&szPath);
+ }
+
+ //
+ // OPACITY TEXTURE ------------------------------------------------
+ //
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_OPACITY(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piOpacityTexture,&szPath);
+ }
+ else
+ {
+ int flags = 0;
+ aiGetMaterialInteger(pcMat,AI_MATKEY_TEXFLAGS_DIFFUSE(0),&flags);
+
+ // try to find out whether the diffuse texture has any
+ // non-opaque pixels. If we find a few, use it as opacity texture
+ if (pcMesh->piDiffuseTexture && !(flags & aiTextureFlags_IgnoreAlpha) && HasAlphaPixels(pcMesh->piDiffuseTexture))
+ {
+ int iVal;
+
+ // NOTE: This special value is set by the tree view if the user
+ // manually removes the alpha texture from the view ...
+ if (AI_SUCCESS != aiGetMaterialInteger(pcMat,"no_a_from_d",0,0,&iVal))
+ {
+ pcMesh->piOpacityTexture = pcMesh->piDiffuseTexture;
+ pcMesh->piOpacityTexture->AddRef();
+ }
+ }
+ }
+
+ //
+ // AMBIENT TEXTURE ------------------------------------------------
+ //
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_AMBIENT(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piAmbientTexture,&szPath);
+ }
+
+ //
+ // EMISSIVE TEXTURE ------------------------------------------------
+ //
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_EMISSIVE(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piEmissiveTexture,&szPath);
+ }
+
+ //
+ // Shininess TEXTURE ------------------------------------------------
+ //
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_SHININESS(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piShininessTexture,&szPath);
+ }
+
+ //
+ // Lightmap TEXTURE ------------------------------------------------
+ //
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_LIGHTMAP(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piLightmapTexture,&szPath);
+ }
+
+
+ //
+ // NORMAL/HEIGHT MAP ------------------------------------------------
+ //
+ bool bHM = false;
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_NORMALS(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piNormalTexture,&szPath);
+ }
+ else
+ {
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_TEXTURE_HEIGHT(0),&szPath))
+ {
+ LoadTexture(&pcMesh->piNormalTexture,&szPath);
+ }
+ else bib = true;
+ bHM = true;
+ }
+
+ // normal/height maps are sometimes mixed up. Try to detect the type
+ // of the texture automatically
+ if (pcMesh->piNormalTexture)
+ {
+ HMtoNMIfNecessary(pcMesh->piNormalTexture, &pcMesh->piNormalTexture,bHM);
+ }
+ }
+
+ // check whether a global background texture is contained
+ // in this material. Some loaders set this value ...
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_GLOBAL_BACKGROUND_IMAGE,&szPath))
+ {
+ CBackgroundPainter::Instance().SetTextureBG(szPath.data);
+ }
+
+ // BUGFIX: If the shininess is 0.0f disable phong lighting
+ // This is a workaround for some meshes in the DX SDK (e.g. tiny.x)
+ // FIX: Added this check to the x-loader, but the line remains to
+ // catch other loader doing the same ...
+ if (0.0f == pcMesh->fShininess){
+ pcMesh->eShadingMode = aiShadingMode_Gouraud;
+ }
+
+ int two_sided = 0;
+ aiGetMaterialInteger(pcMat,AI_MATKEY_TWOSIDED,&two_sided);
+ pcMesh->twosided = (two_sided != 0);
+
+ // check whether we have already a material using the same
+ // shader. This will decrease loading time rapidly ...
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i)
+ {
+ if (g_pcAsset->pcScene->mMeshes[i] == pcSource)
+ {
+ break;
+ }
+ AssetHelper::MeshHelper* pc = g_pcAsset->apcMeshes[i];
+
+ if ((pcMesh->piDiffuseTexture != nullptr ? true : false) !=
+ (pc->piDiffuseTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->piSpecularTexture != nullptr ? true : false) !=
+ (pc->piSpecularTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->piAmbientTexture != nullptr ? true : false) !=
+ (pc->piAmbientTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->piEmissiveTexture != nullptr ? true : false) !=
+ (pc->piEmissiveTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->piNormalTexture != nullptr ? true : false) !=
+ (pc->piNormalTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->piOpacityTexture != nullptr ? true : false) !=
+ (pc->piOpacityTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->piShininessTexture != nullptr ? true : false) !=
+ (pc->piShininessTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->piLightmapTexture != nullptr ? true : false) !=
+ (pc->piLightmapTexture != nullptr ? true : false))
+ continue;
+ if ((pcMesh->eShadingMode != aiShadingMode_Gouraud ? true : false) !=
+ (pc->eShadingMode != aiShadingMode_Gouraud ? true : false))
+ continue;
+
+ if ((pcMesh->fOpacity != 1.0f ? true : false) != (pc->fOpacity != 1.0f ? true : false))
+ continue;
+
+ if (pcSource->HasBones() != g_pcAsset->pcScene->mMeshes[i]->HasBones())
+ continue;
+
+ // we can reuse this material
+ if (pc->piEffect)
+ {
+ pcMesh->piEffect = pc->piEffect;
+ pc->bSharedFX = pcMesh->bSharedFX = true;
+ pcMesh->piEffect->AddRef();
+ return 2;
+ }
+ }
+ m_iShaderCount++;
+
+ // build macros for the HLSL compiler
+ unsigned int iCurrent = 0;
+ if (pcMesh->piDiffuseTexture)
+ {
+ sMacro[iCurrent].Name = "AV_DIFFUSE_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+
+ if (mapU == aiTextureMapMode_Wrap)
+ sMacro[iCurrent].Name = "AV_WRAPU";
+ else if (mapU == aiTextureMapMode_Mirror)
+ sMacro[iCurrent].Name = "AV_MIRRORU";
+ else // if (mapU == aiTextureMapMode_Clamp)
+ sMacro[iCurrent].Name = "AV_CLAMPU";
+
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+
+
+ if (mapV == aiTextureMapMode_Wrap)
+ sMacro[iCurrent].Name = "AV_WRAPV";
+ else if (mapV == aiTextureMapMode_Mirror)
+ sMacro[iCurrent].Name = "AV_MIRRORV";
+ else // if (mapV == aiTextureMapMode_Clamp)
+ sMacro[iCurrent].Name = "AV_CLAMPV";
+
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+ if (pcMesh->piSpecularTexture)
+ {
+ sMacro[iCurrent].Name = "AV_SPECULAR_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+ if (pcMesh->piAmbientTexture)
+ {
+ sMacro[iCurrent].Name = "AV_AMBIENT_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+ if (pcMesh->piEmissiveTexture)
+ {
+ sMacro[iCurrent].Name = "AV_EMISSIVE_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+ char buff[32];
+ if (pcMesh->piLightmapTexture)
+ {
+ sMacro[iCurrent].Name = "AV_LIGHTMAP_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+
+ int idx;
+ if(AI_SUCCESS == aiGetMaterialInteger(pcMat,AI_MATKEY_UVWSRC_LIGHTMAP(0),&idx) && idx >= 1 && pcSource->mTextureCoords[idx]) {
+ sMacro[iCurrent].Name = "AV_TWO_UV";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+
+ sMacro[iCurrent].Definition = "IN.TexCoord1";
+ }
+ else sMacro[iCurrent].Definition = "IN.TexCoord0";
+ sMacro[iCurrent].Name = "AV_LIGHTMAP_TEXTURE_UV_COORD";
+
+ ++iCurrent;float f= 1.f;
+ aiGetMaterialFloat(pcMat,AI_MATKEY_TEXBLEND_LIGHTMAP(0),&f);
+ sprintf(buff,"%f",f);
+
+ sMacro[iCurrent].Name = "LM_STRENGTH";
+ sMacro[iCurrent].Definition = buff;
+ ++iCurrent;
+ }
+ if (pcMesh->piNormalTexture && !bib)
+ {
+ sMacro[iCurrent].Name = "AV_NORMAL_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+ if (pcMesh->piOpacityTexture)
+ {
+ sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+
+ if (pcMesh->piOpacityTexture == pcMesh->piDiffuseTexture)
+ {
+ sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK";
+ sMacro[iCurrent].Definition = "a";
+ ++iCurrent;
+ }
+ else
+ {
+ sMacro[iCurrent].Name = "AV_OPACITY_TEXTURE_REGISTER_MASK";
+ sMacro[iCurrent].Definition = "r";
+ ++iCurrent;
+ }
+ }
+
+ if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular)
+ {
+ sMacro[iCurrent].Name = "AV_SPECULAR_COMPONENT";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+
+ if (pcMesh->piShininessTexture)
+ {
+ sMacro[iCurrent].Name = "AV_SHININESS_TEXTURE";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+ }
+ if (1.0f != pcMesh->fOpacity)
+ {
+ sMacro[iCurrent].Name = "AV_OPACITY";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+
+ if( pcSource->HasBones())
+ {
+ sMacro[iCurrent].Name = "AV_SKINNING";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+
+ // If a cubemap is active, we'll need to lookup it for calculating
+ // a physically correct reflection
+ if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
+ {
+ sMacro[iCurrent].Name = "AV_SKYBOX_LOOKUP";
+ sMacro[iCurrent].Definition = "1";
+ ++iCurrent;
+ }
+ sMacro[iCurrent].Name = nullptr;
+ sMacro[iCurrent].Definition = nullptr;
+
+ // compile the shader
+ if(FAILED( D3DXCreateEffect(g_piDevice,
+ g_szMaterialShader.c_str(),(UINT)g_szMaterialShader.length(),
+ (const D3DXMACRO*)sMacro,nullptr,0,nullptr,&pcMesh->piEffect,&piBuffer)))
+ {
+ // failed to compile the shader
+ if( piBuffer)
+ {
+ MessageBox(g_hDlg,(LPCSTR)piBuffer->GetBufferPointer(),"HLSL",MB_OK);
+ piBuffer->Release();
+ }
+ // use the default material instead
+ if (g_piDefaultEffect)
+ {
+ pcMesh->piEffect = g_piDefaultEffect;
+ g_piDefaultEffect->AddRef();
+ }
+
+ // get the name of the material and use it in the log message
+ if(AI_SUCCESS == aiGetMaterialString(pcMat,AI_MATKEY_NAME,&szPath) &&
+ '\0' != szPath.data[0])
+ {
+ std::string sz = "[ERROR] Unable to load material: ";
+ sz.append(szPath.data);
+ CLogDisplay::Instance().AddEntry(sz);
+ }
+ else
+ {
+ CLogDisplay::Instance().AddEntry("Unable to load material: UNNAMED");
+ }
+ return 0;
+ } else
+ {
+ // use Fixed Function effect when working with shaderless cards
+ if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
+ pcMesh->piEffect->SetTechnique( "MaterialFX_FF");
+ }
+
+ if( piBuffer) piBuffer->Release();
+
+
+ // now commit all constants to the shader
+ //
+ // This is not necessary for shared shader. Shader constants for
+ // shared shaders are automatically recommited before the shader
+ // is being used for a particular mesh
+
+ if (1.0f != pcMesh->fOpacity)
+ pcMesh->piEffect->SetFloat("TRANSPARENCY",pcMesh->fOpacity);
+ if (pcMesh->eShadingMode != aiShadingMode_Gouraud && !g_sOptions.bNoSpecular)
+ {
+ pcMesh->piEffect->SetFloat("SPECULARITY",pcMesh->fShininess);
+ pcMesh->piEffect->SetFloat("SPECULAR_STRENGTH",pcMesh->fSpecularStrength);
+ }
+
+ pcMesh->piEffect->SetVector("DIFFUSE_COLOR",&pcMesh->vDiffuseColor);
+ pcMesh->piEffect->SetVector("SPECULAR_COLOR",&pcMesh->vSpecularColor);
+ pcMesh->piEffect->SetVector("AMBIENT_COLOR",&pcMesh->vAmbientColor);
+ pcMesh->piEffect->SetVector("EMISSIVE_COLOR",&pcMesh->vEmissiveColor);
+
+ if (pcMesh->piDiffuseTexture)
+ pcMesh->piEffect->SetTexture("DIFFUSE_TEXTURE",pcMesh->piDiffuseTexture);
+ if (pcMesh->piOpacityTexture)
+ pcMesh->piEffect->SetTexture("OPACITY_TEXTURE",pcMesh->piOpacityTexture);
+ if (pcMesh->piSpecularTexture)
+ pcMesh->piEffect->SetTexture("SPECULAR_TEXTURE",pcMesh->piSpecularTexture);
+ if (pcMesh->piAmbientTexture)
+ pcMesh->piEffect->SetTexture("AMBIENT_TEXTURE",pcMesh->piAmbientTexture);
+ if (pcMesh->piEmissiveTexture)
+ pcMesh->piEffect->SetTexture("EMISSIVE_TEXTURE",pcMesh->piEmissiveTexture);
+ if (pcMesh->piNormalTexture)
+ pcMesh->piEffect->SetTexture("NORMAL_TEXTURE",pcMesh->piNormalTexture);
+ if (pcMesh->piShininessTexture)
+ pcMesh->piEffect->SetTexture("SHININESS_TEXTURE",pcMesh->piShininessTexture);
+ if (pcMesh->piLightmapTexture)
+ pcMesh->piEffect->SetTexture("LIGHTMAP_TEXTURE",pcMesh->piLightmapTexture);
+
+ if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode()){
+ pcMesh->piEffect->SetTexture("lw_tex_envmap",CBackgroundPainter::Instance().GetTexture());
+ }
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CMaterialManager::SetupMaterial (
+ AssetHelper::MeshHelper* pcMesh,
+ const aiMatrix4x4& pcProj,
+ const aiMatrix4x4& aiMe,
+ const aiMatrix4x4& pcCam,
+ const aiVector3D& vPos)
+{
+ ai_assert(nullptr != pcMesh);
+ if (!pcMesh->piEffect)return 0;
+
+ ID3DXEffect* piEnd = pcMesh->piEffect;
+
+ piEnd->SetMatrix("WorldViewProjection",
+ (const D3DXMATRIX*)&pcProj);
+
+ piEnd->SetMatrix("World",(const D3DXMATRIX*)&aiMe);
+ piEnd->SetMatrix("WorldInverseTranspose",
+ (const D3DXMATRIX*)&pcCam);
+
+ D3DXVECTOR4 apcVec[5];
+ memset(apcVec,0,sizeof(apcVec));
+ apcVec[0].x = g_avLightDirs[0].x;
+ apcVec[0].y = g_avLightDirs[0].y;
+ apcVec[0].z = g_avLightDirs[0].z;
+ apcVec[0].w = 0.0f;
+ apcVec[1].x = g_avLightDirs[0].x * -1.0f;
+ apcVec[1].y = g_avLightDirs[0].y * -1.0f;
+ apcVec[1].z = g_avLightDirs[0].z * -1.0f;
+ apcVec[1].w = 0.0f;
+ D3DXVec4Normalize(&apcVec[0],&apcVec[0]);
+ D3DXVec4Normalize(&apcVec[1],&apcVec[1]);
+ piEnd->SetVectorArray("afLightDir",apcVec,5);
+
+ apcVec[0].x = ((g_avLightColors[0] >> 16) & 0xFF) / 255.0f;
+ apcVec[0].y = ((g_avLightColors[0] >> 8) & 0xFF) / 255.0f;
+ apcVec[0].z = ((g_avLightColors[0]) & 0xFF) / 255.0f;
+ apcVec[0].w = 1.0f;
+
+ if( g_sOptions.b3Lights)
+ {
+ apcVec[1].x = ((g_avLightColors[1] >> 16) & 0xFF) / 255.0f;
+ apcVec[1].y = ((g_avLightColors[1] >> 8) & 0xFF) / 255.0f;
+ apcVec[1].z = ((g_avLightColors[1]) & 0xFF) / 255.0f;
+ apcVec[1].w = 0.0f;
+ } else
+ {
+ apcVec[1].x = 0.0f;
+ apcVec[1].y = 0.0f;
+ apcVec[1].z = 0.0f;
+ apcVec[1].w = 0.0f;
+ }
+
+ apcVec[0] *= g_fLightIntensity;
+ apcVec[1] *= g_fLightIntensity;
+ piEnd->SetVectorArray("afLightColor",apcVec,5);
+
+ apcVec[0].x = ((g_avLightColors[2] >> 16) & 0xFF) / 255.0f;
+ apcVec[0].y = ((g_avLightColors[2] >> 8) & 0xFF) / 255.0f;
+ apcVec[0].z = ((g_avLightColors[2]) & 0xFF) / 255.0f;
+ apcVec[0].w = 1.0f;
+
+ apcVec[1].x = ((g_avLightColors[2] >> 16) & 0xFF) / 255.0f;
+ apcVec[1].y = ((g_avLightColors[2] >> 8) & 0xFF) / 255.0f;
+ apcVec[1].z = ((g_avLightColors[2]) & 0xFF) / 255.0f;
+ apcVec[1].w = 0.0f;
+
+ // FIX: light intensity doesn't apply to ambient color
+ //apcVec[0] *= g_fLightIntensity;
+ //apcVec[1] *= g_fLightIntensity;
+ piEnd->SetVectorArray("afLightColorAmbient",apcVec,5);
+
+
+ apcVec[0].x = vPos.x;
+ apcVec[0].y = vPos.y;
+ apcVec[0].z = vPos.z;
+ piEnd->SetVector( "vCameraPos",&apcVec[0]);
+
+ // if the effect instance is shared by multiple materials we need to
+ // recommit its whole state once per frame ...
+ if (pcMesh->bSharedFX)
+ {
+ // now commit all constants to the shader
+ if (1.0f != pcMesh->fOpacity)
+ pcMesh->piEffect->SetFloat("TRANSPARENCY",pcMesh->fOpacity);
+ if (pcMesh->eShadingMode != aiShadingMode_Gouraud)
+ {
+ pcMesh->piEffect->SetFloat("SPECULARITY",pcMesh->fShininess);
+ pcMesh->piEffect->SetFloat("SPECULAR_STRENGTH",pcMesh->fSpecularStrength);
+ }
+
+ pcMesh->piEffect->SetVector("DIFFUSE_COLOR",&pcMesh->vDiffuseColor);
+ pcMesh->piEffect->SetVector("SPECULAR_COLOR",&pcMesh->vSpecularColor);
+ pcMesh->piEffect->SetVector("AMBIENT_COLOR",&pcMesh->vAmbientColor);
+ pcMesh->piEffect->SetVector("EMISSIVE_COLOR",&pcMesh->vEmissiveColor);
+
+ if (pcMesh->piOpacityTexture)
+ pcMesh->piEffect->SetTexture("OPACITY_TEXTURE",pcMesh->piOpacityTexture);
+ if (pcMesh->piDiffuseTexture)
+ pcMesh->piEffect->SetTexture("DIFFUSE_TEXTURE",pcMesh->piDiffuseTexture);
+ if (pcMesh->piSpecularTexture)
+ pcMesh->piEffect->SetTexture("SPECULAR_TEXTURE",pcMesh->piSpecularTexture);
+ if (pcMesh->piAmbientTexture)
+ pcMesh->piEffect->SetTexture("AMBIENT_TEXTURE",pcMesh->piAmbientTexture);
+ if (pcMesh->piEmissiveTexture)
+ pcMesh->piEffect->SetTexture("EMISSIVE_TEXTURE",pcMesh->piEmissiveTexture);
+ if (pcMesh->piNormalTexture)
+ pcMesh->piEffect->SetTexture("NORMAL_TEXTURE",pcMesh->piNormalTexture);
+ if (pcMesh->piShininessTexture)
+ pcMesh->piEffect->SetTexture("SHININESS_TEXTURE",pcMesh->piShininessTexture);
+ if (pcMesh->piLightmapTexture)
+ pcMesh->piEffect->SetTexture("LIGHTMAP_TEXTURE",pcMesh->piLightmapTexture);
+
+ if (CBackgroundPainter::TEXTURE_CUBE == CBackgroundPainter::Instance().GetMode())
+ {
+ piEnd->SetTexture("lw_tex_envmap",CBackgroundPainter::Instance().GetTexture());
+ }
+ }
+
+ // disable culling, if necessary
+ if (pcMesh->twosided && g_sOptions.bCulling) {
+ g_piDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
+ }
+
+ // setup the correct shader technique to be used for drawing
+ if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
+ {
+ g_piDefaultEffect->SetTechnique( "MaterialFXSpecular_FF");
+ } else
+ if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0) || g_sOptions.bLowQuality)
+ {
+ if (g_sOptions.b3Lights)
+ piEnd->SetTechnique("MaterialFXSpecular_PS20_D2");
+ else piEnd->SetTechnique("MaterialFXSpecular_PS20_D1");
+ }
+ else
+ {
+ if (g_sOptions.b3Lights)
+ piEnd->SetTechnique("MaterialFXSpecular_D2");
+ else piEnd->SetTechnique("MaterialFXSpecular_D1");
+ }
+
+ // activate the effect
+ UINT dwPasses = 0;
+ piEnd->Begin(&dwPasses,0);
+ piEnd->BeginPass(0);
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CMaterialManager::EndMaterial (AssetHelper::MeshHelper* pcMesh)
+{
+ ai_assert(nullptr != pcMesh);
+ if (!pcMesh->piEffect)return 0;
+
+ // end the effect
+ pcMesh->piEffect->EndPass();
+ pcMesh->piEffect->End();
+
+ // re-enable culling if necessary
+ if (pcMesh->twosided && g_sOptions.bCulling) {
+ g_piDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
+ }
+
+ return 1;
+}
+
+} // end namespace AssimpView
diff --git a/libs/assimp/tools/assimp_view/MaterialManager.h b/libs/assimp/tools/assimp_view/MaterialManager.h
new file mode 100644
index 0000000..625cae2
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/MaterialManager.h
@@ -0,0 +1,195 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#pragma once
+
+#include <map>
+
+#include "AssetHelper.h"
+
+namespace AssimpView {
+
+//-------------------------------------------------------------------------------
+/* Helper class to create, access and destroy materials
+ */
+//-------------------------------------------------------------------------------
+class CMaterialManager {
+ friend class CDisplay;
+
+public:
+ //------------------------------------------------------------------
+ // Singleton accessors
+ inline static CMaterialManager &Instance() {
+ return s_cInstance;
+ }
+
+ //------------------------------------------------------------------
+ // Delete all resources of a given material
+ //
+ // Must be called before CreateMaterial() to prevent memory leaking
+ void DeleteMaterial(AssetHelper::MeshHelper *pcIn);
+
+ /// @brief Create the material for a mesh.
+ ///
+ /// The function checks whether an identical shader is already in use.
+ /// A shader is considered to be identical if it has the same input
+ /// signature and takes the same number of texture channels.
+ int CreateMaterial(AssetHelper::MeshHelper *pcMesh, const aiMesh *pcSource);
+
+ /// @brief Setup the material for a given mesh.
+ /// @param pcMesh Mesh to be rendered
+ /// @param pcProj Projection matrix
+ /// @param aiMe Current world matrix
+ /// @param pcCam Camera matrix
+ /// @param vPos Position of the camera
+ /// @return 0 if successful.
+ int SetupMaterial(AssetHelper::MeshHelper *pcMesh,
+ const aiMatrix4x4 &pcProj,
+ const aiMatrix4x4 &aiMe,
+ const aiMatrix4x4 &pcCam,
+ const aiVector3D &vPos);
+
+ //------------------------------------------------------------------
+ // End the material for a given mesh
+ // Called after mesh rendering is complete
+ // pcMesh Mesh object
+ int EndMaterial(AssetHelper::MeshHelper *pcMesh);
+
+ //------------------------------------------------------------------
+ // Recreate all specular materials depending on the current
+ // specularity settings
+ //
+ // Diffuse-only materials are ignored.
+ // Must be called after specular highlights have been toggled
+ int UpdateSpecularMaterials();
+
+ //------------------------------------------------------------------
+ // find a valid path to a texture file
+ //
+ // Handle 8.3 syntax correctly, search the environment of the
+ // executable and the asset for a texture with a name very similar
+ // to a given one
+ int FindValidPath(aiString *p_szString);
+
+ //------------------------------------------------------------------
+ // Load a texture into memory and create a native D3D texture resource
+ //
+ // The function tries to find a valid path for a texture
+ int LoadTexture(IDirect3DTexture9 **p_ppiOut, aiString *szPath);
+
+ //------------------------------------------------------------------
+ // Getter for m_iShaderCount
+ //
+ inline unsigned int GetShaderCount() {
+ return this->m_iShaderCount;
+ }
+
+ //------------------------------------------------------------------
+ // Reset the state of the class
+ // Called whenever a new asset is loaded
+ inline void Reset() {
+ m_iShaderCount = 0;
+ for (auto & sCachedTexture : sCachedTextures) {
+ sCachedTexture.second->Release();
+ }
+ sCachedTextures.clear();
+ }
+
+private:
+ // The default constructor
+ CMaterialManager() :
+ m_iShaderCount(0),
+ sDefaultTexture() {
+ // empty
+ }
+
+ // Destructor, private.
+ ~CMaterialManager() {
+ if (sDefaultTexture) {
+ sDefaultTexture->Release();
+ }
+ Reset();
+ }
+
+ //------------------------------------------------------------------
+ // find a valid path to a texture file
+ //
+ // Handle 8.3 syntax correctly, search the environment of the
+ // executable and the asset for a texture with a name very similar
+ // to a given one
+ bool TryLongerPath(char *szTemp, aiString *p_szString);
+
+ //------------------------------------------------------------------
+ // Setup the default texture for a texture channel
+ //
+ // Generates a default checker pattern for a texture
+ int SetDefaultTexture(IDirect3DTexture9 **p_ppiOut);
+
+ //------------------------------------------------------------------
+ // Convert a height map to a normal map if necessary
+ //
+ // The function tries to detect the type of a texture automatically.
+ // However, this won't work in every case.
+ void HMtoNMIfNecessary(IDirect3DTexture9 *piTexture,
+ IDirect3DTexture9 **piTextureOut,
+ bool bWasOriginallyHM = true);
+
+ //------------------------------------------------------------------
+ // Search for non-opaque pixels in a texture
+ //
+ // A pixel is considered to be non-opaque if its alpha value is
+ // less than 255
+ //------------------------------------------------------------------
+ bool HasAlphaPixels(IDirect3DTexture9 *piTexture);
+
+private:
+ static CMaterialManager s_cInstance;
+
+ // Specifies the number of different shaders generated for
+ // the current asset. This number is incremented by CreateMaterial()
+ // each time a shader isn't found in cache and needs to be created
+ unsigned int m_iShaderCount;
+ IDirect3DTexture9 *sDefaultTexture;
+ using TextureCache = std::map<std::string, IDirect3DTexture9 *>;
+ TextureCache sCachedTextures;
+};
+
+} // namespace AssimpView
diff --git a/libs/assimp/tools/assimp_view/MeshRenderer.cpp b/libs/assimp/tools/assimp_view/MeshRenderer.cpp
new file mode 100644
index 0000000..655e99d
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/MeshRenderer.cpp
@@ -0,0 +1,167 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+
+#include <map>
+#include <functional>
+
+namespace AssimpView {
+
+CMeshRenderer CMeshRenderer::s_cInstance;
+
+//-------------------------------------------------------------------------------
+int CMeshRenderer::DrawUnsorted(unsigned int iIndex) {
+ ai_assert(iIndex < g_pcAsset->pcScene->mNumMeshes);
+
+ // set vertex and index buffer
+ g_piDevice->SetStreamSource(0,g_pcAsset->apcMeshes[iIndex]->piVB,0,
+ sizeof(AssetHelper::Vertex));
+
+ g_piDevice->SetIndices(g_pcAsset->apcMeshes[iIndex]->piIB);
+
+ D3DPRIMITIVETYPE type = D3DPT_POINTLIST;
+ switch (g_pcAsset->pcScene->mMeshes[iIndex]->mPrimitiveTypes) {
+ case aiPrimitiveType_POINT:
+ type = D3DPT_POINTLIST;
+ break;
+ case aiPrimitiveType_LINE:
+ type = D3DPT_LINELIST;
+ break;
+ case aiPrimitiveType_TRIANGLE:
+ type = D3DPT_TRIANGLELIST;
+ break;
+ }
+ // and draw the mesh
+ g_piDevice->DrawIndexedPrimitive(type,
+ 0,0,
+ g_pcAsset->pcScene->mMeshes[iIndex]->mNumVertices,0,
+ g_pcAsset->pcScene->mMeshes[iIndex]->mNumFaces);
+
+ return 1;
+}
+//-------------------------------------------------------------------------------
+int CMeshRenderer::DrawSorted(unsigned int iIndex,const aiMatrix4x4& mWorld) {
+ ai_assert(iIndex < g_pcAsset->pcScene->mNumMeshes);
+
+ AssetHelper::MeshHelper* pcHelper = g_pcAsset->apcMeshes[iIndex];
+ const aiMesh* pcMesh = g_pcAsset->pcScene->mMeshes[iIndex];
+
+ if (!pcHelper || !pcMesh || !pcHelper->piIB)
+ return -5;
+
+ if (pcMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE || pcMesh->HasBones() || g_sOptions.bNoAlphaBlending)
+ return DrawUnsorted(iIndex);
+
+
+ // compute the position of the camera in worldspace
+ aiMatrix4x4 mWorldInverse = mWorld;
+ mWorldInverse.Inverse();
+ mWorldInverse.Transpose();
+ const aiVector3D vLocalCamera = mWorldInverse * g_sCamera.vPos;
+
+ // well ... this is really funny now. We must compute their distance
+ // from the camera. We take the average distance of a face and add it
+ // to a map which sorts it
+ std::map<float,unsigned int, std::greater<float> > smap;
+
+ for (unsigned int iFace = 0; iFace < pcMesh->mNumFaces;++iFace)
+ {
+ const aiFace* pcFace = &pcMesh->mFaces[iFace];
+ float fDist = 0.0f;
+ for (unsigned int c = 0; c < 3;++c)
+ {
+ aiVector3D vPos = pcMesh->mVertices[pcFace->mIndices[c]];
+ vPos -= vLocalCamera;
+ fDist += vPos.SquareLength();
+ }
+ smap.insert(std::pair<float, unsigned int>(fDist,iFace));
+ }
+
+ // now we can lock the index buffer and rebuild it
+ D3DINDEXBUFFER_DESC sDesc;
+ pcHelper->piIB->GetDesc(&sDesc);
+
+ if (D3DFMT_INDEX16 == sDesc.Format)
+ {
+ uint16_t* aiIndices;
+ pcHelper->piIB->Lock(0,0,(void**)&aiIndices,D3DLOCK_DISCARD);
+
+ for (std::map<float,unsigned int, std::greater<float> >::const_iterator
+ i = smap.begin();
+ i != smap.end();++i)
+ {
+ const aiFace* pcFace = &pcMesh->mFaces[(*i).second];
+ *aiIndices++ = (uint16_t)pcFace->mIndices[0];
+ *aiIndices++ = (uint16_t)pcFace->mIndices[1];
+ *aiIndices++ = (uint16_t)pcFace->mIndices[2];
+ }
+ }
+ else if (D3DFMT_INDEX32 == sDesc.Format)
+ {
+ uint32_t* aiIndices;
+ pcHelper->piIB->Lock(0,0,(void**)&aiIndices,D3DLOCK_DISCARD);
+
+ for (std::map<float,unsigned int, std::greater<float> >::const_iterator
+ i = smap.begin();
+ i != smap.end();++i)
+ {
+ const aiFace* pcFace = &pcMesh->mFaces[(*i).second];
+ *aiIndices++ = (uint32_t)pcFace->mIndices[0];
+ *aiIndices++ = (uint32_t)pcFace->mIndices[1];
+ *aiIndices++ = (uint32_t)pcFace->mIndices[2];
+ }
+ }
+ pcHelper->piIB->Unlock();
+
+ // set vertex and index buffer
+ g_piDevice->SetStreamSource(0,pcHelper->piVB,0,sizeof(AssetHelper::Vertex));
+
+ // and draw the mesh
+ g_piDevice->SetIndices(pcHelper->piIB);
+ g_piDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
+ 0,0,
+ pcMesh->mNumVertices,0,
+ pcMesh->mNumFaces);
+
+ return 1;
+}
+}
diff --git a/libs/assimp/tools/assimp_view/MeshRenderer.h b/libs/assimp/tools/assimp_view/MeshRenderer.h
new file mode 100644
index 0000000..d756a99
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/MeshRenderer.h
@@ -0,0 +1,99 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_MESH_RENDERER_H_INCLUDED)
+#define AV_MESH_RENDERER_H_INCLUDED
+
+namespace AssimpView {
+
+
+ //-------------------------------------------------------------------------------
+ /* Helper class tp render meshes
+ */
+ //-------------------------------------------------------------------------------
+ class CMeshRenderer
+ {
+ private:
+
+ // default constructor
+ CMeshRenderer()
+
+ {
+ // no other members to initialize
+ }
+
+ public:
+
+ //------------------------------------------------------------------
+ // Singleton accessors
+ static CMeshRenderer s_cInstance;
+ inline static CMeshRenderer& Instance()
+ {
+ return s_cInstance;
+ }
+
+
+ //------------------------------------------------------------------
+ // Draw a mesh in the global mesh list using the current pipeline state
+ // iIndex Index of the mesh to be drawn
+ //
+ // The function draws all faces in order, regardless of their distance
+ int DrawUnsorted( unsigned int iIndex );
+
+ //------------------------------------------------------------------
+ // Draw a mesh in the global mesh list using the current pipeline state
+ // iIndex Index of the mesh to be drawn
+ //
+ // The method sorts all vertices by their distance (back to front)
+ //
+ // mWorld World matrix for the node
+ int DrawSorted( unsigned int iIndex,
+ const aiMatrix4x4& mWorld );
+
+
+
+ private:
+
+
+ };
+
+}
+#endif //!! include guard
diff --git a/libs/assimp/tools/assimp_view/MessageProc.cpp b/libs/assimp/tools/assimp_view/MessageProc.cpp
new file mode 100644
index 0000000..e51c829
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/MessageProc.cpp
@@ -0,0 +1,2434 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+#include <assimp/Exporter.hpp>
+#include <algorithm>
+
+#include <windowsx.h>
+#include <commdlg.h>
+
+#ifdef __MINGW32__
+# include <mmsystem.h>
+#else
+# include <timeapi.h>
+#endif
+
+namespace AssimpView {
+
+using namespace Assimp;
+
+// Static array to keep custom color values
+COLORREF g_aclCustomColors[16] = {0};
+
+// Global registry key
+HKEY g_hRegistry = nullptr;
+
+// list of previous files (always 5)
+std::vector<std::string> g_aPreviousFiles;
+
+// history menu item
+HMENU g_hHistoryMenu = nullptr;
+
+float g_fACMR = 3.0f;
+
+#define AI_VIEW_NUM_RECENT_FILES 0x8
+#define AI_VIEW_RECENT_FILE_ID(_n_) (5678 + _n_)
+
+#define AI_VIEW_EXPORT_FMT_BASE 7912
+#define AI_VIEW_EXPORT_FMT_ID(_n_) (AI_VIEW_EXPORT_FMT_BASE + _n_)
+
+void UpdateHistory();
+void SaveHistory();
+
+//-------------------------------------------------------------------------------
+// Setup file associations for all formats supported by the library
+//
+// File associations are registered in HKCU\Software\Classes. They might
+// be overwritten by global file associations.
+//-------------------------------------------------------------------------------
+void MakeFileAssociations() {
+ char szTemp2[MAX_PATH];
+ char szTemp[MAX_PATH + 10];
+
+ GetModuleFileName(nullptr,szTemp2,MAX_PATH);
+ sprintf(szTemp,"%s %%1",szTemp2);
+
+ HKEY hRegistry = nullptr;
+
+ aiString list, tmp;
+ aiGetExtensionList(&list);
+ tmp = list;
+
+ const char* sz = strtok(list.data,";");
+ do {
+ char buf[256];
+ ai_assert(sz[0] == '*');
+ sprintf(buf,"Software\\Classes\\%s",sz+1);
+
+ RegCreateKeyEx(HKEY_CURRENT_USER,buf,0,nullptr,0,KEY_ALL_ACCESS, nullptr, &hRegistry,nullptr);
+ RegSetValueEx(hRegistry,"",0,REG_SZ,(const BYTE*)"ASSIMPVIEW_CLASS",(DWORD)strlen("ASSIMPVIEW_CLASS")+1);
+ RegCloseKey(hRegistry);
+ } while ((sz = strtok(nullptr,";")) != nullptr);
+
+ RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Classes\\ASSIMPVIEW_CLASS",0,nullptr,0,KEY_ALL_ACCESS, nullptr, &hRegistry,nullptr);
+ RegCloseKey(hRegistry);
+
+ RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Classes\\ASSIMPVIEW_CLASS\\shell\\open\\command",0,nullptr,0,KEY_ALL_ACCESS, nullptr, &hRegistry,nullptr);
+ RegSetValueEx(hRegistry,"",0,REG_SZ,(const BYTE*)szTemp,(DWORD)strlen(szTemp)+1);
+ RegCloseKey(hRegistry);
+
+ CLogDisplay::Instance().AddEntry("[OK] File associations have been registered",
+ D3DCOLOR_ARGB(0xFF,0,0xFF,0));
+
+ CLogDisplay::Instance().AddEntry(tmp.data,D3DCOLOR_ARGB(0xFF,0,0xFF,0));
+}
+
+//-------------------------------------------------------------------------------
+// Handle command line parameters
+//
+// The function loads an asset specified on the command line as first argument
+// Other command line parameters are not handled
+//-------------------------------------------------------------------------------
+void HandleCommandLine(char* p_szCommand) {
+ char* sz = p_szCommand;
+ //bool bQuak = false;
+
+ if (strlen(sz) < 2) {
+ return;
+ }
+
+ if (*sz == '\"') {
+ char* sz2 = strrchr(sz,'\"');
+ if (sz2)*sz2 = 0;
+ sz++; // skip the starting quote
+ }
+
+ strcpy( g_szFileName, sz );
+ LoadAsset();
+
+ // update the history
+ UpdateHistory();
+
+ // Save the list of previous files to the registry
+ SaveHistory();
+}
+
+//-------------------------------------------------------------------------------
+// Load the light colors from the registry
+//-------------------------------------------------------------------------------
+void LoadLightColors() {
+ DWORD dwTemp = 4;
+ RegQueryValueEx(g_hRegistry,"LightColor0",nullptr,nullptr, (BYTE*)&g_avLightColors[0],&dwTemp);
+ RegQueryValueEx(g_hRegistry,"LightColor1",nullptr,nullptr, (BYTE*)&g_avLightColors[1],&dwTemp);
+ RegQueryValueEx(g_hRegistry,"LightColor2",nullptr,nullptr, (BYTE*)&g_avLightColors[2],&dwTemp);
+}
+
+//-------------------------------------------------------------------------------
+// Save the light colors to the registry
+//-------------------------------------------------------------------------------
+void SaveLightColors() {
+ RegSetValueExA(g_hRegistry,"LightColor0",0,REG_DWORD,(const BYTE*)&g_avLightColors[0],4);
+ RegSetValueExA(g_hRegistry,"LightColor1",0,REG_DWORD,(const BYTE*)&g_avLightColors[1],4);
+ RegSetValueExA(g_hRegistry,"LightColor2",0,REG_DWORD,(const BYTE*)&g_avLightColors[2],4);
+}
+
+//-------------------------------------------------------------------------------
+// Save the checker pattern colors to the registry
+//-------------------------------------------------------------------------------
+void SaveCheckerPatternColors() {
+ // we have it as float4. save it as binary value --.
+ RegSetValueExA(g_hRegistry,"CheckerPattern0",0,REG_BINARY,
+ (const BYTE*)CDisplay::Instance().GetFirstCheckerColor(),
+ sizeof(D3DXVECTOR3));
+
+ RegSetValueExA(g_hRegistry,"CheckerPattern1",0,REG_BINARY,
+ (const BYTE*)CDisplay::Instance().GetSecondCheckerColor(),
+ sizeof(D3DXVECTOR3));
+}
+
+//-------------------------------------------------------------------------------
+// Load the checker pattern colors from the registry
+//-------------------------------------------------------------------------------
+void LoadCheckerPatternColors() {
+ DWORD dwTemp = sizeof(D3DXVECTOR3);
+ RegQueryValueEx(g_hRegistry,"CheckerPattern0",nullptr,nullptr,
+ (BYTE*) /* jep, this is evil */ CDisplay::Instance().GetFirstCheckerColor(),&dwTemp);
+
+ RegQueryValueEx(g_hRegistry,"CheckerPattern1",nullptr,nullptr,
+ (BYTE*) /* jep, this is evil */ CDisplay::Instance().GetSecondCheckerColor(),&dwTemp);
+}
+
+//-------------------------------------------------------------------------------
+// Changed pp setup
+//-------------------------------------------------------------------------------
+void UpdatePPSettings() {
+ DWORD dwValue = ppsteps;
+ RegSetValueExA(g_hRegistry,"PostProcessing",0,REG_DWORD,(const BYTE*)&dwValue,4);
+ UpdateWindow(g_hDlg);
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "Display Normals" state
+//-------------------------------------------------------------------------------
+void ToggleNormals() {
+ g_sOptions.bRenderNormals = !g_sOptions.bRenderNormals;
+
+ // store this in the registry, too
+ DWORD dwValue = 0;
+ if (g_sOptions.bRenderNormals)dwValue = 1;
+ RegSetValueExA(g_hRegistry,"RenderNormals",0,REG_DWORD,(const BYTE*)&dwValue,4);
+}
+
+static void storeRegKey(bool option, LPCSTR name) {
+ // store this in the registry, too
+ DWORD dwValue = 0;
+ if (option) {
+ dwValue = 1;
+ }
+ RegSetValueExA(g_hRegistry, name, 0, REG_DWORD, (const BYTE*)&dwValue, 4);
+
+}
+//-------------------------------------------------------------------------------
+// Toggle the "AutoRotate" state
+//-------------------------------------------------------------------------------
+void ToggleAutoRotate() {
+ g_sOptions.bRotate = !g_sOptions.bRotate;
+ storeRegKey(g_sOptions.bRotate, "AutoRotate");
+ UpdateWindow(g_hDlg);
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "FPS" state
+//-------------------------------------------------------------------------------
+void ToggleFPSView() {
+ g_bFPSView = !g_bFPSView;
+ SetupFPSView();
+ storeRegKey(g_bFPSView, "FPSView");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "2 Light sources" state
+//-------------------------------------------------------------------------------
+void ToggleMultipleLights() {
+ g_sOptions.b3Lights = !g_sOptions.b3Lights;
+ storeRegKey(g_sOptions.b3Lights, "MultipleLights");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "LightRotate" state
+//-------------------------------------------------------------------------------
+void ToggleLightRotate() {
+ g_sOptions.bLightRotate = !g_sOptions.bLightRotate;
+ storeRegKey(g_sOptions.bLightRotate, "LightRotate");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "NoTransparency" state
+//-------------------------------------------------------------------------------
+void ToggleTransparency() {
+ g_sOptions.bNoAlphaBlending = !g_sOptions.bNoAlphaBlending;
+ storeRegKey(g_sOptions.bNoAlphaBlending, "NoTransparency");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "LowQuality" state
+//-------------------------------------------------------------------------------
+void ToggleLowQuality() {
+ g_sOptions.bLowQuality = !g_sOptions.bLowQuality;
+ storeRegKey(g_sOptions.bLowQuality, "LowQuality");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "Specular" state
+//-------------------------------------------------------------------------------
+void ToggleSpecular() {
+ g_sOptions.bNoSpecular = !g_sOptions.bNoSpecular;
+
+ storeRegKey(g_sOptions.bNoSpecular, "NoSpecular");
+
+ // update all specular materials
+ CMaterialManager::Instance().UpdateSpecularMaterials();
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "RenderMats" state
+//-------------------------------------------------------------------------------
+void ToggleMats() {
+ g_sOptions.bRenderMats = !g_sOptions.bRenderMats;
+
+ storeRegKey(g_sOptions.bRenderMats, "RenderMats");
+
+ // update all specular materials
+ CMaterialManager::Instance().UpdateSpecularMaterials();
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "Culling" state
+//-------------------------------------------------------------------------------
+void ToggleCulling() {
+ g_sOptions.bCulling = !g_sOptions.bCulling;
+ storeRegKey(g_sOptions.bCulling, "Culling");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "Skeleton" state
+//-------------------------------------------------------------------------------
+void ToggleSkeleton() {
+ g_sOptions.bSkeleton = !g_sOptions.bSkeleton;
+ storeRegKey(g_sOptions.bSkeleton, "Skeleton");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "WireFrame" state
+//-------------------------------------------------------------------------------
+void ToggleWireFrame() {
+ if (g_sOptions.eDrawMode == RenderOptions::WIREFRAME) {
+ g_sOptions.eDrawMode = RenderOptions::NORMAL;
+ } else {
+ g_sOptions.eDrawMode = RenderOptions::WIREFRAME;
+ }
+
+ storeRegKey(RenderOptions::WIREFRAME == g_sOptions.eDrawMode, "Wireframe");
+}
+
+//-------------------------------------------------------------------------------
+// Toggle the "MultiSample" state
+//-------------------------------------------------------------------------------
+void ToggleMS() {
+ g_sOptions.bMultiSample = !g_sOptions.bMultiSample;
+ DeleteAssetData();
+ ShutdownDevice();
+ if (0 == CreateDevice()) {
+ CLogDisplay::Instance().AddEntry(
+ "[ERROR] Failed to toggle MultiSampling mode");
+ g_sOptions.bMultiSample = !g_sOptions.bMultiSample;
+ CreateDevice();
+ }
+ CreateAssetData();
+
+ if (g_sOptions.bMultiSample) {
+ CLogDisplay::Instance().AddEntry(
+ "[OK] Changed MultiSampling mode to the maximum value for this device");
+ } else {
+ CLogDisplay::Instance().AddEntry(
+ "[OK] MultiSampling has been disabled");
+ }
+
+ storeRegKey(g_sOptions.bMultiSample, "MultiSampling");
+}
+
+//-------------------------------------------------------------------------------
+// Expand or collapse the UI
+//-------------------------------------------------------------------------------
+void ToggleUIState() {
+ // adjust the size
+ RECT sRect;
+ GetWindowRect(g_hDlg,&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ RECT sRect2;
+ GetWindowRect(GetDlgItem ( g_hDlg, IDC_BLUBB ),&sRect2);
+ sRect2.left -= sRect.left;
+ sRect2.top -= sRect.top;
+
+ if (BST_UNCHECKED == IsDlgButtonChecked(g_hDlg,IDC_BLUBB)) {
+ SetWindowPos(g_hDlg,nullptr,0,0,sRect.right-214,sRect.bottom,
+ SWP_NOMOVE | SWP_NOZORDER);
+
+ SetWindowText(GetDlgItem(g_hDlg,IDC_BLUBB),">>");
+ storeRegKey(false, "MultiSampling");
+ } else {
+ SetWindowPos(g_hDlg,nullptr,0,0,sRect.right+214,sRect.bottom,
+ SWP_NOMOVE | SWP_NOZORDER);
+
+ storeRegKey(true, "LastUIState");
+ SetWindowText(GetDlgItem(g_hDlg,IDC_BLUBB),"<<");
+ }
+ UpdateWindow(g_hDlg);
+}
+
+//-------------------------------------------------------------------------------
+// Load the background texture for the viewer
+//-------------------------------------------------------------------------------
+void LoadBGTexture() {
+ char szFileName[MAX_PATH];
+
+ DWORD dwTemp = MAX_PATH;
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"TextureSrc",nullptr,nullptr, (BYTE*)szFileName,&dwTemp)) {
+ // Key was not found. Use C:
+ strcpy(szFileName,"");
+ } else {
+ // need to remove the file name
+ char* sz = strrchr(szFileName,'\\');
+ if (!sz)
+ sz = strrchr(szFileName,'/');
+ if (sz)
+ *sz = 0;
+ }
+ OPENFILENAME sFilename1 = {
+ sizeof(OPENFILENAME),
+ g_hDlg,GetModuleHandle(nullptr),
+ "Textures\0*.png;*.dds;*.tga;*.bmp;*.tif;*.ppm;*.ppx;*.jpg;*.jpeg;*.exr\0*.*\0",
+ nullptr, 0, 1,
+ szFileName, MAX_PATH, nullptr, 0, nullptr,
+ "Open texture as background",
+ OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
+ 0, 1, ".jpg", 0, nullptr, nullptr
+ };
+ if(GetOpenFileName(&sFilename1) == 0) return;
+
+ // Now store the file in the registry
+ RegSetValueExA(g_hRegistry,"TextureSrc",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+ RegSetValueExA(g_hRegistry,"LastTextureSrc",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+ RegSetValueExA(g_hRegistry,"LastSkyBoxSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH);
+
+ CBackgroundPainter::Instance().SetTextureBG(szFileName);
+}
+
+//-------------------------------------------------------------------------------
+// Reset the background color to a smart and nice grey
+//-------------------------------------------------------------------------------
+void ClearBG() {
+ D3DCOLOR clrColor = D3DCOLOR_ARGB(0xFF,100,100,100);
+ CBackgroundPainter::Instance().SetColor(clrColor);
+
+ RegSetValueExA(g_hRegistry,"LastSkyBoxSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH);
+ RegSetValueExA(g_hRegistry,"LastTextureSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH);
+
+ RegSetValueExA(g_hRegistry,"Color",0,REG_DWORD,(const BYTE*)&clrColor,4);
+}
+
+//-------------------------------------------------------------------------------
+// Let the user choose a color in a windows standard color dialog
+//-------------------------------------------------------------------------------
+void DisplayColorDialog(D3DCOLOR* pclrResult) {
+ CHOOSECOLOR clr;
+ clr.lStructSize = sizeof(CHOOSECOLOR);
+ clr.hwndOwner = g_hDlg;
+ clr.Flags = CC_RGBINIT | CC_FULLOPEN;
+ clr.rgbResult = RGB((*pclrResult >> 16) & 0xff,(*pclrResult >> 8) & 0xff,*pclrResult & 0xff);
+ clr.lpCustColors = g_aclCustomColors;
+ clr.lpfnHook = nullptr;
+ clr.lpTemplateName = nullptr;
+ clr.lCustData = 0;
+
+ ChooseColor(&clr);
+
+ *pclrResult = D3DCOLOR_ARGB(0xFF,
+ GetRValue(clr.rgbResult),
+ GetGValue(clr.rgbResult),
+ GetBValue(clr.rgbResult));
+}
+
+//-------------------------------------------------------------------------------
+// Let the user choose a color in a windows standard color dialog
+//-------------------------------------------------------------------------------
+void DisplayColorDialog(D3DXVECTOR4* pclrResult) {
+ CHOOSECOLOR clr;
+ clr.lStructSize = sizeof(CHOOSECOLOR);
+ clr.hwndOwner = g_hDlg;
+ clr.Flags = CC_RGBINIT | CC_FULLOPEN;
+ clr.rgbResult = RGB(clamp<unsigned char>(pclrResult->x * 255.0f),
+ clamp<unsigned char>(pclrResult->y * 255.0f),
+ clamp<unsigned char>(pclrResult->z * 255.0f));
+ clr.lpCustColors = g_aclCustomColors;
+ clr.lpfnHook = nullptr;
+ clr.lpTemplateName = nullptr;
+ clr.lCustData = 0;
+
+ ChooseColor(&clr);
+
+ pclrResult->x = GetRValue(clr.rgbResult) / 255.0f;
+ pclrResult->y = GetGValue(clr.rgbResult) / 255.0f;
+ pclrResult->z = GetBValue(clr.rgbResult) / 255.0f;
+}
+
+//-------------------------------------------------------------------------------
+// Let the user choose the background color for the viewer
+//-------------------------------------------------------------------------------
+void ChooseBGColor() {
+ RegSetValueExA(g_hRegistry,"LastSkyBoxSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH);
+ RegSetValueExA(g_hRegistry,"LastTextureSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH);
+
+ D3DCOLOR clrColor;
+ DisplayColorDialog(&clrColor);
+ CBackgroundPainter::Instance().SetColor(clrColor);
+
+ RegSetValueExA(g_hRegistry,"Color",0,REG_DWORD,(const BYTE*)&clrColor,4);
+}
+
+//-------------------------------------------------------------------------------
+// Display the OpenFile dialog and let the user choose a new slybox as bg
+//-------------------------------------------------------------------------------
+void LoadSkybox() {
+ char szFileName[MAX_PATH];
+
+ DWORD dwTemp = MAX_PATH;
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"SkyBoxSrc",nullptr,nullptr,
+ (BYTE*)szFileName,&dwTemp))
+ {
+ // Key was not found. Use C:
+ strcpy(szFileName,"");
+ }
+ else
+ {
+ // need to remove the file name
+ char* sz = strrchr(szFileName,'\\');
+ if (!sz)
+ sz = strrchr(szFileName,'/');
+ if (sz)
+ *sz = 0;
+ }
+ OPENFILENAME sFilename1 = {
+ sizeof(OPENFILENAME),
+ g_hDlg,GetModuleHandle(nullptr),
+ "Skyboxes\0*.dds\0*.*\0", nullptr, 0, 1,
+ szFileName, MAX_PATH, nullptr, 0, nullptr,
+ "Open skybox as background",
+ OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
+ 0, 1, ".dds", 0, nullptr, nullptr
+ };
+ if(GetOpenFileName(&sFilename1) == 0) return;
+
+ // Now store the file in the registry
+ RegSetValueExA(g_hRegistry,"SkyBoxSrc",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+ RegSetValueExA(g_hRegistry,"LastSkyBoxSrc",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+ RegSetValueExA(g_hRegistry,"LastTextureSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH);
+
+ CBackgroundPainter::Instance().SetCubeMapBG(szFileName);
+ return;
+}
+
+template<class T>
+inline
+void SaveRelease(T **iface ) {
+ if (nullptr != iface) {
+ (*iface)->Release();
+ *iface = nullptr;
+ }
+}
+
+//-------------------------------------------------------------------------------
+// Save a screenshot to an user-defined file
+//-------------------------------------------------------------------------------
+void SaveScreenshot() {
+ char szFileName[MAX_PATH];
+
+ DWORD dwTemp = MAX_PATH;
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"ScreenShot",nullptr,nullptr, (BYTE*)szFileName,&dwTemp)) {
+ // Key was not found. Use C:
+ strcpy(szFileName,"");
+ } else {
+ // need to remove the file name
+ char* sz = strrchr(szFileName,'\\');
+ if (!sz)
+ sz = strrchr(szFileName,'/');
+ if (sz)
+ *sz = 0;
+ }
+ OPENFILENAME sFilename1 = {
+ sizeof(OPENFILENAME),
+ g_hDlg,GetModuleHandle(nullptr),
+ "PNG Images\0*.png", nullptr, 0, 1,
+ szFileName, MAX_PATH, nullptr, 0, nullptr,
+ "Save Screenshot to file",
+ OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
+ 0, 1, ".png", 0, nullptr, nullptr
+ };
+ if(GetSaveFileName(&sFilename1) == 0) return;
+
+ // Now store the file in the registry
+ RegSetValueExA(g_hRegistry,"ScreenShot",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+
+ IDirect3DSurface9* pi = nullptr;
+ g_piDevice->GetRenderTarget(0,&pi);
+ if(!pi || FAILED(D3DXSaveSurfaceToFile(szFileName,D3DXIFF_PNG,pi,nullptr,nullptr))) {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to save screenshot",
+ D3DCOLOR_ARGB(0xFF,0xFF,0,0));
+ } else {
+ CLogDisplay::Instance().AddEntry("[INFO] The screenshot has been saved",
+ D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ }
+ SaveRelease(&pi);
+}
+
+//-------------------------------------------------------------------------------
+// Get the amount of memory required for textures
+//-------------------------------------------------------------------------------
+void AddTextureMem(IDirect3DTexture9* pcTex, unsigned int& out) {
+ if (!pcTex) {
+ return;
+ }
+
+ D3DSURFACE_DESC sDesc;
+ pcTex->GetLevelDesc(0,&sDesc);
+
+ out += (sDesc.Width * sDesc.Height) << 2;
+}
+
+//-------------------------------------------------------------------------------
+// Display memory statistics
+//-------------------------------------------------------------------------------
+void DisplayMemoryConsumption() {
+ // first get the memory consumption for the aiScene
+ if (! g_pcAsset ||!g_pcAsset->pcScene) {
+ MessageBox(g_hDlg,"No asset is loaded. Can you guess how much memory I need to store nothing?",
+ "Memory consumption",MB_OK);
+ return;
+ }
+ unsigned int iScene = sizeof(aiScene);
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) {
+ iScene += sizeof(aiMesh);
+ if (g_pcAsset->pcScene->mMeshes[i]->HasPositions())
+ iScene += sizeof(aiVector3D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices;
+
+ if (g_pcAsset->pcScene->mMeshes[i]->HasNormals())
+ iScene += sizeof(aiVector3D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices;
+
+ if (g_pcAsset->pcScene->mMeshes[i]->HasTangentsAndBitangents())
+ iScene += sizeof(aiVector3D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices * 2;
+
+ for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
+ if (g_pcAsset->pcScene->mMeshes[i]->HasVertexColors(a)) {
+ iScene += sizeof(aiColor4D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices;
+ } else {
+ break;
+ }
+ }
+ for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
+ if (g_pcAsset->pcScene->mMeshes[i]->HasTextureCoords(a))
+ iScene += sizeof(aiVector3D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices;
+ else break;
+ }
+ if (g_pcAsset->pcScene->mMeshes[i]->HasBones()) {
+ for (unsigned int p = 0; p < g_pcAsset->pcScene->mMeshes[i]->mNumBones;++p) {
+ iScene += sizeof(aiBone);
+ iScene += g_pcAsset->pcScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight);
+ }
+ }
+ iScene += (sizeof(aiFace) + 3 * sizeof(unsigned int))*g_pcAsset->pcScene->mMeshes[i]->mNumFaces;
+ }
+ // add all embedded textures
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumTextures;++i) {
+ const aiTexture* pc = g_pcAsset->pcScene->mTextures[i];
+ if (0 != pc->mHeight) {
+ iScene += 4 * pc->mHeight * pc->mWidth;
+ } else {
+ iScene += pc->mWidth;
+ }
+ }
+ // add 30k for each material ... a string has 4k for example
+ iScene += g_pcAsset->pcScene->mNumMaterials * 30 * 1024;
+
+ // now get the memory consumption required by D3D, first all textures
+ unsigned int iTexture = 0;
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) {
+ AssetHelper::MeshHelper* pc = g_pcAsset->apcMeshes[i];
+
+ AddTextureMem(pc->piDiffuseTexture,iTexture);
+ AddTextureMem(pc->piSpecularTexture,iTexture);
+ AddTextureMem(pc->piAmbientTexture,iTexture);
+ AddTextureMem(pc->piEmissiveTexture,iTexture);
+ AddTextureMem(pc->piOpacityTexture,iTexture);
+ AddTextureMem(pc->piNormalTexture,iTexture);
+ AddTextureMem(pc->piShininessTexture,iTexture);
+ }
+ unsigned int iVRAM = iTexture;
+
+ // now get the memory consumption of all vertex/index buffers
+ unsigned int iVB( 0 ), iIB(0);
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) {
+ AssetHelper:: MeshHelper* pc = g_pcAsset->apcMeshes[i];
+
+ union{
+ D3DVERTEXBUFFER_DESC sDesc;
+ D3DINDEXBUFFER_DESC sDesc2;
+ };
+
+ if (pc->piVB)
+ {
+ pc->piVB->GetDesc(&sDesc);
+ iVB += sDesc.Size;
+ }
+ if (pc->piVBNormals)
+ {
+ pc->piVBNormals->GetDesc(&sDesc);
+ iVB += sDesc.Size;
+ }
+ if (pc->piIB)
+ {
+ pc->piIB->GetDesc(&sDesc2);
+ iIB += sDesc2.Size;
+ }
+ }
+ iVRAM += iVB + iIB;
+ // add the memory for the back buffer and depth stencil buffer
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
+ sRect.bottom -= sRect.top;
+ sRect.right -= sRect.left;
+ iVRAM += sRect.bottom * sRect.right * 8;
+
+ char szOut[2048];
+ sprintf(szOut,
+ "(1 KiB = 1024 bytes)\n\n"
+ "ASSIMP Import Data: \t%i KiB\n"
+ "Texture data:\t\t%i KiB\n"
+ "Vertex buffers:\t\t%i KiB\n"
+ "Index buffers:\t\t%i KiB\n"
+ "Video Memory:\t\t%i KiB\n\n"
+ "Total: \t\t\t%i KiB",
+ iScene / 1024,iTexture / 1024,iVB / 1024,iIB / 1024,iVRAM / 1024,
+ (iScene + iTexture + iVB + iIB + iVRAM) / 1024);
+ MessageBox(g_hDlg,szOut,"Memory consumption",MB_OK);
+}
+
+//-------------------------------------------------------------------------------
+// Save the list of recent files to the registry
+//-------------------------------------------------------------------------------
+void SaveHistory() {
+ for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i) {
+ char szName[66];
+ sprintf(szName,"Recent%i",i+1);
+
+ RegSetValueEx(g_hRegistry,szName,0,REG_SZ,
+ (const BYTE*)g_aPreviousFiles[i].c_str(),(DWORD)g_aPreviousFiles[i].length());
+ }
+}
+
+//-------------------------------------------------------------------------------
+// Recover the file history
+//-------------------------------------------------------------------------------
+void LoadHistory() {
+ g_aPreviousFiles.resize(AI_VIEW_NUM_RECENT_FILES);
+
+ char szFileName[MAX_PATH];
+
+ for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i) {
+ char szName[66];
+ sprintf(szName,"Recent%i",i+1);
+
+ DWORD dwTemp = MAX_PATH;
+
+ szFileName[0] ='\0';
+ if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,szName,nullptr,nullptr,
+ (BYTE*)szFileName,&dwTemp)) {
+ g_aPreviousFiles[i] = std::string(szFileName);
+ }
+ }
+
+ // add sub items for all recent files
+ g_hHistoryMenu = CreateMenu();
+ for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) {
+ const char* szText = g_aPreviousFiles[i].c_str();
+ UINT iFlags = 0;
+ if ('\0' == *szText) {
+ szText = "<empty>";
+ iFlags = MF_GRAYED | MF_DISABLED;
+ }
+ AppendMenu(g_hHistoryMenu,MF_STRING | iFlags,AI_VIEW_RECENT_FILE_ID(i),szText);
+ }
+
+ ModifyMenu(GetMenu(g_hDlg),ID_VIEWER_RECENTFILES,MF_BYCOMMAND | MF_POPUP,
+ (UINT_PTR)g_hHistoryMenu,"Recent files");
+}
+
+//-------------------------------------------------------------------------------
+// Clear the file history
+//-------------------------------------------------------------------------------
+void ClearHistory() {
+ for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES; ++i) {
+ g_aPreviousFiles[i] = std::string("");
+ }
+
+ for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) {
+ ModifyMenu(g_hHistoryMenu,AI_VIEW_RECENT_FILE_ID(i),
+ MF_STRING | MF_BYCOMMAND | MF_GRAYED | MF_DISABLED,AI_VIEW_RECENT_FILE_ID(i),"<empty>");
+ }
+
+ SaveHistory();
+}
+
+//-------------------------------------------------------------------------------
+// Update the file history
+//-------------------------------------------------------------------------------
+void UpdateHistory() {
+ if (!g_hHistoryMenu) {
+ return;
+ }
+
+ std::string sz = std::string(g_szFileName);
+ if (g_aPreviousFiles[AI_VIEW_NUM_RECENT_FILES - 1] == sz) {
+ return;
+ }
+
+ // add the new asset to the list of recent files
+ for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES-1;++i) {
+ g_aPreviousFiles[i] = g_aPreviousFiles[i+1];
+ }
+ g_aPreviousFiles[AI_VIEW_NUM_RECENT_FILES-1] = sz;
+ for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) {
+ const char* szText = g_aPreviousFiles[i].c_str();
+ UINT iFlags = 0;
+ if ('\0' == *szText) {
+ szText = "<empty>";
+ iFlags = MF_GRAYED | MF_DISABLED;
+ }
+ ModifyMenu(g_hHistoryMenu,AI_VIEW_RECENT_FILE_ID(i),
+ MF_STRING | MF_BYCOMMAND | iFlags,AI_VIEW_RECENT_FILE_ID(i),szText);
+ }
+}
+
+//-------------------------------------------------------------------------------
+// Open a new asset
+//-------------------------------------------------------------------------------
+void OpenAsset() {
+ char szFileName[MAX_PATH];
+
+ DWORD dwTemp = MAX_PATH;
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"CurrentApp",nullptr,nullptr, (BYTE*)szFileName,&dwTemp)) {
+ // Key was not found. Use C:
+ strcpy(szFileName,"");
+ } else {
+ // need to remove the file name
+ char* sz = strrchr(szFileName,'\\');
+ if (!sz)
+ sz = strrchr(szFileName,'/');
+ if (sz)
+ *sz = 0;
+ }
+
+ // get a list of all file extensions supported by ASSIMP
+ aiString sz;
+ aiGetExtensionList(&sz);
+
+ char szList[MAXLEN + 100];
+ strcpy(szList,"ASSIMP assets");
+ char* szCur = szList + 14;
+ strcpy(szCur,sz.data);
+ szCur += sz.length+1;
+ strcpy(szCur,"All files");
+ szCur += 10;
+ strcpy(szCur,"*.*");
+ szCur[4] = 0;
+
+ OPENFILENAME sFilename1;
+ ZeroMemory(&sFilename1, sizeof(sFilename1));
+ sFilename1.lStructSize = sizeof(sFilename1);
+ sFilename1.hwndOwner = g_hDlg;
+ sFilename1.hInstance = GetModuleHandle(nullptr);
+ sFilename1.lpstrFile = szFileName;
+ sFilename1.lpstrFile[0] = '\0';
+ sFilename1.nMaxFile = sizeof(szList);
+ sFilename1.lpstrFilter = szList;
+ sFilename1.nFilterIndex = 1;
+ sFilename1.lpstrFileTitle = nullptr;
+ sFilename1.nMaxFileTitle = 0;
+ sFilename1.lpstrInitialDir = nullptr;
+ sFilename1.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
+ if (GetOpenFileName(&sFilename1) == 0) {
+ return;
+ }
+
+ // Now store the file in the registry
+ RegSetValueExA(g_hRegistry,"CurrentApp",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+
+ if (0 != strcmp(g_szFileName,szFileName)) {
+ strcpy(g_szFileName, szFileName);
+ DeleteAssetData();
+ DeleteAsset();
+ LoadAsset();
+
+ // update the history
+ UpdateHistory();
+
+ // Save the list of previous files to the registry
+ SaveHistory();
+ }
+}
+
+//-------------------------------------------------------------------------------
+void SetupPPUIState() {
+ // that's ugly. anyone willing to rewrite me from scratch?
+ HMENU hMenu = GetMenu(g_hDlg);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_JIV,ppsteps & aiProcess_JoinIdenticalVertices ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_CTS,ppsteps & aiProcess_CalcTangentSpace ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FD,ppsteps & aiProcess_FindDegenerates ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FID,ppsteps & aiProcess_FindInvalidData ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FIM,ppsteps & aiProcess_FindInstances ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FIN,ppsteps & aiProcess_FixInfacingNormals ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_GUV,ppsteps & aiProcess_GenUVCoords ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_ICL,ppsteps & aiProcess_ImproveCacheLocality ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_OG,ppsteps & aiProcess_OptimizeGraph ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_OM,ppsteps & aiProcess_OptimizeMeshes ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_PTV,ppsteps & aiProcess_PreTransformVertices ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_RRM2,ppsteps & aiProcess_RemoveRedundantMaterials ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_TUV,ppsteps & aiProcess_TransformUVCoords ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_VDS,ppsteps & aiProcess_ValidateDataStructure ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_VIEWER_PP_DB,ppsteps & aiProcess_Debone ? MF_CHECKED : MF_UNCHECKED);
+}
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+//-------------------------------------------------------------------------------
+// Fill the 'export' top level menu with a list of all supported export formats
+//-------------------------------------------------------------------------------
+void PopulateExportMenu() {
+ // add sub items for all recent files
+ Exporter exp;
+ HMENU hm = ::CreateMenu();
+ for(size_t i = 0; i < exp.GetExportFormatCount(); ++i) {
+ const aiExportFormatDesc* const e = exp.GetExportFormatDescription(i);
+ char tmp[256];
+ sprintf(tmp,"%s (%s)",e->description,e->id);
+
+ AppendMenu(hm,MF_STRING,AI_VIEW_EXPORT_FMT_ID(i),tmp);
+ }
+
+ ModifyMenu(GetMenu(g_hDlg),ID_EXPORT,MF_BYCOMMAND | MF_POPUP,
+ (UINT_PTR)hm,"Export");
+}
+
+//-------------------------------------------------------------------------------
+// Export function
+//-------------------------------------------------------------------------------
+void DoExport(size_t formatId) {
+ if (!g_szFileName[0]) {
+ MessageBox(g_hDlg, "No model loaded", "Export", MB_ICONERROR);
+ return;
+ }
+ Exporter exp;
+ const aiExportFormatDesc* const e = exp.GetExportFormatDescription(formatId);
+ ai_assert(e);
+
+ char szFileName[MAX_PATH*2];
+ DWORD dwTemp = sizeof(szFileName);
+ if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"ModelExportDest",nullptr,nullptr,(BYTE*)szFileName, &dwTemp)) {
+ ai_assert(strlen(szFileName) <= MAX_PATH);
+
+ // invent a nice default file name
+ char* sz = std::max(strrchr(szFileName,'\\'),strrchr(szFileName,'/'));
+ if (sz) {
+ strncpy(sz,std::max(strrchr(g_szFileName,'\\'),strrchr(g_szFileName,'/')),MAX_PATH);
+ }
+ }
+ else {
+ // Key was not found. Use the folder where the asset comes from
+ strncpy(szFileName,g_szFileName,MAX_PATH);
+ }
+
+ // fix file extension
+ { char * const sz = strrchr(szFileName,'.');
+ if(sz) {
+ ai_assert((sz - &szFileName[0]) + strlen(e->fileExtension) + 1 <= MAX_PATH);
+ strcpy(sz+1,e->fileExtension);
+ }
+ }
+
+ // build the stupid info string for GetSaveFileName() - can't use sprintf() because the string must contain binary zeros.
+ char desc[256] = {0};
+ char* c = strcpy(desc,e->description) + strlen(e->description)+1;
+ c += sprintf(c,"*.%s",e->fileExtension)+1;
+ strcpy(c, "*.*\0"); c += 4;
+
+ ai_assert(c - &desc[0] <= 256);
+
+ const std::string ext = "."+std::string(e->fileExtension);
+ OPENFILENAME sFilename1 = {
+ sizeof(OPENFILENAME),
+ g_hDlg,GetModuleHandle(nullptr),
+ desc, nullptr, 0, 1,
+ szFileName, MAX_PATH, nullptr, 0, nullptr,
+ "Export asset",
+ OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR,
+ 0, 1, ext.c_str(), 0, nullptr, nullptr
+ };
+ if(::GetSaveFileName(&sFilename1) == 0) {
+ return;
+ }
+
+ // Now store the file in the registry unless the user decided to stay in the model directory
+ const std::string sFinal = szFileName, sub = sFinal.substr(0,sFinal.find_last_of("\\/"));
+ if (strncmp(sub.c_str(),g_szFileName,sub.length())) {
+ RegSetValueExA(g_hRegistry,"ModelExportDest",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
+ }
+
+ // export the file
+ const aiReturn res = exp.Export(g_pcAsset->pcScene,e->id,sFinal.c_str(),
+ ppsteps | /* configurable pp steps */
+ aiProcess_GenSmoothNormals | // generate smooth normal vectors if not existing
+ aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
+ aiProcess_Triangulate | // triangulate polygons with more than 3 edges
+ aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
+ aiProcess_SortByPType | // make 'clean' meshes which consist of a single typ of primitives
+ 0
+ );
+ if (res == aiReturn_SUCCESS) {
+ CLogDisplay::Instance().AddEntry("[INFO] Exported file " + sFinal,D3DCOLOR_ARGB(0xFF,0x00,0xFF,0x00));
+ return;
+ }
+ CLogDisplay::Instance().AddEntry("[INFO] Failure exporting file " +
+ sFinal,D3DCOLOR_ARGB(0xFF,0xFF,0x00,0x00));
+}
+#endif
+
+//-------------------------------------------------------------------------------
+// Initialize the user interface
+//-------------------------------------------------------------------------------
+void InitUI() {
+ SetDlgItemText(g_hDlg,IDC_EVERT,"0");
+ SetDlgItemText(g_hDlg,IDC_EFACE,"0");
+ SetDlgItemText(g_hDlg,IDC_EMAT,"0");
+ SetDlgItemText(g_hDlg,IDC_ESHADER,"0");
+ SetDlgItemText(g_hDlg,IDC_ENODEWND,"0");
+ SetDlgItemText(g_hDlg,IDC_ETEX,"0");
+ SetDlgItemText(g_hDlg,IDC_EMESH,"0");
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+ PopulateExportMenu();
+#endif
+
+ // setup the default window title
+ SetWindowText(g_hDlg,AI_VIEW_CAPTION_BASE);
+
+ // read some UI properties from the registry and apply them
+ DWORD dwValue;
+ DWORD dwTemp = sizeof( DWORD );
+
+ // store the key in a global variable for later use
+ RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\ASSIMP\\Viewer",
+ 0,nullptr,0,KEY_ALL_ACCESS, nullptr, &g_hRegistry,nullptr);
+
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LastUIState",nullptr,nullptr, (BYTE*)&dwValue,&dwTemp)) {
+ dwValue = 1;
+ }
+ if (0 == dwValue) {
+ // collapse the viewer
+ // adjust the size
+ RECT sRect;
+ GetWindowRect(g_hDlg,&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ RECT sRect2;
+ GetWindowRect(GetDlgItem ( g_hDlg, IDC_BLUBB ),&sRect2);
+ sRect2.left -= sRect.left;
+ sRect2.top -= sRect.top;
+
+ SetWindowPos(g_hDlg,nullptr,0,0,sRect.right-214,sRect.bottom,
+ SWP_NOMOVE | SWP_NOZORDER);
+ SetWindowText(GetDlgItem(g_hDlg,IDC_BLUBB),">>");
+ } else {
+ CheckDlgButton(g_hDlg,IDC_BLUBB,BST_CHECKED);
+ }
+
+ // AutoRotate
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"AutoRotate",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue) {
+ g_sOptions.bRotate = false;
+ CheckDlgButton(g_hDlg,IDC_AUTOROTATE,BST_UNCHECKED);
+ } else {
+ g_sOptions.bRotate = true;
+ CheckDlgButton(g_hDlg,IDC_AUTOROTATE,BST_CHECKED);
+ }
+
+ // MultipleLights
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"MultipleLights",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue) {
+ g_sOptions.b3Lights = false;
+ CheckDlgButton(g_hDlg,IDC_3LIGHTS,BST_UNCHECKED);
+ } else {
+ g_sOptions.b3Lights = true;
+ CheckDlgButton(g_hDlg,IDC_3LIGHTS,BST_CHECKED);
+ }
+
+ // Light rotate
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LightRotate",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue) {
+ g_sOptions.bLightRotate = false;
+ CheckDlgButton(g_hDlg,IDC_LIGHTROTATE,BST_UNCHECKED);
+ } else {
+ g_sOptions.bLightRotate = true;
+ CheckDlgButton(g_hDlg,IDC_LIGHTROTATE,BST_CHECKED);
+ }
+
+ // NoSpecular
+ if (ERROR_SUCCESS != RegQueryValueEx(g_hRegistry, "NoSpecular", nullptr, nullptr, (BYTE*)&dwValue, &dwTemp)) {
+ dwValue = 0;
+ }
+ if (0 == dwValue) {
+ g_sOptions.bNoSpecular = false;
+ CheckDlgButton(g_hDlg,IDC_NOSPECULAR,BST_UNCHECKED);
+ } else {
+ g_sOptions.bNoSpecular = true;
+ CheckDlgButton(g_hDlg,IDC_NOSPECULAR,BST_CHECKED);
+ }
+
+ // LowQuality
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LowQuality",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue) {
+ g_sOptions.bLowQuality = false;
+ CheckDlgButton(g_hDlg,IDC_LOWQUALITY,BST_UNCHECKED);
+ } else {
+ g_sOptions.bLowQuality = true;
+ CheckDlgButton(g_hDlg,IDC_LOWQUALITY,BST_CHECKED);
+ }
+
+ // LowQuality
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"NoTransparency",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue) {
+ g_sOptions.bNoAlphaBlending = false;
+ CheckDlgButton(g_hDlg,IDC_NOAB,BST_UNCHECKED);
+ } else {
+ g_sOptions.bNoAlphaBlending = true;
+ CheckDlgButton(g_hDlg,IDC_NOAB,BST_CHECKED);
+ }
+
+ // DisplayNormals
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"RenderNormals",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue) {
+ g_sOptions.bRenderNormals = false;
+ CheckDlgButton(g_hDlg,IDC_TOGGLENORMALS,BST_UNCHECKED);
+ } else {
+ g_sOptions.bRenderNormals = true;
+ CheckDlgButton(g_hDlg,IDC_TOGGLENORMALS,BST_CHECKED);
+ }
+
+ // NoMaterials
+ if (ERROR_SUCCESS != RegQueryValueEx(g_hRegistry, "RenderMats", nullptr, nullptr,
+ (BYTE*)&dwValue, &dwTemp)) {
+ dwValue = 1;
+ }
+ if (0 == dwValue) {
+ g_sOptions.bRenderMats = false;
+ CheckDlgButton(g_hDlg,IDC_TOGGLEMAT,BST_CHECKED);
+ } else {
+ g_sOptions.bRenderMats = true;
+ CheckDlgButton(g_hDlg,IDC_TOGGLEMAT,BST_UNCHECKED);
+ }
+
+ // MultiSampling
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"MultiSampling",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 1;
+ if (0 == dwValue)
+ {
+ g_sOptions.bMultiSample = false;
+ CheckDlgButton(g_hDlg,IDC_TOGGLEMS,BST_UNCHECKED);
+ } else {
+ g_sOptions.bMultiSample = true;
+ CheckDlgButton(g_hDlg,IDC_TOGGLEMS,BST_CHECKED);
+ }
+
+ // FPS Mode
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"FPSView",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue) {
+ g_bFPSView = false;
+ CheckDlgButton(g_hDlg,IDC_ZOOM,BST_CHECKED);
+ } else {
+ g_bFPSView = true;
+ CheckDlgButton(g_hDlg,IDC_ZOOM,BST_UNCHECKED);
+ }
+
+ // WireFrame
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"Wireframe",nullptr,nullptr,
+ (BYTE*)&dwValue,&dwTemp))dwValue = 0;
+ if (0 == dwValue)
+ {
+ g_sOptions.eDrawMode = RenderOptions::NORMAL;
+ CheckDlgButton(g_hDlg,IDC_TOGGLEWIRE,BST_UNCHECKED);
+ }
+ else
+ {
+ g_sOptions.eDrawMode = RenderOptions::WIREFRAME;
+ CheckDlgButton(g_hDlg,IDC_TOGGLEWIRE,BST_CHECKED);
+ }
+
+ if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"PostProcessing",nullptr,nullptr,(BYTE*)&dwValue,&dwTemp))
+ ppsteps = ppstepsdefault;
+ else ppsteps = dwValue;
+
+ SetupPPUIState();
+ LoadCheckerPatternColors();
+
+ SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMIN,TRUE,0);
+ SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMAX,TRUE,10000);
+}
+
+//-------------------------------------------------------------------------------
+// Message procedure for the smooth normals dialog
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK SMMessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam) {
+ UNREFERENCED_PARAMETER(lParam);
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ {
+ char s[30];
+ ::sprintf(s, "%.2f", g_smoothAngle);
+ SetDlgItemText(hwndDlg, IDC_EDITSM, s);
+ }
+ return TRUE;
+
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return TRUE;
+
+ case WM_COMMAND:
+ {
+ if (IDOK == LOWORD(wParam)) {
+ char s[30];
+ GetDlgItemText(hwndDlg, IDC_EDITSM, s, 30);
+ g_smoothAngle = (float)atof(s);
+
+ EndDialog(hwndDlg, 0);
+ } else if (IDCANCEL == LOWORD(wParam)) {
+ EndDialog(hwndDlg, 1);
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//-------------------------------------------------------------------------------
+// Main message procedure of the application
+//
+// The function handles all incoming messages for the main window.
+// However, if does not directly process input commands.
+// NOTE: Due to the impossibility to process WM_CHAR messages in dialogs
+// properly the code for all hotkeys has been moved to the WndMain
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam) {
+ UNREFERENCED_PARAMETER(lParam);
+ UNREFERENCED_PARAMETER(wParam);
+
+ int xPos,yPos;
+ int xPos2,yPos2;
+ int fHalfX;
+ int fHalfY;
+
+ TRACKMOUSEEVENT sEvent;
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+
+ g_hDlg = hwndDlg;
+
+ // load the state of the user interface
+ InitUI();
+
+ // load the file history
+ LoadHistory();
+
+ // load the current color of the lights
+ LoadLightColors();
+ return TRUE;
+
+ case WM_HSCROLL:
+
+ // XXX quick and dirty fix for #3029892
+ if (GetDlgItem(g_hDlg, IDC_SLIDERANIM) == (HWND)lParam && g_pcAsset && g_pcAsset->pcScene->mAnimations)
+ {
+ double num = (double)SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_GETPOS,0,0);
+ const aiAnimation* anim = g_pcAsset->pcScene->mAnimations[ g_pcAsset->mAnimator->CurrentAnimIndex() ];
+
+ g_dCurrent = (anim->mDuration/anim->mTicksPerSecond) * num/10000;
+ g_pcAsset->mAnimator->Calculate(g_dCurrent);
+ }
+ break;
+
+ case WM_MOUSEWHEEL:
+
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode())
+ {
+ CDisplay::Instance().SetTextureViewZoom ( GET_WHEEL_DELTA_WPARAM(wParam) / 50.0f );
+ }
+ else
+ {
+ if (!g_bFPSView)
+ {
+ g_sCamera.vPos.z += GET_WHEEL_DELTA_WPARAM(wParam) / 50.0f;
+ }
+ else
+ {
+ g_sCamera.vPos += (GET_WHEEL_DELTA_WPARAM(wParam) / 50.0f) *
+ g_sCamera.vLookAt.Normalize();
+ }
+ }
+ return TRUE;
+
+ case WM_MOUSELEAVE:
+
+ g_bMousePressed = false;
+ g_bMousePressedR = false;
+ g_bMousePressedM = false;
+ g_bMousePressedBoth = false;
+ return TRUE;
+
+ case WM_LBUTTONDBLCLK:
+
+ CheckDlgButton(hwndDlg,IDC_AUTOROTATE,
+ IsDlgButtonChecked(hwndDlg,IDC_AUTOROTATE) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleAutoRotate();
+ return TRUE;
+
+
+ case WM_CLOSE:
+ PostQuitMessage(0);
+ DestroyWindow(hwndDlg);
+ return TRUE;
+
+ case WM_NOTIFY:
+
+ if (IDC_TREE1 == wParam)
+ {
+ NMTREEVIEW* pnmtv = (LPNMTREEVIEW) lParam;
+
+ if (TVN_SELCHANGED == pnmtv->hdr.code)
+ CDisplay::Instance().OnSetup( pnmtv->itemNew.hItem );
+ else if (NM_RCLICK == pnmtv->hdr.code)
+ {
+ // determine in which item the click was ...
+ POINT sPoint;
+ GetCursorPos(&sPoint);
+ ScreenToClient(GetDlgItem(g_hDlg,IDC_TREE1),&sPoint);
+
+ TVHITTESTINFO sHit;
+ sHit.pt = sPoint;
+ TreeView_HitTest(GetDlgItem(g_hDlg,IDC_TREE1),&sHit);
+ CDisplay::Instance().ShowTreeViewContextMenu(sHit.hItem);
+ }
+ }
+ return TRUE;
+
+ case WM_DRAWITEM:
+ {
+ // draw the two light colors
+ DRAWITEMSTRUCT* pcStruct = (DRAWITEMSTRUCT*)lParam;
+
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_LCOLOR1),&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+ sRect.left = sRect.top = 0;
+
+ bool bDraw = false;
+
+ if(IDC_LCOLOR1 == pcStruct->CtlID)
+ {
+ unsigned char r,g,b;
+ const char* szText;
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode() ||
+ CDisplay::VIEWMODE_MATERIAL == CDisplay::Instance().GetViewMode())
+ {
+ r = (unsigned char)(CDisplay::Instance().GetFirstCheckerColor()->x * 255.0f);
+ g = (unsigned char)(CDisplay::Instance().GetFirstCheckerColor()->y * 255.0f);
+ b = (unsigned char)(CDisplay::Instance().GetFirstCheckerColor()->z * 255.0f);
+ szText = "Background #0";
+ }
+ else if (!g_pcAsset)
+ {
+ r = g = b = 150;szText = "";
+ }
+ else
+ {
+ r = (unsigned char)((g_avLightColors[0] >> 16) & 0xFF);
+ g = (unsigned char)((g_avLightColors[0] >> 8) & 0xFF);
+ b = (unsigned char)((g_avLightColors[0]) & 0xFF);
+ szText = "Light #0";
+ }
+ HBRUSH hbr = CreateSolidBrush(RGB(r,g,b));
+
+ FillRect(pcStruct->hDC,&sRect,hbr);
+
+
+ SetTextColor(pcStruct->hDC,RGB(0xFF-r,0xFF-g,0xFF-b));
+ SetBkMode(pcStruct->hDC,TRANSPARENT);
+ TextOut(pcStruct->hDC,4,1,szText, static_cast<int>(strlen(szText)));
+ bDraw = true;
+ }
+ else if(IDC_LCOLOR2 == pcStruct->CtlID)
+ {
+ unsigned char r,g,b;
+ const char* szText;
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode() ||
+ CDisplay::VIEWMODE_MATERIAL == CDisplay::Instance().GetViewMode())
+ {
+ r = (unsigned char)(CDisplay::Instance().GetSecondCheckerColor()->x * 255.0f);
+ g = (unsigned char)(CDisplay::Instance().GetSecondCheckerColor()->y * 255.0f);
+ b = (unsigned char)(CDisplay::Instance().GetSecondCheckerColor()->z * 255.0f);
+ szText = "Background #1";
+ }
+ else if (!g_pcAsset)
+ {
+ r = g = b = 150;szText = "";
+ }
+ else
+ {
+ r = (unsigned char)((g_avLightColors[1] >> 16) & 0xFF);
+ g = (unsigned char)((g_avLightColors[1] >> 8) & 0xFF);
+ b = (unsigned char)((g_avLightColors[1]) & 0xFF);
+ szText = "Light #1";
+ }
+ HBRUSH hbr = CreateSolidBrush(RGB(r,g,b));
+ FillRect(pcStruct->hDC,&sRect,hbr);
+
+ SetTextColor(pcStruct->hDC,RGB(0xFF-r,0xFF-g,0xFF-b));
+ SetBkMode(pcStruct->hDC,TRANSPARENT);
+ TextOut(pcStruct->hDC,4,1,szText, static_cast<int>(strlen(szText)));
+ bDraw = true;
+ }
+ else if(IDC_LCOLOR3 == pcStruct->CtlID)
+ {
+ unsigned char r,g,b;
+ const char* szText;
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode() ||
+ CDisplay::VIEWMODE_MATERIAL == CDisplay::Instance().GetViewMode())
+ {
+ r = g = b = 0;
+ szText = "";
+ }
+ else if (!g_pcAsset)
+ {
+ r = g = b = 150;szText = "";
+ }
+ else
+ {
+ r = (unsigned char)((g_avLightColors[2] >> 16) & 0xFF);
+ g = (unsigned char)((g_avLightColors[2] >> 8) & 0xFF);
+ b = (unsigned char)((g_avLightColors[2]) & 0xFF);
+ szText = "Ambient";
+ }
+ HBRUSH hbr = CreateSolidBrush(RGB(r,g,b));
+ FillRect(pcStruct->hDC,&sRect,hbr);
+
+ SetTextColor(pcStruct->hDC,RGB(0xFF-r,0xFF-g,0xFF-b));
+ SetBkMode(pcStruct->hDC,TRANSPARENT);
+ TextOut(pcStruct->hDC,4,1,szText,static_cast<int>(strlen(szText)));
+ bDraw = true;
+ }
+ // draw the black border around the rects
+ if (bDraw)
+ {
+ SetBkColor(pcStruct->hDC,RGB(0,0,0));
+ MoveToEx(pcStruct->hDC,0,0,nullptr);
+ LineTo(pcStruct->hDC,sRect.right-1,0);
+ LineTo(pcStruct->hDC,sRect.right-1,sRect.bottom-1);
+ LineTo(pcStruct->hDC,0,sRect.bottom-1);
+ LineTo(pcStruct->hDC,0,0);
+ }
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+
+ // close the open registry key
+ RegCloseKey(g_hRegistry);
+ return TRUE;
+
+ case WM_LBUTTONDOWN:
+ g_bMousePressed = true;
+
+ // register a mouse track handler to be sure we'll know
+ // when the mouse leaves the display view again
+ sEvent.cbSize = sizeof(TRACKMOUSEEVENT);
+ sEvent.dwFlags = TME_LEAVE;
+ sEvent.hwndTrack = g_hDlg;
+ sEvent.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&sEvent);
+
+ if (g_bMousePressedR)
+ {
+ g_bMousePressed = false;
+ g_bMousePressedR = false;
+ g_bMousePressedBoth = true;
+ return TRUE;
+ }
+
+ // need to determine the position of the mouse and the
+ // distance from the center
+ //xPos = (int)(short)LOWORD(lParam);
+ //yPos = (int)(short)HIWORD(lParam);
+
+ POINT sPoint;
+ GetCursorPos(&sPoint);
+ ScreenToClient(GetDlgItem(g_hDlg,IDC_RT),&sPoint);
+ xPos = xPos2 = sPoint.x;
+ yPos = yPos2 = sPoint.y;
+
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg,IDC_RT),&sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ // if the mouse click was inside the viewer panel
+ // give the focus to it
+ if (xPos > 0 && xPos < sRect.right && yPos > 0 && yPos < sRect.bottom)
+ {
+ SetFocus(GetDlgItem(g_hDlg,IDC_RT));
+ }
+
+ // g_bInvert stores whether the mouse has started on the negative
+ // x or on the positive x axis of the imaginary coordinate system
+ // with origin p at the center of the HUD texture
+ xPos -= sRect.right/2;
+ yPos -= sRect.bottom/2;
+
+ if (xPos > 0)g_bInvert = true;
+ else g_bInvert = false;
+
+ D3DSURFACE_DESC sDesc;
+ g_pcTexture->GetLevelDesc(0,&sDesc);
+
+ fHalfX = (int)(((float)sRect.right-(float)sDesc.Width) / 2.0f);
+ fHalfY = (int)(((float)sRect.bottom-(float)sDesc.Height) / 2.0f);
+
+ // Determine the input operation to perform for this position
+ g_eClick = EClickPos_Outside;
+ if (xPos2 >= fHalfX && xPos2 < fHalfX + (int)sDesc.Width &&
+ yPos2 >= fHalfY && yPos2 < fHalfY + (int)sDesc.Height &&
+ nullptr != g_szImageMask)
+ {
+ // inside the texture. Lookup the grayscale value from it
+ xPos2 -= fHalfX;
+ yPos2 -= fHalfY;
+
+ unsigned char chValue = g_szImageMask[xPos2 + yPos2 * sDesc.Width];
+ if (chValue > 0xFF-20)
+ {
+ g_eClick = EClickPos_Circle;
+ }
+ else if (chValue < 0xFF-20 && chValue > 185)
+ {
+ g_eClick = EClickPos_CircleHor;
+ }
+ else if (chValue > 0x10 && chValue < 185)
+ {
+ g_eClick = EClickPos_CircleVert;
+ }
+ }
+ return TRUE;
+
+ case WM_RBUTTONDOWN:
+ g_bMousePressedR = true;
+
+ sEvent.cbSize = sizeof(TRACKMOUSEEVENT);
+ sEvent.dwFlags = TME_LEAVE;
+ sEvent.hwndTrack = g_hDlg;
+ sEvent.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&sEvent);
+
+ if (g_bMousePressed)
+ {
+ g_bMousePressedR = false;
+ g_bMousePressed = false;
+ g_bMousePressedBoth = true;
+ }
+
+ return TRUE;
+
+ case WM_MBUTTONDOWN:
+
+
+ g_bMousePressedM = true;
+
+ sEvent.cbSize = sizeof(TRACKMOUSEEVENT);
+ sEvent.dwFlags = TME_LEAVE;
+ sEvent.hwndTrack = g_hDlg;
+ sEvent.dwHoverTime = HOVER_DEFAULT;
+ TrackMouseEvent(&sEvent);
+ return TRUE;
+
+ case WM_LBUTTONUP:
+ g_bMousePressed = false;
+ g_bMousePressedBoth = false;
+ return TRUE;
+
+ case WM_RBUTTONUP:
+ g_bMousePressedR = false;
+ g_bMousePressedBoth = false;
+ return TRUE;
+
+ case WM_MBUTTONUP:
+ g_bMousePressedM = false;
+ return TRUE;
+
+ case WM_DROPFILES:
+ {
+ HDROP hDrop = (HDROP)wParam;
+ char szFile[MAX_PATH];
+ DragQueryFile(hDrop,0,szFile,sizeof(szFile));
+ const char* sz = strrchr(szFile,'.');
+ if (!sz) {
+ sz = szFile;
+ }
+
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode()) {
+ // replace the selected texture with the new one ...
+ CDisplay::Instance().ReplaceCurrentTexture(szFile);
+ } else {
+ // check whether it is a typical texture file format ...
+ ++sz;
+ if (0 == ASSIMP_stricmp(sz,"png") ||
+ 0 == ASSIMP_stricmp(sz,"bmp") ||
+ 0 == ASSIMP_stricmp(sz,"jpg") ||
+ 0 == ASSIMP_stricmp(sz,"tga") ||
+ 0 == ASSIMP_stricmp(sz,"tif") ||
+ 0 == ASSIMP_stricmp(sz,"hdr") ||
+ 0 == ASSIMP_stricmp(sz,"ppm") ||
+ 0 == ASSIMP_stricmp(sz,"pfm"))
+ {
+ CBackgroundPainter::Instance().SetTextureBG(szFile);
+ }
+ else if (0 == Assimp::ASSIMP_stricmp(sz,"dds"))
+ {
+ // DDS files could contain skyboxes, but they could also
+ // contain normal 2D textures. The easiest way to find this
+ // out is to open the file and check the header ...
+ FILE* pFile = fopen(szFile,"rb");
+ if (!pFile)
+ return TRUE;
+
+ // header of a dds file (begin)
+ /*
+ DWORD dwMagic
+ DWORD dwSize
+ DWORD dwFlags
+ DWORD dwHeight
+ DWORD dwWidth
+ DWORD dwPitchOrLinearSize
+ DWORD dwDepth
+ DWORD dwMipMapCount -> total with this: 32
+ DWORD dwReserved1[11] -> total with this: 76
+ DDPIXELFORMAT ddpfPixelFormat -> total with this: 108
+ DWORD dwCaps1; -> total with this: 112
+ DWORD dwCaps2; ---< here we are!
+ */
+ DWORD dwCaps = 0;
+ fseek(pFile,112,SEEK_SET);
+ fread(&dwCaps,4,1,pFile);
+
+ if (dwCaps & 0x00000400L /* DDSCAPS2_CUBEMAP_POSITIVEX */) {
+ CLogDisplay::Instance().AddEntry(
+ "[INFO] Assuming this dds file is a skybox ...",
+ D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+
+ CBackgroundPainter::Instance().SetCubeMapBG(szFile);
+ } else {
+ CBackgroundPainter::Instance().SetTextureBG(szFile);
+ }
+ fclose(pFile);
+ } else {
+ strcpy(g_szFileName,szFile);
+
+ DeleteAsset();
+ LoadAsset();
+ UpdateHistory();
+ SaveHistory();
+ }
+ }
+ DragFinish(hDrop);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ HMENU hMenu = GetMenu(g_hDlg);
+ if (ID_VIEWER_QUIT == LOWORD(wParam)) {
+ PostQuitMessage(0);
+ DestroyWindow(hwndDlg);
+ } else if (IDC_COMBO1 == LOWORD(wParam)) {
+ if(HIWORD(wParam) == CBN_SELCHANGE) {
+ const size_t sel = static_cast<size_t>(ComboBox_GetCurSel(GetDlgItem(hwndDlg,IDC_COMBO1)));
+ if(g_pcAsset) {
+ g_pcAsset->mAnimator->SetAnimIndex(sel);
+ SendDlgItemMessage(hwndDlg,IDC_SLIDERANIM,TBM_SETPOS,TRUE,0);
+ }
+ }
+ } else if (ID_VIEWER_RESETVIEW == LOWORD(wParam)) {
+ g_sCamera.vPos = aiVector3D(0.0f,0.0f,-10.0f);
+ g_sCamera.vLookAt = aiVector3D(0.0f,0.0f,1.0f);
+ g_sCamera.vUp = aiVector3D(0.0f,1.0f,0.0f);
+ g_sCamera.vRight = aiVector3D(0.0f,1.0f,0.0f);
+ g_mWorldRotate = aiMatrix4x4();
+ g_mWorld = aiMatrix4x4();
+
+ // don't forget to reset the st
+ CBackgroundPainter::Instance().ResetSB();
+ } else if (ID__HELP == LOWORD(wParam)) {
+ DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_AVHELP),
+ hwndDlg,&HelpDialogProc);
+ } else if (ID__ABOUT == LOWORD(wParam)) {
+ DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_ABOUTBOX),
+ hwndDlg,&AboutMessageProc);
+ } else if (ID_TOOLS_LOGWINDOW == LOWORD(wParam)) {
+ CLogWindow::Instance().Show();
+ } else if (ID__WEBSITE == LOWORD(wParam)) {
+ ShellExecute(nullptr,"open","http://assimp.sourceforge.net","","",SW_SHOW);
+ } else if (ID__WEBSITESF == LOWORD(wParam)) {
+ ShellExecute(nullptr,"open","https://sourceforge.net/projects/assimp","","",SW_SHOW);
+ } else if (ID_REPORTBUG == LOWORD(wParam)) {
+ ShellExecute(nullptr,"open","https://sourceforge.net/tracker/?func=add&group_id=226462&atid=1067632","","",SW_SHOW);
+ } else if (ID_FR == LOWORD(wParam)) {
+ ShellExecute(nullptr,"open","https://sourceforge.net/forum/forum.php?forum_id=817653","","",SW_SHOW);
+ } else if (ID_TOOLS_CLEARLOG == LOWORD(wParam)) {
+ CLogWindow::Instance().Clear();
+ } else if (ID_TOOLS_SAVELOGTOFILE == LOWORD(wParam)) {
+ CLogWindow::Instance().Save();
+ } else if (ID_VIEWER_MEMORYCONSUMATION == LOWORD(wParam)) {
+ DisplayMemoryConsumption();
+ } else if (ID_VIEWER_H == LOWORD(wParam)) {
+ MakeFileAssociations();
+ } else if (ID_BACKGROUND_CLEAR == LOWORD(wParam)) {
+ ClearBG();
+ } else if (ID_BACKGROUND_SETCOLOR == LOWORD(wParam)) {
+ ChooseBGColor();
+ } else if (ID_BACKGROUND_LOADTEXTURE == LOWORD(wParam)) {
+ LoadBGTexture();
+ } else if (ID_BACKGROUND_LOADSKYBOX == LOWORD(wParam)) {
+ LoadSkybox();
+ } else if (ID_VIEWER_SAVESCREENSHOTTOFILE == LOWORD(wParam)) {
+ SaveScreenshot();
+ } else if (ID_VIEWER_OPEN == LOWORD(wParam)) {
+ OpenAsset();
+ } else if (ID_TOOLS_FLIPNORMALS == LOWORD(wParam)) {
+ if (g_pcAsset && g_pcAsset->pcScene) {
+ g_pcAsset->FlipNormals();
+ }
+ }
+ // this is ugly. anyone willing to rewrite it from scratch using wxwidgets or similar?
+ else if (ID_VIEWER_PP_JIV == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_JoinIdenticalVertices;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_JIV,ppsteps & aiProcess_JoinIdenticalVertices ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ } else if (ID_VIEWER_PP_CTS == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_CalcTangentSpace;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_CTS,ppsteps & aiProcess_CalcTangentSpace ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ } else if (ID_VIEWER_PP_FD == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_FindDegenerates;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FD,ppsteps & aiProcess_FindDegenerates ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ } else if (ID_VIEWER_PP_FID == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_FindInvalidData;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FID,ppsteps & aiProcess_FindInvalidData ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_FIM == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_FindInstances;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FIM,ppsteps & aiProcess_FindInstances ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_FIN == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_FixInfacingNormals;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_FIN,ppsteps & aiProcess_FixInfacingNormals ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_GUV == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_GenUVCoords;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_GUV,ppsteps & aiProcess_GenUVCoords ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_ICL == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_ImproveCacheLocality;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_ICL,ppsteps & aiProcess_ImproveCacheLocality ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_OG == LOWORD(wParam)) {
+ if (ppsteps & aiProcess_PreTransformVertices) {
+ CLogDisplay::Instance().AddEntry("[ERROR] This setting is incompatible with \'Pretransform Vertices\'");
+ }
+ else {
+ ppsteps ^= aiProcess_OptimizeGraph;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_OG,ppsteps & aiProcess_OptimizeGraph ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ }
+ else if (ID_VIEWER_PP_OM == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_OptimizeMeshes;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_OM,ppsteps & aiProcess_OptimizeMeshes ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_PTV == LOWORD(wParam)) {
+ if (ppsteps & aiProcess_OptimizeGraph) {
+ CLogDisplay::Instance().AddEntry("[ERROR] This setting is incompatible with \'Optimize Scenegraph\'");
+ }
+ else {
+ ppsteps ^= aiProcess_PreTransformVertices;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_PTV,ppsteps & aiProcess_PreTransformVertices ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ }
+ else if (ID_VIEWER_PP_RRM2 == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_RemoveRedundantMaterials;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_RRM2,ppsteps & aiProcess_RemoveRedundantMaterials ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_TUV == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_TransformUVCoords;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_TUV,ppsteps & aiProcess_TransformUVCoords ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_DB == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_Debone;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_DB,ppsteps & aiProcess_Debone ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_PP_VDS == LOWORD(wParam)) {
+ ppsteps ^= aiProcess_ValidateDataStructure;
+ CheckMenuItem(hMenu,ID_VIEWER_PP_VDS,ppsteps & aiProcess_ValidateDataStructure ? MF_CHECKED : MF_UNCHECKED);
+ UpdatePPSettings();
+ }
+ else if (ID_VIEWER_RELOAD == LOWORD(wParam))
+ {
+ DeleteAsset();
+ LoadAsset();
+ }
+ else if (ID_IMPORTSETTINGS_RESETTODEFAULT == LOWORD(wParam))
+ {
+ ppsteps = ppstepsdefault;
+ UpdatePPSettings();
+ SetupPPUIState();
+ }
+ else if (ID_IMPORTSETTINGS_OPENPOST == LOWORD(wParam))
+ {
+ ShellExecute(nullptr,"open","http://assimp.sourceforge.net/lib_html/ai_post_process_8h.html","","",SW_SHOW);
+ }
+ else if (ID_TOOLS_ORIGINALNORMALS == LOWORD(wParam))
+ {
+ if (g_pcAsset && g_pcAsset->pcScene)
+ {
+ g_pcAsset->SetNormalSet(AssimpView::AssetHelper::ORIGINAL);
+ CheckMenuItem(hMenu,ID_TOOLS_ORIGINALNORMALS,MF_BYCOMMAND | MF_CHECKED);
+ CheckMenuItem(hMenu,ID_TOOLS_HARDNORMALS,MF_BYCOMMAND | MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_TOOLS_SMOOTHNORMALS,MF_BYCOMMAND | MF_UNCHECKED);
+ }
+ }
+
+ else if (ID_TOOLS_SMOOTHNORMALS == LOWORD(wParam))
+ {
+ if (g_pcAsset && g_pcAsset->pcScene)
+ {
+ g_pcAsset->SetNormalSet(AssimpView::AssetHelper::SMOOTH);
+ CheckMenuItem(hMenu,ID_TOOLS_ORIGINALNORMALS,MF_BYCOMMAND | MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_TOOLS_HARDNORMALS,MF_BYCOMMAND | MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_TOOLS_SMOOTHNORMALS,MF_BYCOMMAND | MF_CHECKED);
+ }
+ }
+ else if (ID_TOOLS_HARDNORMALS == LOWORD(wParam))
+ {
+ if (g_pcAsset && g_pcAsset->pcScene)
+ {
+ g_pcAsset->SetNormalSet(AssimpView::AssetHelper::HARD);
+ CheckMenuItem(hMenu,ID_TOOLS_ORIGINALNORMALS,MF_BYCOMMAND | MF_UNCHECKED);
+ CheckMenuItem(hMenu,ID_TOOLS_HARDNORMALS,MF_BYCOMMAND | MF_CHECKED);
+ CheckMenuItem(hMenu,ID_TOOLS_SMOOTHNORMALS,MF_BYCOMMAND | MF_UNCHECKED);
+ }
+ }
+ else if (ID_TOOLS_STEREOVIEW == LOWORD(wParam))
+ {
+ g_sOptions.bStereoView =! g_sOptions.bStereoView;
+
+ HMENU menu = ::GetMenu(g_hDlg);
+ if (g_sOptions.bStereoView) {
+ ::ModifyMenu(menu,ID_TOOLS_STEREOVIEW,
+ MF_BYCOMMAND | MF_CHECKED | MF_STRING,ID_TOOLS_STEREOVIEW,"Stereo view");
+
+ CLogDisplay::Instance().AddEntry("[INFO] Switched to stereo mode",
+ D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ } else {
+ ModifyMenu(menu,ID_TOOLS_STEREOVIEW,
+ MF_BYCOMMAND | MF_UNCHECKED | MF_STRING,ID_TOOLS_STEREOVIEW,"Stereo view");
+
+ CLogDisplay::Instance().AddEntry("[INFO] Switched to mono mode",
+ D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0));
+ }
+ } else if (ID_TOOLS_SETANGLELIMIT == LOWORD(wParam)) {
+ DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_DIALOGSMOOTH),g_hDlg,&SMMessageProc);
+ } else if (ID_VIEWER_CLEARHISTORY == LOWORD(wParam)) {
+ ClearHistory();
+ } else if (ID_VIEWER_CLOSEASSET == LOWORD(wParam)) {
+ DeleteAssetData();
+ DeleteAsset();
+ }
+ else if (BN_CLICKED == HIWORD(wParam))
+ {
+ if (IDC_TOGGLEMS == LOWORD(wParam))
+ {
+ ToggleMS();
+ }
+ else if (IDC_TOGGLEMAT == LOWORD(wParam))
+ {
+ ToggleMats();
+ }
+ else if (IDC_LCOLOR1 == LOWORD(wParam))
+ {
+
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode() ||
+ CDisplay::VIEWMODE_MATERIAL == CDisplay::Instance().GetViewMode())
+ {
+ // hey, I'm tired and yes, I KNOW IT IS EVIL!
+ DisplayColorDialog(const_cast<D3DXVECTOR4*>(CDisplay::Instance().GetFirstCheckerColor()));
+ SaveCheckerPatternColors();
+ }
+ else
+ {
+ DisplayColorDialog(&g_avLightColors[0]);
+ SaveLightColors();
+ }
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR1),nullptr,TRUE);
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR1));
+ }
+ else if (IDC_LCOLOR2 == LOWORD(wParam))
+ {
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode() ||
+ CDisplay::VIEWMODE_MATERIAL == CDisplay::Instance().GetViewMode())
+ {
+ // hey, I'm tired and yes, I KNOW IT IS EVIL!
+ DisplayColorDialog(const_cast<D3DXVECTOR4*>(CDisplay::Instance().GetSecondCheckerColor()));
+ SaveCheckerPatternColors();
+ }
+ else
+ {
+ DisplayColorDialog(&g_avLightColors[1]);
+ SaveLightColors();
+ }
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR2),nullptr,TRUE);
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR2));
+ }
+ else if (IDC_LCOLOR3 == LOWORD(wParam))
+ {
+ DisplayColorDialog(&g_avLightColors[2]);
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR3),nullptr,TRUE);
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR3));
+ SaveLightColors();
+ }
+ else if (IDC_LRESET == LOWORD(wParam))
+ {
+ if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode() ||
+ CDisplay::VIEWMODE_MATERIAL == CDisplay::Instance().GetViewMode())
+ {
+ CDisplay::Instance().SetFirstCheckerColor(D3DXVECTOR4(0.4f,0.4f,0.4f,1.0f));
+ CDisplay::Instance().SetSecondCheckerColor(D3DXVECTOR4(0.6f,0.6f,0.6f,1.0f));
+ SaveCheckerPatternColors();
+ }
+ else
+ {
+ g_avLightColors[0] = D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0xFF);
+ g_avLightColors[1] = D3DCOLOR_ARGB(0xFF,0xFF,0x00,0x00);
+ g_avLightColors[2] = D3DCOLOR_ARGB(0xFF,0x05,0x05,0x05);
+ SaveLightColors();
+ }
+
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR1),nullptr,TRUE);
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR1));
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR2),nullptr,TRUE);
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR2));
+ InvalidateRect(GetDlgItem(g_hDlg,IDC_LCOLOR3),nullptr,TRUE);
+ UpdateWindow(GetDlgItem(g_hDlg,IDC_LCOLOR3));
+ }
+ else if (IDC_NOSPECULAR == LOWORD(wParam))
+ {
+ ToggleSpecular();
+ }
+ else if (IDC_NOAB == LOWORD(wParam))
+ {
+ ToggleTransparency();
+ }
+ else if (IDC_ZOOM == LOWORD(wParam))
+ {
+ ToggleFPSView();
+ }
+ else if (IDC_BLUBB == LOWORD(wParam))
+ {
+ ToggleUIState();
+ }
+ else if (IDC_TOGGLENORMALS == LOWORD(wParam))
+ {
+ ToggleNormals();
+ }
+ else if (IDC_LOWQUALITY == LOWORD(wParam))
+ {
+ ToggleLowQuality();
+ }
+ else if (IDC_3LIGHTS == LOWORD(wParam))
+ {
+ ToggleMultipleLights();
+ }
+ else if (IDC_LIGHTROTATE == LOWORD(wParam))
+ {
+ ToggleLightRotate();
+ }
+ else if (IDC_AUTOROTATE == LOWORD(wParam))
+ {
+ ToggleAutoRotate();
+ }
+ else if (IDC_TOGGLEWIRE == LOWORD(wParam))
+ {
+ ToggleWireFrame();
+ }
+ else if (IDC_SHOWSKELETON == LOWORD(wParam))
+ {
+ ToggleSkeleton();
+ }
+ else if (IDC_BFCULL == LOWORD(wParam))
+ {
+ ToggleCulling();
+ }
+ else if (IDC_PLAY == LOWORD(wParam))
+ {
+ g_bPlay = !g_bPlay;
+ SetDlgItemText(g_hDlg,IDC_PLAY,(g_bPlay ? "Stop" : "Play"));
+
+ if (g_bPlay)
+ EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),FALSE);
+ else EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),TRUE);
+ }
+ }
+ // check the file history
+ for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i)
+ {
+ if (AI_VIEW_RECENT_FILE_ID(i) == LOWORD(wParam))
+ {
+ strcpy(g_szFileName,g_aPreviousFiles[i].c_str());
+ DeleteAssetData();
+ DeleteAsset();
+ LoadAsset();
+
+ // update and safe the history
+ UpdateHistory();
+ SaveHistory();
+ }
+ }
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+ if (LOWORD(wParam) >= AI_VIEW_EXPORT_FMT_BASE && LOWORD(wParam) < AI_VIEW_EXPORT_FMT_BASE+Assimp::Exporter().GetExportFormatCount()) {
+ DoExport(LOWORD(wParam) - AI_VIEW_EXPORT_FMT_BASE);
+ }
+#endif
+
+ // handle popup menus for the tree window
+ CDisplay::Instance().HandleTreeViewPopup(wParam,lParam);
+
+ return TRUE;
+ };
+ return FALSE;
+ }
+
+
+//-------------------------------------------------------------------------------
+// Message prcoedure for the progress dialog
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK ProgressMessageProc(HWND hwndDlg,UINT uMsg,
+ WPARAM wParam,LPARAM lParam)
+ {
+ UNREFERENCED_PARAMETER(lParam);
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+
+ SendDlgItemMessage(hwndDlg,IDC_PROGRESS,PBM_SETRANGE,0,
+ MAKELPARAM(0,500));
+
+ SetTimer(hwndDlg,0,40,nullptr);
+ return TRUE;
+
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return TRUE;
+
+ case WM_COMMAND:
+
+ if (IDOK == LOWORD(wParam))
+ {
+#if 0
+ g_bLoadingCanceled = true;
+ TerminateThread(g_hThreadHandle,5);
+ g_pcAsset = nullptr;
+
+ EndDialog(hwndDlg,0);
+#endif
+
+ // PROBLEM: If we terminate the loader thread, ASSIMP's state
+ // is undefined. Any further attempts to load assets will
+ // fail.
+ exit(5);
+// return TRUE;
+ }
+ case WM_TIMER:
+
+ UINT iPos = (UINT)SendDlgItemMessage(hwndDlg,IDC_PROGRESS,PBM_GETPOS,0,0);
+ iPos += 10;
+ if (iPos > 490)iPos = 0;
+ SendDlgItemMessage(hwndDlg,IDC_PROGRESS,PBM_SETPOS,iPos,0);
+
+ if (g_bLoadingFinished)
+ {
+ EndDialog(hwndDlg,0);
+ return TRUE;
+ }
+
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+
+//-------------------------------------------------------------------------------
+// Message procedure for the about dialog
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK AboutMessageProc(HWND hwndDlg,UINT uMsg,
+ WPARAM wParam,LPARAM lParam)
+ {
+ UNREFERENCED_PARAMETER(lParam);
+ switch (uMsg)
+ {
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ return TRUE;
+
+ case WM_COMMAND:
+
+ if (IDOK == LOWORD(wParam))
+ {
+ EndDialog(hwndDlg,0);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+}
+
+using namespace AssimpView;
+
+//-------------------------------------------------------------------------------
+// Entry point to the application
+//-------------------------------------------------------------------------------
+int APIENTRY _tWinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine,
+ int nCmdShow)
+{
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ // needed for the RichEdit control in the about/help dialog
+ LoadLibrary( "riched20.dll" );
+
+ // load windows common controls library to get XP style
+ InitCommonControls();
+
+ // initialize the IDirect3D9 interface
+ g_hInstance = hInstance;
+ if (0 == InitD3D()) {
+ MessageBox(nullptr,"Failed to initialize Direct3D 9",
+ "ASSIMP ModelViewer",MB_OK);
+ return -6;
+ }
+
+ // create the main dialog
+ HWND hDlg = CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOGMAIN),
+ nullptr,&MessageProc);
+
+ // ensure we get high priority
+ ::SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
+
+ // initialize the default logger if necessary
+ Assimp::DefaultLogger::create("",Assimp::Logger::VERBOSE);
+
+ CLogWindow::Instance().pcStream = new CMyLogStream();
+ Assimp::DefaultLogger::get()->attachStream(CLogWindow::Instance().pcStream,
+ Assimp::DefaultLogger::Debugging | Assimp::DefaultLogger::Info |
+ Assimp::DefaultLogger::Err | Assimp::DefaultLogger::Warn);
+
+ if (nullptr == hDlg) {
+ MessageBox(nullptr,"Failed to create dialog from resource",
+ "ASSIMP ModelViewer",MB_OK);
+ return -5;
+ }
+
+ // display the window
+ g_hDlg = hDlg;
+ MSG uMsg;
+ memset(&uMsg,0,sizeof( MSG));
+ ShowWindow( hDlg, nCmdShow );
+ UpdateWindow( hDlg );
+
+ // create the D3D device object
+ if (0 == CreateDevice(g_sOptions.bMultiSample,false,true)) {
+ MessageBox(nullptr,"Failed to initialize Direct3D 9 (2)",
+ "ASSIMP ModelViewer",MB_OK);
+ return -4;
+ }
+
+ CLogDisplay::Instance().AddEntry("[OK] Here we go!");
+
+ // create the log window
+ CLogWindow::Instance().Init();
+ // set the focus to the main window
+ SetFocus(g_hDlg);
+
+ // recover background skyboxes/textures from the last session
+ HKEY hRegistry;
+ union {
+ char szFileName[MAX_PATH];
+ D3DCOLOR clrColor;
+ };
+ DWORD dwTemp = MAX_PATH;
+ RegCreateKeyEx(HKEY_CURRENT_USER,
+ "Software\\ASSIMP\\Viewer",0,nullptr,0,KEY_ALL_ACCESS, nullptr, &hRegistry,nullptr);
+ if(ERROR_SUCCESS == RegQueryValueEx(hRegistry,"LastSkyBoxSrc",nullptr,nullptr,
+ (BYTE*)szFileName,&dwTemp) && '\0' != szFileName[0])
+ {
+ CBackgroundPainter::Instance().SetCubeMapBG(szFileName);
+ }
+ else if(ERROR_SUCCESS == RegQueryValueEx(hRegistry,"LastTextureSrc",nullptr,nullptr,
+ (BYTE*)szFileName,&dwTemp) && '\0' != szFileName[0])
+ {
+ CBackgroundPainter::Instance().SetTextureBG(szFileName);
+ }
+ else if(ERROR_SUCCESS == RegQueryValueEx(hRegistry,"Color",nullptr,nullptr,
+ (BYTE*)&clrColor,&dwTemp))
+ {
+ CBackgroundPainter::Instance().SetColor(clrColor);
+ }
+ RegCloseKey(hRegistry);
+
+ // now handle command line arguments
+ HandleCommandLine(lpCmdLine);
+
+ double adLast[30];
+ for (int i = 0; i < 30;++i)adLast[i] = 0.0f;
+ int iCurrent = 0;
+
+ double g_dCurTime = 0;
+ double g_dLastTime = 0;
+ while( uMsg.message != WM_QUIT )
+ {
+ if( PeekMessage( &uMsg, nullptr, 0, 0, PM_REMOVE ) )
+ {
+ TranslateMessage( &uMsg );
+ DispatchMessage( &uMsg );
+
+ if (WM_CHAR == uMsg.message)
+ {
+
+ switch ((char)uMsg.wParam)
+ {
+ case 'M':
+ case 'm':
+
+ CheckDlgButton(g_hDlg,IDC_TOGGLEMS,
+ IsDlgButtonChecked(g_hDlg,IDC_TOGGLEMS) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleMS();
+ break;
+
+ case 'L':
+ case 'l':
+
+ CheckDlgButton(g_hDlg,IDC_3LIGHTS,
+ IsDlgButtonChecked(g_hDlg,IDC_3LIGHTS) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleMultipleLights();
+ break;
+
+ case 'P':
+ case 'p':
+
+ CheckDlgButton(g_hDlg,IDC_LOWQUALITY,
+ IsDlgButtonChecked(g_hDlg,IDC_LOWQUALITY) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleLowQuality();
+ break;
+
+ case 'D':
+ case 'd':
+
+ CheckDlgButton(g_hDlg,IDC_TOGGLEMAT,
+ IsDlgButtonChecked(g_hDlg,IDC_TOGGLEMAT) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleMats();
+ break;
+
+
+ case 'N':
+ case 'n':
+
+ CheckDlgButton(g_hDlg,IDC_TOGGLENORMALS,
+ IsDlgButtonChecked(g_hDlg,IDC_TOGGLENORMALS) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+ ToggleNormals();
+ break;
+
+
+ case 'S':
+ case 's':
+
+ CheckDlgButton(g_hDlg,IDC_NOSPECULAR,
+ IsDlgButtonChecked(g_hDlg,IDC_NOSPECULAR) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleSpecular();
+ break;
+
+ case 'A':
+ case 'a':
+
+ CheckDlgButton(g_hDlg,IDC_AUTOROTATE,
+ IsDlgButtonChecked(g_hDlg,IDC_AUTOROTATE) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleAutoRotate();
+ break;
+
+
+ case 'R':
+ case 'r':
+
+ CheckDlgButton(g_hDlg,IDC_LIGHTROTATE,
+ IsDlgButtonChecked(g_hDlg,IDC_LIGHTROTATE) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleLightRotate();
+ break;
+
+ case 'Z':
+ case 'z':
+
+ CheckDlgButton(g_hDlg,IDC_ZOOM,
+ IsDlgButtonChecked(g_hDlg,IDC_ZOOM) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleFPSView();
+ break;
+
+
+ case 'W':
+ case 'w':
+
+ CheckDlgButton(g_hDlg,IDC_TOGGLEWIRE,
+ IsDlgButtonChecked(g_hDlg,IDC_TOGGLEWIRE) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleWireFrame();
+ break;
+
+ case 'K':
+ case 'k':
+
+ CheckDlgButton(g_hDlg,IDC_SHOWSKELETON,
+ IsDlgButtonChecked(g_hDlg,IDC_SHOWSKELETON) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleSkeleton();
+ break;
+
+ case 'C':
+ case 'c':
+
+ CheckDlgButton(g_hDlg,IDC_BFCULL,
+ IsDlgButtonChecked(g_hDlg,IDC_BFCULL) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleCulling();
+ break;
+
+ case 'T':
+ case 't':
+
+ CheckDlgButton(g_hDlg,IDC_NOAB,
+ IsDlgButtonChecked(g_hDlg,IDC_NOAB) == BST_CHECKED
+ ? BST_UNCHECKED : BST_CHECKED);
+
+ ToggleTransparency();
+ break;
+ }
+ }
+ }
+
+
+ // render the scene
+ CDisplay::Instance().OnRender();
+
+ // measure FPS, average it out
+ g_dCurTime = timeGetTime();
+ g_fElpasedTime = (float)((g_dCurTime - g_dLastTime) * 0.001);
+ g_dLastTime = g_dCurTime;
+
+ adLast[iCurrent++] = 1.0f / g_fElpasedTime;
+
+ double dFPS = 0.0;
+ for (int i = 0; i < 30; ++i) {
+ dFPS += adLast[ i ];
+ }
+ dFPS /= 30.0;
+
+ if (30 == iCurrent) {
+ iCurrent = 0;
+ if (dFPS != g_fFPS) {
+ g_fFPS = dFPS;
+ char szOut[256];
+
+ sprintf(szOut,"%i",(int)floorf((float)dFPS+0.5f));
+ SetDlgItemText(g_hDlg,IDC_EFPS,szOut);
+ }
+ }
+ }
+ DeleteAsset();
+ Assimp::DefaultLogger::kill();
+ ShutdownDevice();
+ ShutdownD3D();
+
+ return 0;
+}
diff --git a/libs/assimp/tools/assimp_view/NOTE@help.rtf.txt b/libs/assimp/tools/assimp_view/NOTE@help.rtf.txt
new file mode 100644
index 0000000..dd20078
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/NOTE@help.rtf.txt
@@ -0,0 +1,2 @@
+text1.bin is the corresponding bin file to be included with the executable file.
+When updating the rich formatted text inside Visual Studio, a terminating 0 character must be appended
diff --git a/libs/assimp/tools/assimp_view/Normals.cpp b/libs/assimp/tools/assimp_view/Normals.cpp
new file mode 100644
index 0000000..b764089
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Normals.cpp
@@ -0,0 +1,155 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+
+#include "PostProcessing/CalcTangentsProcess.h"
+#include "PostProcessing/GenFaceNormalsProcess.h"
+#include "PostProcessing/GenVertexNormalsProcess.h"
+#include "PostProcessing/JoinVerticesProcess.h"
+#include "PostProcessing/MakeVerboseFormat.h"
+
+namespace AssimpView {
+
+using namespace Assimp;
+
+bool g_bWasFlipped = false;
+float g_smoothAngle = 80.f;
+
+//-------------------------------------------------------------------------------
+// Flip all normal vectors
+//-------------------------------------------------------------------------------
+void AssetHelper::FlipNormalsInt() {
+ // invert all normal vectors
+ for (unsigned int i = 0; i < this->pcScene->mNumMeshes; ++i) {
+ aiMesh *pcMesh = this->pcScene->mMeshes[i];
+
+ if (!pcMesh->mNormals) {
+ continue;
+ }
+
+ for (unsigned int a = 0; a < pcMesh->mNumVertices; ++a) {
+ pcMesh->mNormals[a] *= -1.0f;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------
+void AssetHelper::FlipNormals() {
+ FlipNormalsInt();
+
+ // recreate native data
+ DeleteAssetData(true);
+ CreateAssetData();
+ g_bWasFlipped = !g_bWasFlipped;
+}
+
+//-------------------------------------------------------------------------------
+// Set the normal set of the scene
+//-------------------------------------------------------------------------------
+void AssetHelper::SetNormalSet(unsigned int iSet) {
+ // we need to build an unique set of vertices for this ...
+ {
+ MakeVerboseFormatProcess *pcProcess = new MakeVerboseFormatProcess();
+ pcProcess->Execute(pcScene);
+ delete pcProcess;
+
+ for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
+ if (!apcMeshes[i]->pvOriginalNormals) {
+ apcMeshes[i]->pvOriginalNormals = new aiVector3D[pcScene->mMeshes[i]->mNumVertices];
+ memcpy(apcMeshes[i]->pvOriginalNormals, pcScene->mMeshes[i]->mNormals,
+ pcScene->mMeshes[i]->mNumVertices * sizeof(aiVector3D));
+ }
+ delete[] pcScene->mMeshes[i]->mNormals;
+ pcScene->mMeshes[i]->mNormals = nullptr;
+ }
+ }
+
+ // now we can start to calculate a new set of normals
+ if (HARD == iSet) {
+ GenFaceNormalsProcess *pcProcess = new GenFaceNormalsProcess();
+ pcProcess->Execute(pcScene);
+ FlipNormalsInt();
+ delete pcProcess;
+ } else if (SMOOTH == iSet) {
+ GenVertexNormalsProcess *pcProcess = new GenVertexNormalsProcess();
+ pcProcess->SetMaxSmoothAngle((float)AI_DEG_TO_RAD(g_smoothAngle));
+ pcProcess->Execute(pcScene);
+ FlipNormalsInt();
+ delete pcProcess;
+ } else if (ORIGINAL == iSet) {
+ for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
+ if (apcMeshes[i]->pvOriginalNormals) {
+ delete[] pcScene->mMeshes[i]->mNormals;
+ pcScene->mMeshes[i]->mNormals = apcMeshes[i]->pvOriginalNormals;
+ apcMeshes[i]->pvOriginalNormals = nullptr;
+ }
+ }
+ }
+
+ // recalculate tangents and bitangents
+ Assimp::BaseProcess *pcProcess = new CalcTangentsProcess();
+ pcProcess->Execute(pcScene);
+ delete pcProcess;
+
+ // join the mesh vertices again
+ pcProcess = new JoinVerticesProcess();
+ pcProcess->Execute(pcScene);
+ delete pcProcess;
+
+ iNormalSet = iSet;
+
+ if (g_bWasFlipped) {
+ // invert all normal vectors
+ for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
+ aiMesh *pcMesh = pcScene->mMeshes[i];
+ for (unsigned int a = 0; a < pcMesh->mNumVertices; ++a) {
+ pcMesh->mNormals[a] *= -1.0f;
+ }
+ }
+ }
+
+ // recreate native data
+ DeleteAssetData(true);
+ CreateAssetData();
+}
+
+} // namespace AssimpView
diff --git a/libs/assimp/tools/assimp_view/RenderOptions.h b/libs/assimp/tools/assimp_view/RenderOptions.h
new file mode 100644
index 0000000..6929741
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/RenderOptions.h
@@ -0,0 +1,113 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_RO_H_INCLUDED)
+#define AV_RO_H_INCLUDED
+
+
+//-------------------------------------------------------------------------------
+/** \brief Class to manage render options. One global instance
+*/
+//-------------------------------------------------------------------------------
+class RenderOptions
+ {
+ public:
+
+ // enumerates different drawing modi. POINT is currently
+ // not supported and probably will never be.
+ enum DrawMode {NORMAL, WIREFRAME, POINT};
+
+ inline RenderOptions (void) :
+ bMultiSample (true),
+ bSuperSample (false),
+ bRenderMats (true),
+ bRenderNormals (false),
+ b3Lights (false),
+ bLightRotate (false),
+ bRotate (true),
+ bLowQuality (false),
+ bNoSpecular (false),
+ bStereoView (false),
+ bNoAlphaBlending(false),
+ eDrawMode (NORMAL),
+ bCulling (false),
+ bSkeleton (false)
+
+ {}
+
+ bool bMultiSample;
+
+ // SuperSampling has not yet been implemented
+ bool bSuperSample;
+
+ // Display the real material of the object
+ bool bRenderMats;
+
+ // Render the normals
+ bool bRenderNormals;
+
+ // Use 2 directional light sources
+ bool b3Lights;
+
+ // Automatically rotate the light source(s)
+ bool bLightRotate;
+
+ // Automatically rotate the asset around its origin
+ bool bRotate;
+
+ // use standard lambertian lighting
+ bool bLowQuality;
+
+ // disable specular lighting got all elements in the scene
+ bool bNoSpecular;
+
+ // enable stereo view
+ bool bStereoView;
+
+ bool bNoAlphaBlending;
+
+ // wireframe or solid rendering?
+ DrawMode eDrawMode;
+
+ bool bCulling,bSkeleton;
+ };
+
+#endif // !! IG
diff --git a/libs/assimp/tools/assimp_view/SceneAnimator.cpp b/libs/assimp/tools/assimp_view/SceneAnimator.cpp
new file mode 100644
index 0000000..c8b2022
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/SceneAnimator.cpp
@@ -0,0 +1,235 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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 SceneAnimator.cpp
+ * @brief Implementation of the utility class SceneAnimator
+ */
+
+#include "assimp_view.h"
+
+using namespace AssimpView;
+
+const aiMatrix4x4 IdentityMatrix;
+
+// ------------------------------------------------------------------------------------------------
+// Constructor for a given scene.
+SceneAnimator::SceneAnimator(const aiScene *pScene, size_t pAnimIndex) :
+ mScene(pScene),
+ mCurrentAnimIndex(-1),
+ mAnimEvaluator(nullptr),
+ mRootNode(nullptr) {
+ // build the nodes-for-bones table
+ for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
+ const aiMesh *mesh = pScene->mMeshes[i];
+ for (unsigned int n = 0; n < mesh->mNumBones; ++n) {
+ const aiBone *bone = mesh->mBones[n];
+
+ mBoneNodesByName[bone->mName.data] = pScene->mRootNode->FindNode(bone->mName);
+ }
+ }
+
+ // changing the current animation also creates the node tree for this animation
+ SetAnimIndex(pAnimIndex);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor
+SceneAnimator::~SceneAnimator() {
+ delete mRootNode;
+ delete mAnimEvaluator;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Sets the animation to use for playback.
+void SceneAnimator::SetAnimIndex(size_t pAnimIndex) {
+ // no change
+ if (pAnimIndex == static_cast<unsigned int>(mCurrentAnimIndex)) {
+ return;
+ }
+
+ // kill data of the previous anim
+ delete mRootNode;
+ mRootNode = nullptr;
+ delete mAnimEvaluator;
+ mAnimEvaluator = nullptr;
+ mNodesByName.clear();
+
+ mCurrentAnimIndex = static_cast<int>(pAnimIndex);
+
+ // create the internal node tree. Do this even in case of invalid animation index
+ // so that the transformation matrices are properly set up to mimic the current scene
+ mRootNode = CreateNodeTree(mScene->mRootNode, nullptr);
+
+ // invalid anim index
+ if (static_cast<unsigned int>(mCurrentAnimIndex) >= mScene->mNumAnimations) {
+ return;
+ }
+
+ // create an evaluator for this animation
+ mAnimEvaluator = new AnimEvaluator(mScene->mAnimations[mCurrentAnimIndex]);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Calculates the node transformations for the scene.
+void SceneAnimator::Calculate(double pTime) {
+ // invalid anim
+ if (!mAnimEvaluator) {
+ return;
+ }
+
+ // calculate current local transformations
+ mAnimEvaluator->Evaluate(pTime);
+
+ // and update all node transformations with the results
+ UpdateTransforms(mRootNode, mAnimEvaluator->GetTransformations());
+}
+
+// ------------------------------------------------------------------------------------------------
+// Retrieves the most recent local transformation matrix for the given node.
+const aiMatrix4x4 &SceneAnimator::GetLocalTransform(const aiNode *node) const {
+ NodeMap::const_iterator it = mNodesByName.find(node);
+ if (it == mNodesByName.end()) {
+ return IdentityMatrix;
+ }
+
+ return it->second->mLocalTransform;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Retrieves the most recent global transformation matrix for the given node.
+const aiMatrix4x4 &SceneAnimator::GetGlobalTransform(const aiNode *node) const {
+ NodeMap::const_iterator it = mNodesByName.find(node);
+ if (it == mNodesByName.end()) {
+ return IdentityMatrix;
+ }
+
+ return it->second->mGlobalTransform;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Calculates the bone matrices for the given mesh.
+const std::vector<aiMatrix4x4> &SceneAnimator::GetBoneMatrices(const aiNode *pNode, size_t pMeshIndex /* = 0 */) {
+ ai_assert(pMeshIndex < pNode->mNumMeshes);
+ size_t meshIndex = pNode->mMeshes[pMeshIndex];
+ ai_assert(meshIndex < mScene->mNumMeshes);
+ const aiMesh *mesh = mScene->mMeshes[meshIndex];
+
+ // resize array and initialize it with identity matrices
+ mTransforms.resize(mesh->mNumBones, aiMatrix4x4());
+
+ // calculate the mesh's inverse global transform
+ aiMatrix4x4 globalInverseMeshTransform = GetGlobalTransform(pNode);
+ globalInverseMeshTransform.Inverse();
+
+ // Bone matrices transform from mesh coordinates in bind pose to mesh coordinates in skinned pose
+ // Therefore the formula is offsetMatrix * currentGlobalTransform * inverseCurrentMeshTransform
+ for (size_t a = 0; a < mesh->mNumBones; ++a) {
+ const aiBone *bone = mesh->mBones[a];
+ const aiMatrix4x4 &currentGlobalTransform = GetGlobalTransform(mBoneNodesByName[bone->mName.data]);
+ mTransforms[a] = globalInverseMeshTransform * currentGlobalTransform * bone->mOffsetMatrix;
+ }
+
+ // and return the result
+ return mTransforms;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Recursively creates an internal node structure matching the current scene and animation.
+SceneAnimNode *SceneAnimator::CreateNodeTree(aiNode *pNode, SceneAnimNode *pParent) {
+ // create a node
+ SceneAnimNode *internalNode = new SceneAnimNode(pNode->mName.data);
+ internalNode->mParent = pParent;
+ mNodesByName[pNode] = internalNode;
+
+ // copy its transformation
+ internalNode->mLocalTransform = pNode->mTransformation;
+ CalculateGlobalTransform(internalNode);
+
+ // find the index of the animation track affecting this node, if any
+ if (static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations) {
+ internalNode->mChannelIndex = -1;
+ const aiAnimation *currentAnim = mScene->mAnimations[mCurrentAnimIndex];
+ for (unsigned int a = 0; a < currentAnim->mNumChannels; a++) {
+ if (currentAnim->mChannels[a]->mNodeName.data == internalNode->mName) {
+ internalNode->mChannelIndex = a;
+ break;
+ }
+ }
+ }
+
+ // continue for all child nodes and assign the created internal nodes as our children
+ for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
+ SceneAnimNode *childNode = CreateNodeTree(pNode->mChildren[a], internalNode);
+ internalNode->mChildren.push_back(childNode);
+ }
+
+ return internalNode;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Recursively updates the internal node transformations from the given matrix array
+void SceneAnimator::UpdateTransforms(SceneAnimNode *pNode, const std::vector<aiMatrix4x4> &pTransforms) {
+ // update node local transform
+ if (pNode->mChannelIndex != -1) {
+ ai_assert(static_cast<unsigned int>(pNode->mChannelIndex) < pTransforms.size());
+ pNode->mLocalTransform = pTransforms[pNode->mChannelIndex];
+ }
+
+ // update global transform as well
+ CalculateGlobalTransform(pNode);
+
+ // continue for all children
+ for (std::vector<SceneAnimNode *>::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it) {
+ UpdateTransforms(*it, pTransforms);
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Calculates the global transformation matrix for the given internal node
+void SceneAnimator::CalculateGlobalTransform(SceneAnimNode *pInternalNode) {
+ // concatenate all parent transforms to get the global transform for this node
+ pInternalNode->mGlobalTransform = pInternalNode->mLocalTransform;
+ SceneAnimNode *node = pInternalNode->mParent;
+ while (node) {
+ pInternalNode->mGlobalTransform = node->mLocalTransform * pInternalNode->mGlobalTransform;
+ node = node->mParent;
+ }
+}
diff --git a/libs/assimp/tools/assimp_view/SceneAnimator.h b/libs/assimp/tools/assimp_view/SceneAnimator.h
new file mode 100644
index 0000000..454357f
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/SceneAnimator.h
@@ -0,0 +1,237 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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 SceneAnimator.h
+ * Manages animations for a given scene and calculates present
+ * transformations for all nodes
+ */
+
+#ifndef AV_SCENEANIMATOR_H_INCLUDED
+#define AV_SCENEANIMATOR_H_INCLUDED
+
+#include <map>
+
+namespace AssimpView {
+
+// ---------------------------------------------------------------------------------
+/** A little tree structure to match the scene's node structure, but holding
+ * additional data. Needs to be public to allow using it in templates at
+ * certain compilers.
+ */
+struct SceneAnimNode {
+ std::string mName;
+ SceneAnimNode *mParent;
+ std::vector<SceneAnimNode *> mChildren;
+
+ //! most recently calculated local transform
+ aiMatrix4x4 mLocalTransform;
+
+ //! same, but in world space
+ aiMatrix4x4 mGlobalTransform;
+
+ //! index in the current animation's channel array. -1 if not animated.
+ int mChannelIndex;
+
+ //! Default construction
+ SceneAnimNode() :
+ mName(), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
+ // empty
+ }
+
+ //! Construction from a given name
+ SceneAnimNode(const std::string &pName) :
+ mName(pName), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
+ // empty
+ }
+
+ //! Destruct all children recursively
+ ~SceneAnimNode() {
+ for (std::vector<SceneAnimNode *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) {
+ delete *it;
+ }
+ }
+};
+
+// ---------------------------------------------------------------------------------
+/** Calculates the animated node transformations for a given scene and timestamp.
+ *
+ * Create an instance for a aiScene you want to animate and set the current animation
+ * to play. You can then have the instance calculate the current pose for all nodes
+ * by calling Calculate() for a given timestamp. After this you can retrieve the
+ * present transformation for a given node by calling GetLocalTransform() or
+ * GetGlobalTransform(). A full set of bone matrices can be retrieved by
+ * GetBoneMatrices() for a given mesh.
+ */
+class SceneAnimator {
+public:
+ // ----------------------------------------------------------------------------
+ /** Constructor for a given scene.
+ *
+ * The object keeps a reference to the scene during its lifetime, but
+ * ownership stays at the caller.
+ * @param pScene The scene to animate.
+ * @param pAnimIndex [optional] Index of the animation to play. Assumed to
+ * be 0 if not given.
+ */
+ SceneAnimator(const aiScene *pScene, size_t pAnimIndex = 0);
+
+ /** Destructor */
+ ~SceneAnimator();
+
+ // ----------------------------------------------------------------------------
+ /** Sets the animation to use for playback. This also recreates the internal
+ * mapping structures, which might take a few cycles.
+ * @param pAnimIndex Index of the animation in the scene's animation array
+ */
+ void SetAnimIndex(size_t pAnimIndex);
+
+ // ----------------------------------------------------------------------------
+ /** Calculates the node transformations for the scene. Call this to get
+ * up-to-date results before calling one of the getters.
+ * @param pTime Current time. Can be an arbitrary range.
+ */
+ void Calculate(double pTime);
+
+ // ----------------------------------------------------------------------------
+ /** Retrieves the most recent local transformation matrix for the given node.
+ *
+ * The returned matrix is in the node's parent's local space, just like the
+ * original node's transformation matrix. If the node is not animated, the
+ * node's original transformation is returned so that you can safely use or
+ * assign it to the node itsself. If there is no node with the given name,
+ * the identity matrix is returned. All transformations are updated whenever
+ * Calculate() is called.
+ * @param pNodeName Name of the node
+ * @return A reference to the node's most recently calculated local
+ * transformation matrix.
+ */
+ const aiMatrix4x4 &GetLocalTransform(const aiNode *node) const;
+
+ // ----------------------------------------------------------------------------
+ /** Retrieves the most recent global transformation matrix for the given node.
+ *
+ * The returned matrix is in world space, which is the same coordinate space
+ * as the transformation of the scene's root node. If the node is not animated,
+ * the node's original transformation is returned so that you can safely use or
+ * assign it to the node itsself. If there is no node with the given name, the
+ * identity matrix is returned. All transformations are updated whenever
+ * Calculate() is called.
+ * @param pNodeName Name of the node
+ * @return A reference to the node's most recently calculated global
+ * transformation matrix.
+ */
+ const aiMatrix4x4 &GetGlobalTransform(const aiNode *node) const;
+
+ // ----------------------------------------------------------------------------
+ /** Calculates the bone matrices for the given mesh.
+ *
+ * Each bone matrix transforms from mesh space in bind pose to mesh space in
+ * skinned pose, it does not contain the mesh's world matrix. Thus the usual
+ * matrix chain for using in the vertex shader is
+ * @code
+ * boneMatrix * worldMatrix * viewMatrix * projMatrix
+ * @endcode
+ * @param pNode The node carrying the mesh.
+ * @param pMeshIndex Index of the mesh in the node's mesh array. The NODE's
+ * mesh array, not the scene's mesh array! Leave out to use the first mesh
+ * of the node, which is usually also the only one.
+ * @return A reference to a vector of bone matrices. Stays stable till the
+ * next call to GetBoneMatrices();
+ */
+ const std::vector<aiMatrix4x4> &GetBoneMatrices(const aiNode *pNode,
+ size_t pMeshIndex = 0);
+
+ // ----------------------------------------------------------------------------
+ /** @brief Get the current animation index
+ */
+ size_t CurrentAnimIndex() const {
+ return mCurrentAnimIndex;
+ }
+
+ // ----------------------------------------------------------------------------
+ /** @brief Get the current animation or NULL
+ */
+ aiAnimation *CurrentAnim() const {
+ return static_cast<unsigned int>(mCurrentAnimIndex) < mScene->mNumAnimations ? mScene->mAnimations[mCurrentAnimIndex] : NULL;
+ }
+
+protected:
+ /** Recursively creates an internal node structure matching the
+ * current scene and animation.
+ */
+ SceneAnimNode *CreateNodeTree(aiNode *pNode, SceneAnimNode *pParent);
+
+ /** Recursively updates the internal node transformations from the
+ * given matrix array
+ */
+ void UpdateTransforms(SceneAnimNode *pNode, const std::vector<aiMatrix4x4> &pTransforms);
+
+ /** Calculates the global transformation matrix for the given internal node */
+ void CalculateGlobalTransform(SceneAnimNode *pInternalNode);
+
+protected:
+ /** The scene we're operating on */
+ const aiScene *mScene;
+
+ /** Current animation index */
+ int mCurrentAnimIndex;
+
+ /** The AnimEvaluator we use to calculate the current pose for the current animation */
+ AnimEvaluator *mAnimEvaluator;
+
+ /** Root node of the internal scene structure */
+ SceneAnimNode *mRootNode;
+
+ /** Name to node map to quickly find nodes by their name */
+ typedef std::map<const aiNode *, SceneAnimNode *> NodeMap;
+ NodeMap mNodesByName;
+
+ /** Name to node map to quickly find nodes for given bones by their name */
+ typedef std::map<const char *, const aiNode *> BoneMap;
+ BoneMap mBoneNodesByName;
+
+ /** Array to return transformations results inside. */
+ std::vector<aiMatrix4x4> mTransforms;
+};
+
+} // end of namespace AssimpView
+
+#endif // AV_SCENEANIMATOR_H_INCLUDED
diff --git a/libs/assimp/tools/assimp_view/Shaders.cpp b/libs/assimp/tools/assimp_view/Shaders.cpp
new file mode 100644
index 0000000..9fd05ca
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Shaders.cpp
@@ -0,0 +1,1397 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+#include "assimp_view.h"
+
+namespace AssimpView {
+
+// ------------------------------------------------------------------------------------------------
+std::string g_szNormalsShader = std::string(
+
+ // World * View * Projection matrix\n"
+ // NOTE: Assume that the material uses a WorldViewProjection matrix\n"
+ "float4x4 WorldViewProjection : WORLDVIEWPROJECTION;\n"
+ "float4 OUTPUT_COLOR;\n"
+
+ // Vertex shader input structure
+ "struct VS_INPUT\n"
+ "{\n"
+ "// Position\n"
+ "float3 Position : POSITION;\n"
+ "};\n"
+
+ // Vertex shader output structure for pixel shader usage
+ "struct VS_OUTPUT\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "};\n"
+
+ // Vertex shader output structure for FixedFunction usage
+ "struct VS_OUTPUT_FF\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float4 Color : COLOR;\n"
+ "};\n"
+
+ // Vertex shader for rendering normals using pixel shader
+ "VS_OUTPUT RenderNormalsVS(VS_INPUT IN)\n"
+ "{\n"
+ "// Initialize the output structure with zero\n"
+ "VS_OUTPUT Out = (VS_OUTPUT)0;\n"
+
+ "// Multiply with the WorldViewProjection matrix\n"
+ "Out.Position = mul(float4(IN.Position,1.0f),WorldViewProjection);\n"
+
+ "return Out;\n"
+ "}\n"
+
+ // Vertex shader for rendering normals using fixed function pipeline
+ "VS_OUTPUT_FF RenderNormalsVS_FF(VS_INPUT IN)\n"
+ "{\n"
+ "VS_OUTPUT_FF Out;\n"
+ "Out.Position = mul(float4(IN.Position,1.0f),WorldViewProjection);\n"
+ "Out.Color = OUTPUT_COLOR;\n"
+ "return Out;\n"
+ "}\n"
+
+ // Pixel shader
+ "float4 RenderNormalsPS() : COLOR\n"
+ "{\n"
+ "return OUTPUT_COLOR;\n"
+ "}\n"
+
+ // Technique for the normal rendering effect (ps_2_0)
+ "technique RenderNormals\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "CullMode=none;\n"
+ "PixelShader = compile ps_2_0 RenderNormalsPS();\n"
+ "VertexShader = compile vs_2_0 RenderNormalsVS();\n"
+ "}\n"
+ "};\n"
+
+ // Technique for the normal rendering effect (fixed function)
+ "technique RenderNormals_FF\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "CullMode=none;\n"
+ "VertexShader = compile vs_2_0 RenderNormalsVS_FF();\n"
+ "ColorOp[0] = SelectArg1;\n"
+ "ColorArg0[0] = Diffuse;\n"
+ "AlphaOp[0] = SelectArg1;\n"
+ "AlphaArg0[0] = Diffuse;\n"
+ "}\n"
+ "};\n");
+
+// ------------------------------------------------------------------------------------------------
+std::string g_szSkyboxShader = std::string(
+
+ // Sampler and texture for the skybox
+ "textureCUBE lw_tex_envmap;\n"
+ "samplerCUBE EnvironmentMapSampler = sampler_state\n"
+ "{\n"
+ "Texture = (lw_tex_envmap);\n"
+ "AddressU = CLAMP;\n"
+ "AddressV = CLAMP;\n"
+ "AddressW = CLAMP;\n"
+
+ "MAGFILTER = linear;\n"
+ "MINFILTER = linear;\n"
+ "};\n"
+
+ // World * View * Projection matrix\n"
+ // NOTE: Assume that the material uses a WorldViewProjection matrix\n"
+ "float4x4 WorldViewProjection : WORLDVIEWPROJECTION;\n"
+
+ // Vertex shader input structure
+ "struct VS_INPUT\n"
+ "{\n"
+ "float3 Position : POSITION;\n"
+ "float3 Texture0 : TEXCOORD0;\n"
+ "};\n"
+
+ // Vertex shader output structure
+ "struct VS_OUTPUT\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float3 Texture0 : TEXCOORD0;\n"
+ "};\n"
+
+ // Vertex shader
+ "VS_OUTPUT RenderSkyBoxVS(VS_INPUT IN)\n"
+ "{\n"
+ "VS_OUTPUT Out;\n"
+
+ // Multiply with the WorldViewProjection matrix
+ "Out.Position = mul(float4(IN.Position,1.0f),WorldViewProjection);\n"
+
+ // Set z to w to ensure z becomes 1.0 after the division through w occurs
+ "Out.Position.z = Out.Position.w;\n"
+
+ // Simply pass through texture coordinates
+ "Out.Texture0 = IN.Texture0;\n"
+
+ "return Out;\n"
+ "}\n"
+
+ // Pixel shader
+ "float4 RenderSkyBoxPS(float3 Texture0 : TEXCOORD0) : COLOR\n"
+ "{\n"
+ // Lookup the skybox texture
+ "return texCUBE(EnvironmentMapSampler,Texture0) ;\n"
+ "}\n"
+
+ // Technique for the skybox shader (ps_2_0)
+ "technique RenderSkyBox\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "ZWriteEnable = FALSE;\n"
+ "FogEnable = FALSE;\n"
+ "CullMode = NONE;\n"
+
+ "PixelShader = compile ps_2_0 RenderSkyBoxPS();\n"
+ "VertexShader = compile vs_2_0 RenderSkyBoxVS();\n"
+ "}\n"
+ "};\n"
+
+ // -------------- same for static background image -----------------
+ "texture TEXTURE_2D;\n"
+ "sampler TEXTURE_SAMPLER = sampler_state\n"
+ "{\n"
+ "Texture = (TEXTURE_2D);\n"
+ "};\n"
+
+ "struct VS_OUTPUT2\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float2 TexCoord0 : TEXCOORD0;\n"
+ "};\n"
+
+ "VS_OUTPUT2 RenderImageVS(float4 INPosition : POSITION, float2 INTexCoord0 : TEXCOORD0 )\n"
+ "{\n"
+ "VS_OUTPUT2 Out;\n"
+
+ "Out.Position.xy = INPosition.xy;\n"
+ "Out.Position.z = Out.Position.w = 1.0f;\n"
+ "Out.TexCoord0 = INTexCoord0;\n"
+
+ "return Out;\n"
+ "}\n"
+
+ "float4 RenderImagePS(float2 IN : TEXCOORD0) : COLOR\n"
+ "{\n"
+ "return tex2D(TEXTURE_SAMPLER,IN);\n"
+ "}\n"
+
+ // Technique for the background image shader (ps_2_0)
+ "technique RenderImage2D\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "ZWriteEnable = FALSE;\n"
+ "FogEnable = FALSE;\n"
+ "CullMode = NONE;\n"
+
+ "PixelShader = compile ps_2_0 RenderImagePS();\n"
+ "VertexShader = compile vs_2_0 RenderImageVS();\n"
+ "}\n"
+ "};\n");
+
+std::string g_szDefaultShader = std::string(
+
+ // World * View * Projection matrix
+ // NOTE: Assume that the material uses a WorldViewProjection matrix
+ "float4x4 WorldViewProjection : WORLDVIEWPROJECTION;\n"
+ "float4x4 World : WORLD;\n"
+ "float4x3 WorldInverseTranspose : WORLDINVERSETRANSPOSE;\n"
+
+ // light colors
+ "float3 afLightColor[5];\n"
+ // light direction
+ "float3 afLightDir[5];\n"
+
+ // position of the camera in worldspace\n"
+ "float3 vCameraPos : CAMERAPOSITION;\n"
+
+ // Bone matrices
+ // "#ifdef AV_SKINNING \n"
+ "float4x3 gBoneMatrix[60]; \n"
+ // "#endif // AV_SKINNING \n"
+
+ // Vertex shader input structure
+ "struct VS_INPUT\n"
+ "{\n"
+ "float3 Position : POSITION;\n"
+ "float3 Normal : NORMAL;\n"
+ // "#ifdef AV_SKINNING \n"
+ "float4 BlendIndices : BLENDINDICES;\n"
+ "float4 BlendWeights : BLENDWEIGHT;\n"
+ // "#endif // AV_SKINNING \n"
+ "};\n"
+
+ // Vertex shader output structure for pixel shader usage
+ "struct VS_OUTPUT\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float3 ViewDir : TEXCOORD0;\n"
+ "float3 Normal : TEXCOORD1;\n"
+ "};\n"
+
+ // Vertex shader output structure for fixed function
+ "struct VS_OUTPUT_FF\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float4 Color : COLOR;\n"
+ "};\n"
+
+ // Vertex shader for pixel shader usage
+ "VS_OUTPUT DefaultVShader(VS_INPUT IN)\n"
+ "{\n"
+ "VS_OUTPUT Out;\n"
+
+ // "#ifdef AV_SKINNING \n"
+ "float4 weights = IN.BlendWeights; \n"
+ "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n"
+ "float4 localPos = float4( IN.Position, 1.0f); \n"
+ "float3 objPos = mul( localPos, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n"
+ // "#else \n"
+ // "float3 objPos = IN.Position; \n"
+ // "#endif // AV_SKINNING \n"
+
+ // Multiply with the WorldViewProjection matrix
+ "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n"
+ "float3 WorldPos = mul( float4( objPos, 1.0f), World);\n"
+ "Out.ViewDir = vCameraPos - WorldPos;\n"
+ "Out.Normal = mul(IN.Normal,WorldInverseTranspose);\n"
+
+ "return Out;\n"
+ "}\n"
+
+ // Vertex shader for fixed function pipeline
+ "VS_OUTPUT_FF DefaultVShader_FF(VS_INPUT IN)\n"
+ "{\n"
+ "VS_OUTPUT_FF Out;\n"
+
+ // "#ifdef AV_SKINNING \n"
+ "float4 weights = IN.BlendWeights; \n"
+ "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n"
+ "float4 localPos = float4( IN.Position, 1.0f); \n"
+ "float3 objPos = mul( localPos, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n"
+ // "#else \n"
+ // "float3 objPos = IN.Position; \n"
+ // "#endif // AV_SKINNING \n"
+
+ // Multiply with the WorldViewProjection matrix
+ "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n"
+
+ "float3 worldNormal = normalize( mul( IN.Normal, (float3x3) WorldInverseTranspose)); \n"
+
+ // per-vertex lighting. We simply assume light colors of unused lights to be black
+ "Out.Color = float4( 0.2f, 0.2f, 0.2f, 1.0f); \n"
+ "for( int a = 0; a < 2; a++)\n"
+ " Out.Color.rgb += saturate( dot( afLightDir[a], worldNormal)) * afLightColor[a].rgb; \n"
+ "return Out;\n"
+ "}\n"
+
+ // Pixel shader for one light
+ "float4 DefaultPShaderSpecular_D1(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "float3 Normal = normalize(IN.Normal);\n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+
+ "{\n"
+ "float L1 = dot(Normal,afLightDir[0]) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (Normal,afLightDir[0]);\n"
+ "float fHalfLambert = L1*L1;\n"
+ "OUT.rgb += afLightColor[0] * (fHalfLambert +\n"
+ "saturate(fHalfLambert * 4.0f) * pow(dot(Reflect,ViewDir),9));\n"
+ "}\n"
+ "return OUT;\n"
+ "}\n"
+
+ // Pixel shader for two lights
+ "float4 DefaultPShaderSpecular_D2(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "float3 Normal = normalize(IN.Normal);\n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+
+ "{\n"
+ "float L1 = dot(Normal,afLightDir[0]) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (ViewDir,Normal);\n"
+ "float fHalfLambert = L1*L1;\n"
+ "OUT.rgb += afLightColor[0] * (fHalfLambert +\n"
+ "saturate(fHalfLambert * 4.0f) * pow(dot(Reflect,afLightDir[0]),9));\n"
+ "}\n"
+ "{\n"
+ "float L1 = dot(Normal,afLightDir[1]) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (ViewDir,Normal);\n"
+ "float fHalfLambert = L1*L1;\n"
+ "OUT.rgb += afLightColor[1] * (fHalfLambert +\n"
+ "saturate(fHalfLambert * 4.0f) * pow(dot(Reflect,afLightDir[1]),9));\n"
+ "}\n"
+ "return OUT;\n"
+ "}\n"
+ // ----------------------------------------------------------------------------
+ "float4 DefaultPShaderSpecular_PS20_D1(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "float3 Normal = normalize(IN.Normal);\n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+
+ "{\n"
+ "float L1 = dot(Normal,afLightDir[0]);\n"
+ "float3 Reflect = reflect (Normal,afLightDir[0]);\n"
+ "OUT.rgb += afLightColor[0] * ((L1) +\n"
+ "pow(dot(Reflect,ViewDir),9));\n"
+ "}\n"
+
+ "return OUT;\n"
+ "}\n"
+ // ----------------------------------------------------------------------------
+ "float4 DefaultPShaderSpecular_PS20_D2(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "float3 Normal = normalize(IN.Normal);\n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+
+ "{\n"
+ "float L1 = dot(Normal,afLightDir[0]);\n"
+ "float3 Reflect = reflect (Normal,afLightDir[0]);\n"
+ "OUT.rgb += afLightColor[0] * ((L1) +\n"
+ "pow(dot(Reflect,ViewDir),9));\n"
+ "}\n"
+ "{\n"
+ "float L1 = dot(Normal,afLightDir[1]);\n"
+ "float3 Reflect = reflect (Normal,afLightDir[1]);\n"
+ "OUT.rgb += afLightColor[1] * ((L1) +\n"
+ "pow(dot(Reflect,ViewDir),9));\n"
+ "}\n"
+ "return OUT;\n"
+ "}\n"
+
+ // Technique for the default effect
+ "technique DefaultFXSpecular_D1\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "CullMode=none;\n"
+ "PixelShader = compile ps_3_0 DefaultPShaderSpecular_D1();\n"
+ "VertexShader = compile vs_3_0 DefaultVShader();\n"
+ "}\n"
+ "};\n"
+ "technique DefaultFXSpecular_D2\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "CullMode=none;\n"
+ "PixelShader = compile ps_3_0 DefaultPShaderSpecular_D2();\n"
+ "VertexShader = compile vs_3_0 DefaultVShader();\n"
+ "}\n"
+ "};\n"
+
+ // Technique for the default effect (ps_2_0)
+ "technique DefaultFXSpecular_PS20_D1\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "CullMode=none;\n"
+ "PixelShader = compile ps_2_0 DefaultPShaderSpecular_PS20_D1();\n"
+ "VertexShader = compile vs_2_0 DefaultVShader();\n"
+ "}\n"
+ "};\n"
+ "technique DefaultFXSpecular_PS20_D2\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "CullMode=none;\n"
+ "PixelShader = compile ps_2_0 DefaultPShaderSpecular_PS20_D2();\n"
+ "VertexShader = compile vs_2_0 DefaultVShader();\n"
+ "}\n"
+ "};\n"
+
+ // Technique for the default effect using the fixed function pixel pipeline
+ "technique DefaultFXSpecular_FF\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "CullMode=none;\n"
+ "VertexShader = compile vs_2_0 DefaultVShader_FF();\n"
+ "ColorOp[0] = SelectArg1;\n"
+ "ColorArg0[0] = Diffuse;\n"
+ "AlphaOp[0] = SelectArg1;\n"
+ "AlphaArg0[0] = Diffuse;\n"
+ "}\n"
+ "};\n");
+
+std::string g_szMaterialShader = std::string(
+
+ // World * View * Projection matrix
+ // NOTE: Assume that the material uses a WorldViewProjection matrix
+ "float4x4 WorldViewProjection : WORLDVIEWPROJECTION;\n"
+ "float4x4 World : WORLD;\n"
+ "float4x3 WorldInverseTranspose : WORLDINVERSETRANSPOSE;\n"
+
+ "#ifndef AV_DISABLESSS\n"
+ "float4x3 ViewProj;\n"
+ "float4x3 InvViewProj;\n"
+ "#endif\n"
+
+ "float4 DIFFUSE_COLOR;\n"
+ "float4 SPECULAR_COLOR;\n"
+ "float4 AMBIENT_COLOR;\n"
+ "float4 EMISSIVE_COLOR;\n"
+
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "float SPECULARITY;\n"
+ "float SPECULAR_STRENGTH;\n"
+ "#endif\n"
+ "#ifdef AV_OPACITY\n"
+ "float TRANSPARENCY;\n"
+ "#endif\n"
+
+ // light colors (diffuse and specular)
+ "float4 afLightColor[5];\n"
+ "float4 afLightColorAmbient[5];\n"
+
+ // light direction
+ "float3 afLightDir[5];\n"
+
+ // position of the camera in worldspace
+ "float3 vCameraPos : CAMERAPOSITION;\n"
+
+ // Bone matrices
+ "#ifdef AV_SKINNING \n"
+ "float4x3 gBoneMatrix[60]; \n"
+ "#endif // AV_SKINNING \n"
+
+ "#ifdef AV_DIFFUSE_TEXTURE\n"
+ "texture DIFFUSE_TEXTURE;\n"
+ "sampler DIFFUSE_SAMPLER\n"
+ "{\n"
+ "Texture = <DIFFUSE_TEXTURE>;\n"
+ "#ifdef AV_WRAPU\n"
+ "AddressU = WRAP;\n"
+ "#endif\n"
+ "#ifdef AV_MIRRORU\n"
+ "AddressU = MIRROR;\n"
+ "#endif\n"
+ "#ifdef AV_CLAMPU\n"
+ "AddressU = CLAMP;\n"
+ "#endif\n"
+ "#ifdef AV_WRAPV\n"
+ "AddressV = WRAP;\n"
+ "#endif\n"
+ "#ifdef AV_MIRRORV\n"
+ "AddressV = MIRROR;\n"
+ "#endif\n"
+ "#ifdef AV_CLAMPV\n"
+ "AddressV = CLAMP;\n"
+ "#endif\n"
+ "};\n"
+ "#endif // AV_DIFFUSE_TEXTUR\n"
+
+ "#ifdef AV_DIFFUSE_TEXTURE2\n"
+ "texture DIFFUSE_TEXTURE2;\n"
+ "sampler DIFFUSE_SAMPLER2\n"
+ "{\n"
+ "Texture = <DIFFUSE_TEXTURE2>;\n"
+ "};\n"
+ "#endif // AV_DIFFUSE_TEXTUR2\n"
+
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "texture SPECULAR_TEXTURE;\n"
+ "sampler SPECULAR_SAMPLER\n"
+ "{\n"
+ "Texture = <SPECULAR_TEXTURE>;\n"
+ "};\n"
+ "#endif // AV_SPECULAR_TEXTUR\n"
+
+ "#ifdef AV_AMBIENT_TEXTURE\n"
+ "texture AMBIENT_TEXTURE;\n"
+ "sampler AMBIENT_SAMPLER\n"
+ "{\n"
+ "Texture = <AMBIENT_TEXTURE>;\n"
+ "};\n"
+ "#endif // AV_AMBIENT_TEXTUR\n"
+
+ "#ifdef AV_LIGHTMAP_TEXTURE\n"
+ "texture LIGHTMAP_TEXTURE;\n"
+ "sampler LIGHTMAP_SAMPLER\n"
+ "{\n"
+ "Texture = <LIGHTMAP_TEXTURE>;\n"
+ "};\n"
+ "#endif // AV_LIGHTMAP_TEXTURE\n"
+
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "texture OPACITY_TEXTURE;\n"
+ "sampler OPACITY_SAMPLER\n"
+ "{\n"
+ "Texture = <OPACITY_TEXTURE>;\n"
+ "};\n"
+ "#endif // AV_OPACITY_TEXTURE\n"
+
+ "#ifdef AV_EMISSIVE_TEXTURE\n"
+ "texture EMISSIVE_TEXTURE;\n"
+ "sampler EMISSIVE_SAMPLER\n"
+ "{\n"
+ "Texture = <EMISSIVE_TEXTURE>;\n"
+ "};\n"
+ "#endif // AV_EMISSIVE_TEXTUR\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "texture NORMAL_TEXTURE;\n"
+ "sampler NORMAL_SAMPLER\n"
+ "{\n"
+ "Texture = <NORMAL_TEXTURE>;\n"
+ "};\n"
+ "#endif // AV_NORMAL_TEXTURE\n"
+
+ "#ifdef AV_SKYBOX_LOOKUP\n"
+ "textureCUBE lw_tex_envmap;\n"
+ "samplerCUBE EnvironmentMapSampler = sampler_state\n"
+ "{\n"
+ "Texture = (lw_tex_envmap);\n"
+ "AddressU = CLAMP;\n"
+ "AddressV = CLAMP;\n"
+ "AddressW = CLAMP;\n"
+
+ "MAGFILTER = linear;\n"
+ "MINFILTER = linear;\n"
+ "};\n"
+ "#endif // AV_SKYBOX_LOOKUP\n"
+
+ // Vertex shader input structure
+ "struct VS_INPUT\n"
+ "{\n"
+ "float3 Position : POSITION;\n"
+ "float3 Normal : NORMAL;\n"
+ "float4 Color : COLOR0;\n"
+ "float3 Tangent : TANGENT;\n"
+ "float3 Bitangent : BINORMAL;\n"
+ "float2 TexCoord0 : TEXCOORD0;\n"
+ "#ifdef AV_TWO_UV \n"
+ "float2 TexCoord1 : TEXCOORD1;\n"
+ "#endif \n"
+ "#ifdef AV_SKINNING \n"
+ "float4 BlendIndices : BLENDINDICES;\n"
+ "float4 BlendWeights : BLENDWEIGHT;\n"
+ "#endif // AV_SKINNING \n"
+ "};\n"
+
+ // Vertex shader output structure for pixel shader usage
+ "struct VS_OUTPUT\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float3 ViewDir : TEXCOORD0;\n"
+
+ "float4 Color : COLOR0;\n"
+
+ "#ifndef AV_NORMAL_TEXTURE\n"
+ "float3 Normal : TEXCOORD1;\n"
+ "#endif\n"
+
+ "float2 TexCoord0 : TEXCOORD2;\n"
+ "#ifdef AV_TWO_UV \n"
+ "float2 TexCoord1 : TEXCOORD3;\n"
+ "#endif \n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float3 Light0 : TEXCOORD3;\n"
+ "float3 Light1 : TEXCOORD4;\n"
+ "#endif\n"
+ "};\n"
+
+ // Vertex shader output structure for fixed function pixel pipeline
+ "struct VS_OUTPUT_FF\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float4 DiffuseColor : COLOR0;\n"
+ "float4 SpecularColor : COLOR1;\n"
+ "float2 TexCoord0 : TEXCOORD0;\n"
+ "};\n"
+
+ // Selective SuperSampling in screenspace for reflection lookups
+ "#define GetSSSCubeMap(_refl) (texCUBElod(EnvironmentMapSampler,float4(_refl,0.0f)).rgb) \n"
+
+ // Vertex shader for pixel shader usage and one light
+ "VS_OUTPUT MaterialVShader_D1(VS_INPUT IN)\n"
+ "{\n"
+ "VS_OUTPUT Out = (VS_OUTPUT)0;\n"
+
+ "#ifdef AV_SKINNING \n"
+ "float4 weights = IN.BlendWeights; \n"
+ "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n"
+ "float4 localPos = float4( IN.Position, 1.0f); \n"
+ "float3 objPos = mul( localPos, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n"
+ "#else \n"
+ "float3 objPos = IN.Position; \n"
+ "#endif // AV_SKINNING \n"
+
+ // Multiply with the WorldViewProjection matrix
+ "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n"
+ "float3 WorldPos = mul( float4( objPos, 1.0f), World);\n"
+ "Out.TexCoord0 = IN.TexCoord0;\n"
+ "#ifdef AV_TWO_UV \n"
+ "Out.TexCoord1 = IN.TexCoord1;\n"
+ "#endif\n"
+ "Out.Color = IN.Color;\n"
+
+ "#ifndef AV_NORMAL_TEXTURE\n"
+ "Out.ViewDir = vCameraPos - WorldPos;\n"
+ "Out.Normal = mul(IN.Normal,WorldInverseTranspose);\n"
+ "#endif\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float3x3 TBNMatrix = float3x3(IN.Tangent, IN.Bitangent, IN.Normal);\n"
+ "float3x3 WTTS = mul(TBNMatrix, (float3x3)WorldInverseTranspose);\n"
+ "Out.Light0 = normalize(mul(WTTS, afLightDir[0] ));\n"
+ "Out.ViewDir = normalize(mul(WTTS, (vCameraPos - WorldPos)));\n"
+ "#endif\n"
+ "return Out;\n"
+ "}\n"
+
+ // Vertex shader for pixel shader usage and two lights
+ "VS_OUTPUT MaterialVShader_D2(VS_INPUT IN)\n"
+ "{\n"
+ "VS_OUTPUT Out = (VS_OUTPUT)0;\n"
+
+ "#ifdef AV_SKINNING \n"
+ "float4 weights = IN.BlendWeights; \n"
+ "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n"
+ "float4 localPos = float4( IN.Position, 1.0f); \n"
+ "float3 objPos = mul( localPos, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n"
+ "#else \n"
+ "float3 objPos = IN.Position; \n"
+ "#endif // AV_SKINNING \n"
+
+ // Multiply with the WorldViewProjection matrix
+ "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n"
+ "float3 WorldPos = mul( float4( objPos, 1.0f), World);\n"
+ "Out.TexCoord0 = IN.TexCoord0;\n"
+ "#ifdef AV_TWO_UV \n"
+ "Out.TexCoord1 = IN.TexCoord1;\n"
+ "#endif\n"
+ "Out.Color = IN.Color;\n"
+
+ "#ifndef AV_NORMAL_TEXTURE\n"
+ "Out.ViewDir = vCameraPos - WorldPos;\n"
+ "Out.Normal = mul(IN.Normal,WorldInverseTranspose);\n"
+ "#endif\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float3x3 TBNMatrix = float3x3(IN.Tangent, IN.Bitangent, IN.Normal);\n"
+ "float3x3 WTTS = mul(TBNMatrix, (float3x3)WorldInverseTranspose);\n"
+ "Out.Light0 = normalize(mul(WTTS, afLightDir[0] ));\n"
+ "Out.Light1 = normalize(mul(WTTS, afLightDir[1] ));\n"
+ "Out.ViewDir = normalize(mul(WTTS, (vCameraPos - WorldPos)));\n"
+ "#endif\n"
+ "return Out;\n"
+ "}\n"
+
+ // Vertex shader for zero to five lights using the fixed function pixel pipeline
+ "VS_OUTPUT_FF MaterialVShader_FF(VS_INPUT IN)\n"
+ "{\n"
+ "VS_OUTPUT_FF Out = (VS_OUTPUT_FF)0;\n"
+
+ "#ifdef AV_SKINNING \n"
+ "float4 weights = IN.BlendWeights; \n"
+ "weights.w = 1.0f - dot( weights.xyz, float3( 1, 1, 1)); \n"
+ "float4 localPos = float4( IN.Position, 1.0f); \n"
+ "float3 objPos = mul( localPos, gBoneMatrix[IN.BlendIndices.x]) * weights.x; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.y]) * weights.y; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.z]) * weights.z; \n"
+ "objPos += mul( localPos, gBoneMatrix[IN.BlendIndices.w]) * weights.w; \n"
+ "#else \n"
+ "float3 objPos = IN.Position; \n"
+ "#endif // AV_SKINNING \n"
+
+ // Multiply with the WorldViewProjection matrix
+ "Out.Position = mul( float4( objPos, 1.0f), WorldViewProjection);\n"
+ "float3 worldPos = mul( float4( objPos, 1.0f), World);\n"
+ "float3 worldNormal = normalize( mul( IN.Normal, (float3x3) WorldInverseTranspose)); \n"
+ "Out.TexCoord0 = IN.TexCoord0;\n"
+
+ // calculate per-vertex diffuse lighting including ambient part
+ "float4 diffuseColor = float4( 0.0f, 0.0f, 0.0f, 1.0f); \n"
+ "for( int a = 0; a < 2; a++) \n"
+ " diffuseColor.rgb += saturate( dot( afLightDir[a], worldNormal)) * afLightColor[a].rgb; \n"
+ // factor in material properties and a bit of ambient lighting
+ "Out.DiffuseColor = diffuseColor * DIFFUSE_COLOR + float4( 0.2f, 0.2f, 0.2f, 1.0f) * AMBIENT_COLOR; ; \n"
+
+ // and specular including emissive part
+ "float4 specularColor = float4( 0.0f, 0.0f, 0.0f, 1.0f); \n"
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "float3 viewDir = normalize( worldPos - vCameraPos); \n"
+ "for( int a = 0; a < 2; a++) \n"
+ "{ \n"
+ " float3 reflDir = reflect( afLightDir[a], worldNormal); \n"
+ " float specIntensity = pow( saturate( dot( reflDir, viewDir)), SPECULARITY) * SPECULAR_STRENGTH; \n"
+ " specularColor.rgb += afLightColor[a] * specIntensity; \n"
+ "} \n"
+ "#endif // AV_SPECULAR_COMPONENT\n"
+ // factor in material properties and the emissive part
+ "Out.SpecularColor = specularColor * SPECULAR_COLOR + EMISSIVE_COLOR; \n"
+
+ "return Out;\n"
+ "}\n"
+
+ // Pixel shader - one light
+ "float4 MaterialPShaderSpecular_D1(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float3 IN_Light0 = normalize(IN.Light0);\n"
+ "float3 Normal = normalize(2.0f * tex2D(NORMAL_SAMPLER, IN.TexCoord0).rgb - 1.0f);\n"
+ "#else\n"
+ "float3 Normal = normalize(IN.Normal);\n"
+ "#endif \n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "float3 Reflect = normalize(reflect (-ViewDir,Normal));\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+
+ "{\n"
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float L1 = dot(Normal,IN_Light0) * 0.5f + 0.5f;\n"
+ "#define AV_LIGHT_0 IN_Light0\n"
+ // would need to convert the reflection vector into world space ....
+ // simply let it ...
+ "#else\n"
+ "float L1 = dot(Normal,afLightDir[0]) * 0.5f + 0.5f;\n"
+ "#define AV_LIGHT_0 afLightDir[0]\n"
+ "#endif\n"
+ "#ifdef AV_DIFFUSE_TEXTURE2\n"
+ "float fHalfLambert = 1.f;\n"
+ "#else\n"
+ "float fHalfLambert = L1*L1;\n"
+ "#endif \n"
+ "#ifdef AV_DIFFUSE_TEXTURE\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * tex2D(DIFFUSE_SAMPLER,IN.TexCoord0).rgb * fHalfLambert * IN.Color.rgb +\n"
+ "#else\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * fHalfLambert * IN.Color.rgb +\n"
+ "#endif // !AV_DIFFUSE_TEXTURE\n"
+
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "#ifndef AV_SKYBOX_LOOKUP\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#else\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * GetSSSCubeMap(Reflect) * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * GetSSSCubeMap(Reflect) * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#endif // !AV_SKYBOX_LOOKUP\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+
+ "#ifdef AV_AMBIENT_TEXTURE\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb * tex2D(AMBIENT_SAMPLER,IN.TexCoord0).rgb +\n"
+ "#else\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb + \n"
+ "#endif // !AV_AMBIENT_TEXTURE\n"
+ "#ifdef AV_EMISSIVE_TEXTURE\n"
+ "EMISSIVE_COLOR.rgb * tex2D(EMISSIVE_SAMPLER,IN.TexCoord0).rgb;\n"
+ "#else \n"
+ "EMISSIVE_COLOR.rgb;\n"
+ "#endif // !AV_EMISSIVE_TEXTURE\n"
+ "}\n"
+ "#ifdef AV_OPACITY\n"
+ "OUT.a = TRANSPARENCY;\n"
+ "#endif\n"
+ "#ifdef AV_LIGHTMAP_TEXTURE\n"
+ "OUT.rgb *= tex2D(LIGHTMAP_SAMPLER,AV_LIGHTMAP_TEXTURE_UV_COORD).rgb*LM_STRENGTH;\n"
+ "#endif\n"
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "OUT.a *= tex2D(OPACITY_SAMPLER,IN.TexCoord0). AV_OPACITY_TEXTURE_REGISTER_MASK;\n"
+ "#endif\n"
+ "return OUT;\n"
+
+ "#undef AV_LIGHT_0\n"
+ "}\n"
+
+ // Pixel shader - two lights
+ "float4 MaterialPShaderSpecular_D2(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float3 IN_Light0 = normalize(IN.Light0);\n"
+ "float3 IN_Light1 = normalize(IN.Light1);\n"
+ "float3 Normal = normalize(2.0f * tex2D(NORMAL_SAMPLER, IN.TexCoord0).rgb - 1.0f);\n"
+ "#else\n"
+ "float3 Normal = normalize(IN.Normal);\n"
+ "#endif \n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "float3 Reflect = -normalize(reflect (ViewDir,Normal));\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+
+ "{\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float L1 = dot(Normal,IN_Light0) * 0.5f + 0.5f;\n"
+ "#define AV_LIGHT_0 IN_Light0\n"
+ "#else\n"
+ "float L1 = dot(Normal,afLightDir[0]) * 0.5f + 0.5f;\n"
+ "#define AV_LIGHT_0 afLightDir[0]\n"
+ "#endif\n"
+ "float fHalfLambert = L1*L1;\n"
+
+ "#ifdef AV_DIFFUSE_TEXTURE\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * tex2D(DIFFUSE_SAMPLER,IN.TexCoord0).rgb * fHalfLambert * IN.Color.rgb +\n"
+ "#else\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * fHalfLambert * IN.Color.rgb +\n"
+ "#endif // !AV_DIFFUSE_TEXTURE\n"
+
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "#ifndef AV_SKYBOX_LOOKUP\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#else\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * GetSSSCubeMap(Reflect) * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * GetSSSCubeMap(Reflect) * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_0),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#endif // !AV_SKYBOX_LOOKUP\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_AMBIENT_TEXTURE\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb * tex2D(AMBIENT_SAMPLER,IN.TexCoord0).rgb + \n"
+ "#else\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb + \n"
+ "#endif // !AV_AMBIENT_TEXTURE\n"
+ "#ifdef AV_EMISSIVE_TEXTURE\n"
+ "EMISSIVE_COLOR.rgb * tex2D(EMISSIVE_SAMPLER,IN.TexCoord0).rgb;\n"
+ "#else \n"
+ "EMISSIVE_COLOR.rgb;\n"
+ "#endif // !AV_EMISSIVE_TEXTURE\n"
+ "}\n"
+ "{\n"
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float L1 = dot(Normal,IN_Light1) * 0.5f + 0.5f;\n"
+ "#define AV_LIGHT_1 IN_Light1\n"
+ "#else\n"
+ "float L1 = dot(Normal,afLightDir[1]) * 0.5f + 0.5f;\n"
+ "#define AV_LIGHT_1 afLightDir[1]\n"
+ "#endif\n"
+ "float fHalfLambert = L1*L1;\n"
+ "#ifdef AV_DIFFUSE_TEXTURE\n"
+ "OUT.rgb += afLightColor[1].rgb * DIFFUSE_COLOR.rgb * tex2D(DIFFUSE_SAMPLER,IN.TexCoord0).rgb * fHalfLambert * IN.Color.rgb +\n"
+ "#else\n"
+ "OUT.rgb += afLightColor[1].rgb * DIFFUSE_COLOR.rgb * fHalfLambert * IN.Color.rgb +\n"
+ "#endif // !AV_DIFFUSE_TEXTURE\n"
+
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "#ifndef AV_SKYBOX_LOOKUP\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[1].rgb * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_1),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[1].rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_1),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#else\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[1].rgb * GetSSSCubeMap(Reflect) * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_1),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[1].rgb * GetSSSCubeMap(Reflect) * (saturate(fHalfLambert * 2.0f) * pow(dot(Reflect,AV_LIGHT_1),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#endif // !AV_SKYBOX_LOOKUP\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_AMBIENT_TEXTURE\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[1].rgb * tex2D(AMBIENT_SAMPLER,IN.TexCoord0).rgb + \n"
+ "#else\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[1].rgb + \n"
+ "#endif // !AV_AMBIENT_TEXTURE\n"
+ "#ifdef AV_EMISSIVE_TEXTURE\n"
+ "EMISSIVE_COLOR.rgb * tex2D(EMISSIVE_SAMPLER,IN.TexCoord0).rgb;\n"
+ "#else \n"
+ "EMISSIVE_COLOR.rgb;\n"
+ "#endif // !AV_EMISSIVE_TEXTURE\n"
+ "}\n"
+ "#ifdef AV_OPACITY\n"
+ "OUT.a = TRANSPARENCY;\n"
+ "#endif\n"
+ "#ifdef AV_LIGHTMAP_TEXTURE\n"
+ "OUT.rgb *= tex2D(LIGHTMAP_SAMPLER,AV_LIGHTMAP_TEXTURE_UV_COORD).rgb*LM_STRENGTH;\n"
+ "#endif\n"
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "OUT.a *= tex2D(OPACITY_SAMPLER,IN.TexCoord0). AV_OPACITY_TEXTURE_REGISTER_MASK;\n"
+ "#endif\n"
+ "return OUT;\n"
+
+ "#undef AV_LIGHT_0\n"
+ "#undef AV_LIGHT_1\n"
+ "}\n"
+
+ // Same pixel shader again, one light
+ "float4 MaterialPShaderSpecular_PS20_D1(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float3 IN_Light0 = normalize(IN.Light0);\n"
+ "float3 Normal = normalize(2.0f * tex2D(NORMAL_SAMPLER, IN.TexCoord0).rgb - 1.0f);\n"
+ "#else\n"
+ "float3 Normal = normalize(IN.Normal);\n"
+ "#endif \n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+
+ "{\n"
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float L1 = dot(Normal,IN_Light0) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (Normal,IN_Light0);\n"
+ "#else\n"
+ "float L1 = dot(Normal,afLightDir[0]) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (Normal,afLightDir[0]);\n"
+ "#endif\n"
+ "#ifdef AV_DIFFUSE_TEXTURE\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * tex2D(DIFFUSE_SAMPLER,IN.TexCoord0).rgb * L1 +\n"
+ "#else\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * L1 +\n"
+ "#endif // !AV_DIFFUSE_TEXTURE\n"
+
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(L1 * 4.0f) * pow(dot(Reflect,ViewDir),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * (saturate(L1 * 4.0f) * pow(dot(Reflect,ViewDir),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_AMBIENT_TEXTURE\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb * tex2D(AMBIENT_SAMPLER,IN.TexCoord0).rgb +\n"
+ "#else\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb +\n"
+ "#endif // !AV_AMBIENT_TEXTURE\n"
+ "#ifdef AV_EMISSIVE_TEXTURE\n"
+ "EMISSIVE_COLOR.rgb * tex2D(EMISSIVE_SAMPLER,IN.TexCoord0).rgb;\n"
+ "#else \n"
+ "EMISSIVE_COLOR.rgb;\n"
+ "#endif // !AV_EMISSIVE_TEXTURE\n"
+ "}\n"
+
+ "#ifdef AV_OPACITY\n"
+ "OUT.a = TRANSPARENCY;\n"
+ "#endif\n"
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "OUT.a *= tex2D(OPACITY_SAMPLER,IN.TexCoord0). AV_OPACITY_TEXTURE_REGISTER_MASK;\n"
+ "#endif\n"
+ "return OUT;\n"
+ "}\n"
+
+ // Same pixel shader again, two lights
+ "float4 MaterialPShaderSpecular_PS20_D2(VS_OUTPUT IN) : COLOR\n"
+ "{\n"
+ "float4 OUT = float4(0.0f,0.0f,0.0f,1.0f);\n"
+
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float3 IN_Light0 = normalize(IN.Light0);\n"
+ "float3 IN_Light1 = normalize(IN.Light1);\n"
+ "float3 Normal = normalize(2.0f * tex2D(NORMAL_SAMPLER, IN.TexCoord0) - 1.0f);\n"
+ "#else\n"
+ "float3 Normal = normalize(IN.Normal);\n"
+ "#endif \n"
+ "float3 ViewDir = normalize(IN.ViewDir);\n"
+
+ "{\n"
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float L1 = dot(Normal,IN_Light0) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (Normal,IN_Light0);\n"
+ "#else\n"
+ "float L1 = dot(Normal,afLightDir[0]) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (Normal,afLightDir[0]);\n"
+ "#endif\n"
+ "#ifdef AV_DIFFUSE_TEXTURE\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * tex2D(DIFFUSE_SAMPLER,IN.TexCoord0).rgb * L1 +\n"
+ "#else\n"
+ "OUT.rgb += afLightColor[0].rgb * DIFFUSE_COLOR.rgb * L1 +\n"
+ "#endif // !AV_DIFFUSE_TEXTURE\n"
+
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(L1 * 4.0f) * pow(dot(Reflect,ViewDir),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[0].rgb * (saturate(L1 * 4.0f) * pow(dot(Reflect,ViewDir),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_AMBIENT_TEXTURE\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb * tex2D(AMBIENT_SAMPLER,IN.TexCoord0).rgb +\n"
+ "#else\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[0].rgb +\n"
+ "#endif // !AV_AMBIENT_TEXTURE\n"
+ "#ifdef AV_EMISSIVE_TEXTURE\n"
+ "EMISSIVE_COLOR.rgb * tex2D(EMISSIVE_SAMPLER,IN.TexCoord0).rgb;\n"
+ "#else \n"
+ "EMISSIVE_COLOR.rgb;\n"
+ "#endif // !AV_EMISSIVE_TEXTURE\n"
+ "}\n"
+ "{\n"
+ "#ifdef AV_NORMAL_TEXTURE\n"
+ "float L1 = dot(Normal,IN_Light1) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (Normal,IN_Light1);\n"
+ "#else\n"
+ "float L1 = dot(Normal,afLightDir[1]) * 0.5f + 0.5f;\n"
+ "float3 Reflect = reflect (Normal,afLightDir[1]);\n"
+ "#endif\n"
+ "#ifdef AV_DIFFUSE_TEXTURE\n"
+ "OUT.rgb += afLightColor[1].rgb * DIFFUSE_COLOR.rgb * tex2D(DIFFUSE_SAMPLER,IN.TexCoord0).rgb * L1 +\n"
+ "#else\n"
+ "OUT.rgb += afLightColor[1].rgb * DIFFUSE_COLOR.rgb * L1 +\n"
+ "#endif // !AV_DIFFUSE_TEXTURE\n"
+
+ "#ifdef AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_SPECULAR_TEXTURE\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[1].rgb * tex2D(SPECULAR_SAMPLER,IN.TexCoord0).rgb * (saturate(L1 * 4.0f) * pow(dot(Reflect,ViewDir),SPECULARITY)) + \n"
+ "#else\n"
+ "SPECULAR_COLOR.rgb * SPECULAR_STRENGTH * afLightColor[1].rgb * (saturate(L1 * 4.0f) * pow(dot(Reflect,ViewDir),SPECULARITY)) + \n"
+ "#endif // !AV_SPECULAR_TEXTURE\n"
+ "#endif // !AV_SPECULAR_COMPONENT\n"
+ "#ifdef AV_AMBIENT_TEXTURE\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[1].rgb * tex2D(AMBIENT_SAMPLER,IN.TexCoord0).rgb +\n"
+ "#else\n"
+ "AMBIENT_COLOR.rgb * afLightColorAmbient[1].rgb + \n"
+ "#endif // !AV_AMBIENT_TEXTURE\n"
+ "#ifdef AV_EMISSIVE_TEXTURE\n"
+ "EMISSIVE_COLOR.rgb * tex2D(EMISSIVE_SAMPLER,IN.TexCoord0).rgb;\n"
+ "#else \n"
+ "EMISSIVE_COLOR.rgb;\n"
+ "#endif // !AV_EMISSIVE_TEXTURE\n"
+ "}\n"
+
+ "#ifdef AV_OPACITY\n"
+ "OUT.a = TRANSPARENCY;\n"
+ "#endif\n"
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "OUT.a *= tex2D(OPACITY_SAMPLER,IN.TexCoord0). AV_OPACITY_TEXTURE_REGISTER_MASK;\n"
+ "#endif\n"
+ "return OUT;\n"
+ "}\n"
+
+ // Technique for the material effect
+ "technique MaterialFXSpecular_D1\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#else\n"
+ "#ifdef AV_OPACITY\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#endif \n"
+ "#endif\n"
+
+ "PixelShader = compile ps_3_0 MaterialPShaderSpecular_D1();\n"
+ "VertexShader = compile vs_3_0 MaterialVShader_D1();\n"
+ "}\n"
+ "};\n"
+ "technique MaterialFXSpecular_D2\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#else\n"
+ "#ifdef AV_OPACITY\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#endif \n"
+ "#endif\n"
+
+ "PixelShader = compile ps_3_0 MaterialPShaderSpecular_D2();\n"
+ "VertexShader = compile vs_3_0 MaterialVShader_D2();\n"
+ "}\n"
+ "};\n"
+
+ // Technique for the material effect (ps_2_0)
+ "technique MaterialFXSpecular_PS20_D1\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#else\n"
+ "#ifdef AV_OPACITY\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#endif \n"
+ "#endif\n"
+
+ "PixelShader = compile ps_2_0 MaterialPShaderSpecular_PS20_D1();\n"
+ "VertexShader = compile vs_2_0 MaterialVShader_D1();\n"
+ "}\n"
+ "};\n"
+
+ "technique MaterialFXSpecular_PS20_D2\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "//CullMode=none;\n"
+
+ "#ifdef AV_OPACITY_TEXTURE\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#else\n"
+ "#ifdef AV_OPACITY\n"
+ "AlphaBlendEnable=TRUE;"
+ "SrcBlend = srcalpha;\n"
+ "DestBlend = invsrcalpha;\n"
+ "#endif \n"
+ "#endif\n"
+
+ "PixelShader = compile ps_2_0 MaterialPShaderSpecular_PS20_D2();\n"
+ "VertexShader = compile vs_2_0 MaterialVShader_D2();\n"
+ "}\n"
+ "};\n"
+
+ // Technique for the material effect using fixed function pixel pipeline
+ "technique MaterialFX_FF\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "//CullMode=none;\n"
+ "SpecularEnable = true; \n"
+ "VertexShader = compile vs_2_0 MaterialVShader_FF();\n"
+ "ColorOp[0] = Modulate;\n"
+ "ColorArg0[0] = Texture;\n"
+ "ColorArg1[0] = Diffuse;\n"
+ "AlphaOp[0] = Modulate;\n"
+ "AlphaArg0[0] = Texture;\n"
+ "AlphaArg1[0] = Diffuse;\n"
+ "}\n"
+ "};\n");
+
+std::string g_szPassThroughShader = std::string(
+ "texture TEXTURE_2D;\n"
+ "sampler TEXTURE_SAMPLER = sampler_state\n"
+ "{\n"
+ "Texture = (TEXTURE_2D);\n"
+ "MinFilter = POINT;\n"
+ "MagFilter = POINT;\n"
+ "};\n"
+
+ // Vertex Shader output for pixel shader usage
+ "struct VS_OUTPUT\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "float2 TexCoord0 : TEXCOORD0;\n"
+ "};\n"
+
+ // vertex shader for pixel shader usage
+ "VS_OUTPUT DefaultVShader(float4 INPosition : POSITION, float2 INTexCoord0 : TEXCOORD0 )\n"
+ "{\n"
+ "VS_OUTPUT Out;\n"
+
+ "Out.Position = INPosition;\n"
+ "Out.TexCoord0 = INTexCoord0;\n"
+
+ "return Out;\n"
+ "}\n"
+
+ // simply lookup a texture
+ "float4 PassThrough_PS(float2 IN : TEXCOORD0) : COLOR\n"
+ "{\n"
+ " return tex2D(TEXTURE_SAMPLER,IN);\n"
+ "}\n"
+
+ // visualize the alpha channel (in black) -> use a
+ "float4 PassThroughAlphaA_PS(float2 IN : TEXCOORD0) : COLOR\n"
+ "{\n"
+ " return float4(0.0f,0.0f,0.0f,tex2D(TEXTURE_SAMPLER,IN).a);\n"
+ "}\n"
+
+ // visualize the alpha channel (in black) -> use r
+ "float4 PassThroughAlphaR_PS(float2 IN : TEXCOORD0) : COLOR\n"
+ "{\n"
+ " return float4(0.0f,0.0f,0.0f,tex2D(TEXTURE_SAMPLER,IN).r);\n"
+ "}\n"
+
+ // Simple pass-through technique
+ "technique PassThrough\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "FillMode=Solid;\n"
+ "ZEnable = FALSE;\n"
+ "CullMode = none;\n"
+ "AlphaBlendEnable = TRUE;\n"
+ "SrcBlend =srcalpha;\n"
+ "DestBlend =invsrcalpha;\n"
+ "PixelShader = compile ps_2_0 PassThrough_PS();\n"
+ "VertexShader = compile vs_2_0 DefaultVShader();\n"
+ "}\n"
+ "};\n"
+
+ // Pass-through technique which visualizes the texture's alpha channel
+ "technique PassThroughAlphaFromA\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "FillMode=Solid;\n"
+ "ZEnable = FALSE;\n"
+ "CullMode = none;\n"
+ "AlphaBlendEnable = TRUE;\n"
+ "SrcBlend =srcalpha;\n"
+ "DestBlend =invsrcalpha;\n"
+ "PixelShader = compile ps_2_0 PassThroughAlphaA_PS();\n"
+ "VertexShader = compile vs_2_0 DefaultVShader();\n"
+ "}\n"
+ "};\n"
+
+ // Pass-through technique which visualizes the texture's red channel
+ "technique PassThroughAlphaFromR\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "FillMode=Solid;\n"
+ "ZEnable = FALSE;\n"
+ "CullMode = none;\n"
+ "AlphaBlendEnable = TRUE;\n"
+ "SrcBlend =srcalpha;\n"
+ "DestBlend =invsrcalpha;\n"
+ "PixelShader = compile ps_2_0 PassThroughAlphaR_PS();\n"
+ "VertexShader = compile vs_2_0 DefaultVShader();\n"
+ "}\n"
+ "};\n"
+
+ // technique for fixed function pixel pipeline
+ "technique PassThrough_FF\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "ZEnable = FALSE;\n"
+ "CullMode = none;\n"
+ "AlphaBlendEnable = TRUE;\n"
+ "SrcBlend =srcalpha;\n"
+ "DestBlend =invsrcalpha;\n"
+ "VertexShader = compile vs_2_0 DefaultVShader();\n"
+ "ColorOp[0] = SelectArg1;\n"
+ "ColorArg0[0] = Texture;\n"
+ "AlphaOp[0] = SelectArg1;\n"
+ "AlphaArg0[0] = Texture;\n"
+ "}\n"
+ "};\n");
+
+std::string g_szCheckerBackgroundShader = std::string(
+
+ // the two colors used to draw the checker pattern
+ "float3 COLOR_ONE = float3(0.4f,0.4f,0.4f);\n"
+ "float3 COLOR_TWO = float3(0.6f,0.6f,0.6f);\n"
+
+ // size of a square in both x and y direction
+ "float SQUARE_SIZE = 10.0f;\n"
+
+ // vertex shader output structure
+ "struct VS_OUTPUT\n"
+ "{\n"
+ "float4 Position : POSITION;\n"
+ "};\n"
+
+ // vertex shader
+ "VS_OUTPUT DefaultVShader(float4 INPosition : POSITION, float2 INTexCoord0 : TEXCOORD0 )\n"
+ "{\n"
+ "VS_OUTPUT Out;\n"
+
+ "Out.Position = INPosition;\n"
+ "return Out;\n"
+ "}\n"
+
+ // pixel shader
+ "float4 MakePattern_PS(float2 IN : VPOS) : COLOR\n"
+ "{\n"
+ "float2 fDiv = IN / SQUARE_SIZE;\n"
+ "float3 fColor = COLOR_ONE;\n"
+ "if (0 == round(fmod(round(fDiv.x),2)))\n"
+ "{\n"
+ " if (0 == round(fmod(round(fDiv.y),2))) fColor = COLOR_TWO;\n"
+ "}\n"
+ "else if (0 != round(fmod(round(fDiv.y),2)))fColor = COLOR_TWO;\n"
+ "return float4(fColor,1.0f);"
+ "}\n"
+
+ // technique to generate a pattern
+ "technique MakePattern\n"
+ "{\n"
+ "pass p0\n"
+ "{\n"
+ "FillMode=Solid;\n"
+ "ZEnable = FALSE;\n"
+ "CullMode = none;\n"
+ "PixelShader = compile ps_3_0 MakePattern_PS();\n"
+ "VertexShader = compile vs_3_0 DefaultVShader();\n"
+ "}\n"
+ "};\n");
+} // namespace AssimpView
diff --git a/libs/assimp/tools/assimp_view/Shaders.h b/libs/assimp/tools/assimp_view/Shaders.h
new file mode 100644
index 0000000..506daa7
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/Shaders.h
@@ -0,0 +1,63 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_SHADERS_H_INCLUDED)
+#define AV_SHADERS_H_INCLUDED
+
+// Shader used for rendering a skybox background
+extern std::string g_szSkyboxShader;
+
+// Shader used for visualizing normal vectors
+extern std::string g_szNormalsShader;
+
+// Default shader
+extern std::string g_szDefaultShader;
+
+// Material shader
+extern std::string g_szMaterialShader;
+
+// Shader used to draw the yellow circle on top of everything
+extern std::string g_szPassThroughShader;
+
+// Shader used to draw the checker pattern background for the texture view
+extern std::string g_szCheckerBackgroundShader;
+
+#endif // !! AV_SHADERS_H_INCLUDED
diff --git a/libs/assimp/tools/assimp_view/assimp_view.cpp b/libs/assimp/tools/assimp_view/assimp_view.cpp
new file mode 100644
index 0000000..c5c48fd
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/assimp_view.cpp
@@ -0,0 +1,1086 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#include "assimp_view.h"
+#include <assimp/StringUtils.h>
+#include <map>
+
+#ifdef __MINGW32__
+#include <mmsystem.h>
+#else
+#include <timeapi.h>
+#endif
+
+using namespace std;
+
+namespace AssimpView {
+
+extern std::string g_szNormalsShader;
+extern std::string g_szDefaultShader;
+extern std::string g_szPassThroughShader;
+
+//-------------------------------------------------------------------------------
+HINSTANCE g_hInstance = nullptr;
+HWND g_hDlg = nullptr;
+IDirect3D9 *g_piD3D = nullptr;
+IDirect3DDevice9 *g_piDevice = nullptr;
+IDirect3DVertexDeclaration9 *gDefaultVertexDecl = nullptr;
+double g_fFPS = 0.0f;
+char g_szFileName[MAX_PATH];
+ID3DXEffect *g_piDefaultEffect = nullptr;
+ID3DXEffect *g_piNormalsEffect = nullptr;
+ID3DXEffect *g_piPassThroughEffect = nullptr;
+ID3DXEffect *g_piPatternEffect = nullptr;
+bool g_bMousePressed = false;
+bool g_bMousePressedR = false;
+bool g_bMousePressedM = false;
+bool g_bMousePressedBoth = false;
+float g_fElpasedTime = 0.0f;
+D3DCAPS9 g_sCaps;
+bool g_bLoadingFinished = false;
+HANDLE g_hThreadHandle = nullptr;
+float g_fWheelPos = -10.0f;
+bool g_bLoadingCanceled = false;
+IDirect3DTexture9 *g_pcTexture = nullptr;
+bool g_bPlay = false;
+double g_dCurrent = 0.;
+
+// default pp steps
+unsigned int ppsteps = aiProcess_CalcTangentSpace | // calculate tangents and bitangents if possible
+ aiProcess_JoinIdenticalVertices | // join identical vertices/ optimize indexing
+ aiProcess_ValidateDataStructure | // perform a full validation of the loader's output
+ aiProcess_ImproveCacheLocality | // improve the cache locality of the output vertices
+ aiProcess_RemoveRedundantMaterials | // remove redundant materials
+ aiProcess_FindDegenerates | // remove degenerated polygons from the import
+ aiProcess_FindInvalidData | // detect invalid model data, such as invalid normal vectors
+ aiProcess_GenUVCoords | // convert spherical, cylindrical, box and planar mapping to proper UVs
+ aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation ...)
+ aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master
+ aiProcess_LimitBoneWeights | // limit bone weights to 4 per vertex
+ aiProcess_OptimizeMeshes | // join small meshes, if possible;
+ aiProcess_SplitByBoneCount | // split meshes with too many bones. Necessary for our (limited) hardware skinning shader
+ 0;
+
+unsigned int ppstepsdefault = ppsteps;
+
+bool nopointslines = false;
+
+extern bool g_bWasFlipped /*= false*/;
+
+aiMatrix4x4 g_mWorld;
+aiMatrix4x4 g_mWorldRotate;
+aiVector3D g_vRotateSpeed = aiVector3D(0.5f, 0.5f, 0.5f);
+
+// NOTE: The second light direction is now computed from the first
+aiVector3D g_avLightDirs[1] = { aiVector3D(-0.5f, 0.6f, 0.2f) };
+
+ D3DCOLOR g_avLightColors[3] = {
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF),
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0x00),
+ D3DCOLOR_ARGB(0xFF, 0x05, 0x05, 0x05),
+};
+
+POINT g_mousePos;
+POINT g_LastmousePos;
+bool g_bFPSView = false;
+bool g_bInvert = false;
+EClickPos g_eClick = EClickPos_Circle;
+unsigned int g_iCurrentColor = 0;
+
+float g_fLightIntensity = 1.0f;
+float g_fLightColor = 1.0f;
+
+RenderOptions g_sOptions;
+Camera g_sCamera;
+AssetHelper *g_pcAsset = nullptr;
+
+//
+// Contains the mask image for the HUD
+// (used to determine the position of a click)
+//
+unsigned char *g_szImageMask = nullptr;
+
+float g_fLoadTime = 0.0f;
+
+//-------------------------------------------------------------------------------
+// Entry point for the loader thread
+// The loader thread loads the asset while the progress dialog displays the
+// smart progress bar
+//-------------------------------------------------------------------------------
+DWORD WINAPI LoadThreadProc(LPVOID lpParameter) {
+ UNREFERENCED_PARAMETER(lpParameter);
+
+ // get current time
+ double fCur = (double)timeGetTime();
+
+ aiPropertyStore *props = aiCreatePropertyStore();
+ aiSetImportPropertyInteger(props, AI_CONFIG_IMPORT_TER_MAKE_UVS, 1);
+ aiSetImportPropertyFloat(props, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, g_smoothAngle);
+ aiSetImportPropertyInteger(props, AI_CONFIG_PP_SBP_REMOVE, nopointslines ? aiPrimitiveType_LINE | aiPrimitiveType_POINT : 0);
+
+ aiSetImportPropertyInteger(props, AI_CONFIG_GLOB_MEASURE_TIME, 1);
+ //aiSetImportPropertyInteger(props,AI_CONFIG_PP_PTV_KEEP_HIERARCHY,1);
+
+ // Call ASSIMPs C-API to load the file
+ g_pcAsset->pcScene = (aiScene *)aiImportFileExWithProperties(g_szFileName,
+ ppsteps | /* configurable pp steps */
+ aiProcess_GenSmoothNormals | // generate smooth normal vectors if not existing
+ aiProcess_SplitLargeMeshes | // split large, unrenderable meshes into submeshes
+ aiProcess_Triangulate | // triangulate polygons with more than 3 edges
+ aiProcess_ConvertToLeftHanded | // convert everything to D3D left handed space
+ aiProcess_SortByPType | // make 'clean' meshes which consist of a single typ of primitives
+ 0,
+ nullptr,
+ props);
+
+ aiReleasePropertyStore(props);
+
+ // get the end time of zje operation, calculate delta t
+ double fEnd = (double)timeGetTime();
+ g_fLoadTime = (float)((fEnd - fCur) / 1000);
+ g_bLoadingFinished = true;
+
+ // check whether the loading process has failed ...
+ if (nullptr == g_pcAsset->pcScene) {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to load this asset:",
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+
+ // print ASSIMPs error string to the log display
+ CLogDisplay::Instance().AddEntry(aiGetErrorString(),
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+ return 1;
+ }
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------------
+// load the current asset
+// THe path to the asset is specified in the global path variable
+//-------------------------------------------------------------------------------
+int LoadAsset() {
+ // set the world and world rotation matrices to the identity
+ g_mWorldRotate = aiMatrix4x4();
+ g_mWorld = aiMatrix4x4();
+
+ // char szTemp[MAX_PATH+64];
+ // sprintf(szTemp,"Starting to load %s",g_szFileName);
+ CLogWindow::Instance().WriteLine(
+ "----------------------------------------------------------------------------");
+ // CLogWindow::Instance().WriteLine(szTemp);
+ // CLogWindow::Instance().WriteLine(
+ // "----------------------------------------------------------------------------");
+ CLogWindow::Instance().SetAutoUpdate(false);
+
+ // create a helper thread to load the asset
+ DWORD dwID;
+ g_bLoadingCanceled = false;
+ g_pcAsset = new AssetHelper();
+ g_hThreadHandle = CreateThread(nullptr, 0, &LoadThreadProc, nullptr, 0, &dwID);
+
+ if (!g_hThreadHandle) {
+ CLogDisplay::Instance().AddEntry(
+ "[ERROR] Unable to create helper thread for loading",
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+ return 0;
+ }
+
+ // show the progress bar dialog
+ DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_LOADDIALOG),
+ g_hDlg, &ProgressMessageProc);
+
+ // update the log window
+ CLogWindow::Instance().SetAutoUpdate(true);
+ CLogWindow::Instance().Update();
+
+ // now we should have loaded the asset. Check this ...
+ g_bLoadingFinished = false;
+ if (!g_pcAsset || !g_pcAsset->pcScene) {
+ if (g_pcAsset) {
+ delete g_pcAsset;
+ g_pcAsset = nullptr;
+ }
+ return 0;
+ }
+
+ // allocate a new MeshHelper array and build a new instance
+ // for each mesh in the original asset
+ g_pcAsset->apcMeshes = new AssetHelper::MeshHelper *[g_pcAsset->pcScene->mNumMeshes]();
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i)
+ g_pcAsset->apcMeshes[i] = new AssetHelper::MeshHelper();
+
+ // create animator
+ g_pcAsset->mAnimator = new SceneAnimator(g_pcAsset->pcScene);
+
+ // build a new caption string for the viewer
+ static const size_t Size = MAX_PATH + 10;
+ char szOut[Size];
+ ai_snprintf(szOut, Size, AI_VIEW_CAPTION_BASE " [%s]", g_szFileName);
+ SetWindowText(g_hDlg, szOut);
+
+ // scale the asset vertices to fit into the viewer window
+ ScaleAsset();
+
+ // reset the camera view to the default position
+ g_sCamera.vPos = aiVector3D(0.0f, 0.0f, -10.0f);
+ g_sCamera.vLookAt = aiVector3D(0.0f, 0.0f, 1.0f);
+ g_sCamera.vUp = aiVector3D(0.0f, 1.0f, 0.0f);
+ g_sCamera.vRight = aiVector3D(0.0f, 1.0f, 0.0f);
+
+ // build native D3D vertex/index buffers, textures, materials
+ if (1 != CreateAssetData())
+ return 0;
+
+ if (!g_pcAsset->pcScene->HasAnimations()) {
+ EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), FALSE);
+ EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), FALSE);
+ } else {
+ EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), TRUE);
+ EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), TRUE);
+ }
+
+ CLogDisplay::Instance().AddEntry("[OK] The asset has been loaded successfully");
+ CDisplay::Instance().FillDisplayList();
+ CDisplay::Instance().FillAnimList();
+
+ CDisplay::Instance().FillDefaultStatistics();
+
+ // render the scene once
+ CDisplay::Instance().OnRender();
+
+ g_pcAsset->iNormalSet = AssetHelper::ORIGINAL;
+ g_bWasFlipped = false;
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Delete the loaded asset
+// The function does nothing is no asset is loaded
+//-------------------------------------------------------------------------------
+int DeleteAsset(void) {
+ if (!g_pcAsset) {
+ return 0;
+ }
+
+ // don't anymore know why this was necessary ...
+ CDisplay::Instance().OnRender();
+
+ // delete everything
+ DeleteAssetData();
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
+ delete g_pcAsset->apcMeshes[i];
+ }
+ aiReleaseImport(g_pcAsset->pcScene);
+ delete[] g_pcAsset->apcMeshes;
+ delete g_pcAsset->mAnimator;
+ delete g_pcAsset;
+ g_pcAsset = nullptr;
+
+ // reset the caption of the viewer window
+ SetWindowText(g_hDlg, AI_VIEW_CAPTION_BASE);
+
+ // clear UI
+ CDisplay::Instance().ClearAnimList();
+ CDisplay::Instance().ClearDisplayList();
+
+ CMaterialManager::Instance().Reset();
+ UpdateWindow(g_hDlg);
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Calculate the boundaries of a given node and all of its children
+// The boundaries are in Worldspace (AABB)
+// piNode Input node
+// p_avOut Receives the min/max boundaries. Must point to 2 vec3s
+// piMatrix Transformation matrix of the graph at this position
+//-------------------------------------------------------------------------------
+int CalculateBounds(aiNode *piNode, aiVector3D *p_avOut, const aiMatrix4x4 &piMatrix) {
+ ai_assert(nullptr != piNode);
+ ai_assert(nullptr != p_avOut);
+
+ aiMatrix4x4 mTemp = piNode->mTransformation;
+ mTemp.Transpose();
+ aiMatrix4x4 aiMe = mTemp * piMatrix;
+
+ for (unsigned int i = 0; i < piNode->mNumMeshes; ++i) {
+ for (unsigned int a = 0; a < g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]]->mNumVertices; ++a) {
+ aiVector3D pc = g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]]->mVertices[a];
+
+ aiVector3D pc1;
+ D3DXVec3TransformCoord((D3DXVECTOR3 *)&pc1, (D3DXVECTOR3 *)&pc,
+ (D3DXMATRIX *)&aiMe);
+
+ p_avOut[0].x = min(p_avOut[0].x, pc1.x);
+ p_avOut[0].y = min(p_avOut[0].y, pc1.y);
+ p_avOut[0].z = min(p_avOut[0].z, pc1.z);
+ p_avOut[1].x = max(p_avOut[1].x, pc1.x);
+ p_avOut[1].y = max(p_avOut[1].y, pc1.y);
+ p_avOut[1].z = max(p_avOut[1].z, pc1.z);
+ }
+ }
+ for (unsigned int i = 0; i < piNode->mNumChildren; ++i) {
+ CalculateBounds(piNode->mChildren[i], p_avOut, aiMe);
+ }
+ return 1;
+}
+//-------------------------------------------------------------------------------
+// Scale the asset that it fits perfectly into the viewer window
+// The function calculates the boundaries of the mesh and modifies the
+// global world transformation matrix according to the aset AABB
+//-------------------------------------------------------------------------------
+int ScaleAsset(void) {
+ aiVector3D aiVecs[2] = { aiVector3D(1e10f, 1e10f, 1e10f),
+ aiVector3D(-1e10f, -1e10f, -1e10f) };
+
+ if (g_pcAsset->pcScene->mRootNode) {
+ aiMatrix4x4 m;
+ CalculateBounds(g_pcAsset->pcScene->mRootNode, aiVecs, m);
+ }
+
+ aiVector3D vDelta = aiVecs[1] - aiVecs[0];
+ aiVector3D vHalf = aiVecs[0] + (vDelta / 2.0f);
+ float fScale = 10.0f / vDelta.Length();
+
+ g_mWorld = aiMatrix4x4(
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ -vHalf.x, -vHalf.y, -vHalf.z, 1.0f) *
+ aiMatrix4x4(
+ fScale, 0.0f, 0.0f, 0.0f,
+ 0.0f, fScale, 0.0f, 0.0f,
+ 0.0f, 0.0f, fScale, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Generate a vertex buffer which holds the normals of the asset as
+// a list of unconnected lines
+// pcMesh Input mesh
+// pcSource Source mesh from ASSIMP
+//-------------------------------------------------------------------------------
+int GenerateNormalsAsLineList(AssetHelper::MeshHelper *pcMesh, const aiMesh *pcSource) {
+ ai_assert(nullptr != pcMesh);
+ ai_assert(nullptr != pcSource);
+
+ if (!pcSource->mNormals) return 0;
+
+ // create vertex buffer
+ if (FAILED(g_piDevice->CreateVertexBuffer(sizeof(AssetHelper::LineVertex) *
+ pcSource->mNumVertices * 2,
+ D3DUSAGE_WRITEONLY,
+ AssetHelper::LineVertex::GetFVF(),
+ D3DPOOL_DEFAULT, &pcMesh->piVBNormals, nullptr))) {
+ CLogDisplay::Instance().AddEntry("Failed to create vertex buffer for the normal list",
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+ return 2;
+ }
+
+ // now fill the vertex buffer with data
+ AssetHelper::LineVertex *pbData2;
+ pcMesh->piVBNormals->Lock(0, 0, (void **)&pbData2, 0);
+ for (unsigned int x = 0; x < pcSource->mNumVertices; ++x) {
+ pbData2->vPosition = pcSource->mVertices[x];
+
+ ++pbData2;
+
+ aiVector3D vNormal = pcSource->mNormals[x];
+ vNormal.Normalize();
+
+ // scalo with the inverse of the world scaling to make sure
+ // the normals have equal length in each case
+ // TODO: Check whether this works in every case, I don't think so
+ vNormal.x /= g_mWorld.a1 * 4;
+ vNormal.y /= g_mWorld.b2 * 4;
+ vNormal.z /= g_mWorld.c3 * 4;
+
+ pbData2->vPosition = pcSource->mVertices[x] + vNormal;
+
+ ++pbData2;
+ }
+ pcMesh->piVBNormals->Unlock();
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Create the native D3D representation of the asset: vertex buffers,
+// index buffers, materials ...
+//-------------------------------------------------------------------------------
+int CreateAssetData() {
+ if (!g_pcAsset) return 0;
+
+ // reset all subsystems
+ CMaterialManager::Instance().Reset();
+ CDisplay::Instance().Reset();
+
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
+ const aiMesh *mesh = g_pcAsset->pcScene->mMeshes[i];
+
+ // create the material for the mesh
+ if (!g_pcAsset->apcMeshes[i]->piEffect) {
+ CMaterialManager::Instance().CreateMaterial(
+ g_pcAsset->apcMeshes[i], mesh);
+ }
+
+ // create vertex buffer
+ if (FAILED(g_piDevice->CreateVertexBuffer(sizeof(AssetHelper::Vertex) *
+ mesh->mNumVertices,
+ D3DUSAGE_WRITEONLY,
+ 0,
+ D3DPOOL_DEFAULT, &g_pcAsset->apcMeshes[i]->piVB, nullptr))) {
+ MessageBox(g_hDlg, "Failed to create vertex buffer",
+ "ASSIMP Viewer Utility", MB_OK);
+ return 2;
+ }
+
+ DWORD dwUsage = 0;
+ if (g_pcAsset->apcMeshes[i]->piOpacityTexture || 1.0f != g_pcAsset->apcMeshes[i]->fOpacity)
+ dwUsage |= D3DUSAGE_DYNAMIC;
+
+ unsigned int nidx = 0;
+ switch (mesh->mPrimitiveTypes) {
+ case aiPrimitiveType_POINT:
+ nidx = 1;
+ break;
+ case aiPrimitiveType_LINE:
+ nidx = 2;
+ break;
+ case aiPrimitiveType_TRIANGLE:
+ nidx = 3;
+ break;
+ default:
+ CLogWindow::Instance().WriteLine("Unknown primitive type");
+ break;
+ };
+
+ unsigned int numIndices = mesh->mNumFaces * 3;
+ if (0 == numIndices && nidx == 1) {
+ numIndices = mesh->mNumVertices;
+ }
+ // check whether we can use 16 bit indices
+ if (numIndices >= 65536) {
+ // create 32 bit index buffer
+ if (FAILED(g_piDevice->CreateIndexBuffer(4 * numIndices,
+ D3DUSAGE_WRITEONLY | dwUsage,
+ D3DFMT_INDEX32,
+ D3DPOOL_DEFAULT,
+ &g_pcAsset->apcMeshes[i]->piIB,
+ nullptr))) {
+ MessageBox(g_hDlg, "Failed to create 32 Bit index buffer",
+ "ASSIMP Viewer Utility", MB_OK);
+ return 2;
+ }
+
+ // now fill the index buffer
+ unsigned int *pbData;
+ g_pcAsset->apcMeshes[i]->piIB->Lock(0, 0, (void **)&pbData, 0);
+ for (unsigned int x = 0; x < mesh->mNumFaces; ++x) {
+ for (unsigned int a = 0; a < nidx; ++a) {
+ *pbData++ = mesh->mFaces[x].mIndices[a];
+ }
+ }
+ } else {
+ // create 16 bit index buffer
+ if (FAILED(g_piDevice->CreateIndexBuffer(2 *
+numIndices,
+ D3DUSAGE_WRITEONLY | dwUsage,
+ D3DFMT_INDEX16,
+ D3DPOOL_DEFAULT,
+ &g_pcAsset->apcMeshes[i]->piIB,
+ nullptr))) {
+ MessageBox(g_hDlg, "Failed to create 16 Bit index buffer",
+ "ASSIMP Viewer Utility", MB_OK);
+ return 2;
+ }
+
+ // now fill the index buffer
+ uint16_t *pbData;
+ g_pcAsset->apcMeshes[i]->piIB->Lock(0, 0, (void **)&pbData, 0);
+ for (unsigned int x = 0; x < mesh->mNumFaces; ++x) {
+ for (unsigned int a = 0; a < nidx; ++a) {
+ *pbData++ = (uint16_t)mesh->mFaces[x].mIndices[a];
+ }
+ }
+ }
+ g_pcAsset->apcMeshes[i]->piIB->Unlock();
+
+ // collect weights on all vertices. Quick and careless
+ std::vector<std::vector<aiVertexWeight>> weightsPerVertex(mesh->mNumVertices);
+ for (unsigned int a = 0; a < mesh->mNumBones; a++) {
+ const aiBone *bone = mesh->mBones[a];
+ for (unsigned int b = 0; b < bone->mNumWeights; b++)
+ weightsPerVertex[bone->mWeights[b].mVertexId].push_back(aiVertexWeight(a, bone->mWeights[b].mWeight));
+ }
+
+ // now fill the vertex buffer
+ AssetHelper::Vertex *pbData2;
+ g_pcAsset->apcMeshes[i]->piVB->Lock(0, 0, (void **)&pbData2, 0);
+ for (unsigned int x = 0; x < mesh->mNumVertices; ++x) {
+ pbData2->vPosition = mesh->mVertices[x];
+
+ if (nullptr == mesh->mNormals)
+ pbData2->vNormal = aiVector3D(0.0f, 0.0f, 0.0f);
+ else
+ pbData2->vNormal = mesh->mNormals[x];
+
+ if (nullptr == mesh->mTangents) {
+ pbData2->vTangent = aiVector3D(0.0f, 0.0f, 0.0f);
+ pbData2->vBitangent = aiVector3D(0.0f, 0.0f, 0.0f);
+ } else {
+ pbData2->vTangent = mesh->mTangents[x];
+ pbData2->vBitangent = mesh->mBitangents[x];
+ }
+
+ if (mesh->HasVertexColors(0)) {
+ pbData2->dColorDiffuse = D3DCOLOR_ARGB(
+ ((unsigned char)max(min(mesh->mColors[0][x].a * 255.0f, 255.0f), 0.0f)),
+ ((unsigned char)max(min(mesh->mColors[0][x].r * 255.0f, 255.0f), 0.0f)),
+ ((unsigned char)max(min(mesh->mColors[0][x].g * 255.0f, 255.0f), 0.0f)),
+ ((unsigned char)max(min(mesh->mColors[0][x].b * 255.0f, 255.0f), 0.0f)));
+ } else
+ pbData2->dColorDiffuse = D3DCOLOR_ARGB(0xFF, 0xff, 0xff, 0xff);
+
+ // ignore a third texture coordinate component
+ if (mesh->HasTextureCoords(0)) {
+ pbData2->vTextureUV = aiVector2D(
+ mesh->mTextureCoords[0][x].x,
+ mesh->mTextureCoords[0][x].y);
+ } else
+ pbData2->vTextureUV = aiVector2D(0.5f, 0.5f);
+
+ if (mesh->HasTextureCoords(1)) {
+ pbData2->vTextureUV2 = aiVector2D(
+ mesh->mTextureCoords[1][x].x,
+ mesh->mTextureCoords[1][x].y);
+ } else
+ pbData2->vTextureUV2 = aiVector2D(0.5f, 0.5f);
+
+ // Bone indices and weights
+ if (mesh->HasBones()) {
+ unsigned char boneIndices[4] = { 0, 0, 0, 0 };
+ unsigned char boneWeights[4] = { 0, 0, 0, 0 };
+ ai_assert(weightsPerVertex[x].size() <= 4);
+ for (unsigned int a = 0; a < weightsPerVertex[x].size(); a++) {
+ boneIndices[a] = static_cast<unsigned char>(weightsPerVertex[x][a].mVertexId);
+ boneWeights[a] = (unsigned char)(weightsPerVertex[x][a].mWeight * 255.0f);
+ }
+
+ memcpy(pbData2->mBoneIndices, boneIndices, sizeof(boneIndices));
+ memcpy(pbData2->mBoneWeights, boneWeights, sizeof(boneWeights));
+ } else {
+ memset(pbData2->mBoneIndices, 0, sizeof(pbData2->mBoneIndices));
+ memset(pbData2->mBoneWeights, 0, sizeof(pbData2->mBoneWeights));
+ }
+
+ ++pbData2;
+ }
+ g_pcAsset->apcMeshes[i]->piVB->Unlock();
+
+ // now generate the second vertex buffer, holding all normals
+ if (!g_pcAsset->apcMeshes[i]->piVBNormals) {
+ GenerateNormalsAsLineList(g_pcAsset->apcMeshes[i], mesh);
+ }
+ }
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Delete all effects, textures, vertex buffers ... associated with
+// an asset
+//-------------------------------------------------------------------------------
+int DeleteAssetData(bool bNoMaterials) {
+ if (!g_pcAsset) return 0;
+
+ // TODO: Move this to a proper destructor
+ for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
+ if (g_pcAsset->apcMeshes[i]->piVB) {
+ g_pcAsset->apcMeshes[i]->piVB->Release();
+ g_pcAsset->apcMeshes[i]->piVB = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piVBNormals) {
+ g_pcAsset->apcMeshes[i]->piVBNormals->Release();
+ g_pcAsset->apcMeshes[i]->piVBNormals = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piIB) {
+ g_pcAsset->apcMeshes[i]->piIB->Release();
+ g_pcAsset->apcMeshes[i]->piIB = nullptr;
+ }
+
+ // TODO ... unfixed memory leak
+ // delete storage eventually allocated to hold a copy
+ // of the original vertex normals
+ //if (g_pcAsset->apcMeshes[i]->pvOriginalNormals)
+ //{
+ // delete[] g_pcAsset->apcMeshes[i]->pvOriginalNormals;
+ //}
+
+ if (!bNoMaterials) {
+ if (g_pcAsset->apcMeshes[i]->piEffect) {
+ g_pcAsset->apcMeshes[i]->piEffect->Release();
+ g_pcAsset->apcMeshes[i]->piEffect = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piDiffuseTexture) {
+ g_pcAsset->apcMeshes[i]->piDiffuseTexture->Release();
+ g_pcAsset->apcMeshes[i]->piDiffuseTexture = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piNormalTexture) {
+ g_pcAsset->apcMeshes[i]->piNormalTexture->Release();
+ g_pcAsset->apcMeshes[i]->piNormalTexture = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piSpecularTexture) {
+ g_pcAsset->apcMeshes[i]->piSpecularTexture->Release();
+ g_pcAsset->apcMeshes[i]->piSpecularTexture = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piAmbientTexture) {
+ g_pcAsset->apcMeshes[i]->piAmbientTexture->Release();
+ g_pcAsset->apcMeshes[i]->piAmbientTexture = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piEmissiveTexture) {
+ g_pcAsset->apcMeshes[i]->piEmissiveTexture->Release();
+ g_pcAsset->apcMeshes[i]->piEmissiveTexture = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piOpacityTexture) {
+ g_pcAsset->apcMeshes[i]->piOpacityTexture->Release();
+ g_pcAsset->apcMeshes[i]->piOpacityTexture = nullptr;
+ }
+ if (g_pcAsset->apcMeshes[i]->piShininessTexture) {
+ g_pcAsset->apcMeshes[i]->piShininessTexture->Release();
+ g_pcAsset->apcMeshes[i]->piShininessTexture = nullptr;
+ }
+ }
+ }
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Switch between zoom/rotate view and the standard FPS view
+// g_bFPSView specifies the view mode to setup
+//-------------------------------------------------------------------------------
+int SetupFPSView() {
+ if (!g_bFPSView) {
+ g_sCamera.vPos = aiVector3D(0.0f, 0.0f, g_fWheelPos);
+ g_sCamera.vLookAt = aiVector3D(0.0f, 0.0f, 1.0f);
+ g_sCamera.vUp = aiVector3D(0.0f, 1.0f, 0.0f);
+ g_sCamera.vRight = aiVector3D(0.0f, 1.0f, 0.0f);
+ } else {
+ g_fWheelPos = g_sCamera.vPos.z;
+ g_sCamera.vPos = aiVector3D(0.0f, 0.0f, -10.0f);
+ g_sCamera.vLookAt = aiVector3D(0.0f, 0.0f, 1.0f);
+ g_sCamera.vUp = aiVector3D(0.0f, 1.0f, 0.0f);
+ g_sCamera.vRight = aiVector3D(0.0f, 1.0f, 0.0f);
+ }
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Initialize the IDIrect3D interface
+// Called by the WinMain
+//-------------------------------------------------------------------------------
+int InitD3D(void) {
+ if (nullptr == g_piD3D) {
+ g_piD3D = Direct3DCreate9(D3D_SDK_VERSION);
+ if (nullptr == g_piD3D) return 0;
+ }
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+// Release the IDirect3D interface.
+// NOTE: Assumes that the device has already been deleted
+//-------------------------------------------------------------------------------
+int ShutdownD3D(void) {
+ ShutdownDevice();
+ if (nullptr != g_piD3D) {
+ g_piD3D->Release();
+ g_piD3D = nullptr;
+ }
+ return 1;
+}
+
+template <class TComPtr>
+inline void SafeRelease(TComPtr *&ptr) {
+ if (nullptr != ptr) {
+ ptr->Release();
+ ptr = nullptr;
+ }
+}
+
+//-------------------------------------------------------------------------------
+// Shutdown the D3D device object and all resources associated with it
+// NOTE: Assumes that the asset has already been deleted
+//-------------------------------------------------------------------------------
+int ShutdownDevice(void) {
+ // release other subsystems
+ CBackgroundPainter::Instance().ReleaseNativeResource();
+ CLogDisplay::Instance().ReleaseNativeResource();
+
+ // release global shaders that have been allocated
+ SafeRelease(g_piDefaultEffect);
+ SafeRelease(g_piNormalsEffect);
+ SafeRelease(g_piPassThroughEffect);
+ SafeRelease(g_piPatternEffect);
+ SafeRelease(g_pcTexture);
+ SafeRelease(gDefaultVertexDecl);
+
+ // delete the main D3D device object
+ SafeRelease(g_piDevice);
+
+ // deleted the one channel image allocated to hold the HUD mask
+ delete[] g_szImageMask;
+ g_szImageMask = nullptr;
+
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------
+int CreateHUDTexture() {
+ // lock the memory resource ourselves
+ HRSRC res = FindResource(nullptr, MAKEINTRESOURCE(IDR_HUD), RT_RCDATA);
+ HGLOBAL hg = LoadResource(nullptr, res);
+ void *pData = LockResource(hg);
+
+ if (FAILED(D3DXCreateTextureFromFileInMemoryEx(g_piDevice,
+ pData, SizeofResource(nullptr, res),
+ D3DX_DEFAULT_NONPOW2,
+ D3DX_DEFAULT_NONPOW2,
+ 1,
+ 0,
+ D3DFMT_A8R8G8B8,
+ D3DPOOL_MANAGED,
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ nullptr,
+ nullptr,
+ &g_pcTexture))) {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD texture",
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+
+ g_pcTexture = nullptr;
+ g_szImageMask = nullptr;
+
+ FreeResource(hg);
+ return 0;
+ }
+
+ FreeResource(hg);
+
+ D3DSURFACE_DESC sDesc;
+ g_pcTexture->GetLevelDesc(0, &sDesc);
+
+ // lock the memory resource ourselves
+ res = FindResource(nullptr, MAKEINTRESOURCE(IDR_HUDMASK), RT_RCDATA);
+ hg = LoadResource(nullptr, res);
+ pData = LockResource(hg);
+
+ IDirect3DTexture9 *pcTex;
+ if (FAILED(D3DXCreateTextureFromFileInMemoryEx(g_piDevice,
+ pData, SizeofResource(nullptr, res),
+ sDesc.Width,
+ sDesc.Height,
+ 1,
+ 0,
+ D3DFMT_L8,
+ D3DPOOL_MANAGED, // unnecessary
+ D3DX_DEFAULT,
+ D3DX_DEFAULT,
+ 0,
+ nullptr,
+ nullptr,
+ &pcTex))) {
+ CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD mask texture",
+ D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
+ g_szImageMask = nullptr;
+
+ FreeResource(hg);
+ return 0;
+ }
+
+ FreeResource(hg);
+
+ // lock the texture and copy it to get a pointer
+ D3DLOCKED_RECT sRect;
+ pcTex->LockRect(0, &sRect, nullptr, D3DLOCK_READONLY);
+
+ unsigned char *szOut = new unsigned char[sDesc.Width * sDesc.Height];
+ unsigned char *_szOut = szOut;
+
+ unsigned char *szCur = (unsigned char *)sRect.pBits;
+ for (unsigned int y = 0; y < sDesc.Height; ++y) {
+ memcpy(_szOut, szCur, sDesc.Width);
+
+ szCur += sRect.Pitch;
+ _szOut += sDesc.Width;
+ }
+ pcTex->UnlockRect(0);
+ pcTex->Release();
+
+ g_szImageMask = szOut;
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------
+int CreateDevice(bool p_bMultiSample, bool p_bSuperSample, bool bHW /*= true*/) {
+ D3DDEVTYPE eType = bHW ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF;
+
+ // get the client rectangle of the window.
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg, IDC_RT), &sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+
+ D3DPRESENT_PARAMETERS sParams;
+ memset(&sParams, 0, sizeof(D3DPRESENT_PARAMETERS));
+
+ // get the current display mode
+ D3DDISPLAYMODE sMode;
+ g_piD3D->GetAdapterDisplayMode(0, &sMode);
+
+ // fill the presentation parameter structure
+ sParams.Windowed = TRUE;
+ sParams.hDeviceWindow = GetDlgItem(g_hDlg, IDC_RT);
+ sParams.EnableAutoDepthStencil = TRUE;
+ sParams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ sParams.BackBufferWidth = (UINT)sRect.right;
+ sParams.BackBufferHeight = (UINT)sRect.bottom;
+ sParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ sParams.BackBufferCount = 1;
+
+ // check whether we can use a D32 depth buffer format
+ if (SUCCEEDED(g_piD3D->CheckDepthStencilMatch(0, eType,
+ D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_D32))) {
+ sParams.AutoDepthStencilFormat = D3DFMT_D32;
+ } else
+ sParams.AutoDepthStencilFormat = D3DFMT_D24X8;
+
+ // find the highest multisample type available on this device
+ D3DMULTISAMPLE_TYPE sMS = D3DMULTISAMPLE_2_SAMPLES;
+ D3DMULTISAMPLE_TYPE sMSOut = D3DMULTISAMPLE_NONE;
+ DWORD dwQuality = 0;
+ if (p_bMultiSample) {
+ while ((D3DMULTISAMPLE_TYPE)(D3DMULTISAMPLE_16_SAMPLES + 1) !=
+ (sMS = (D3DMULTISAMPLE_TYPE)(sMS + 1))) {
+ if (SUCCEEDED(g_piD3D->CheckDeviceMultiSampleType(0, eType,
+ sMode.Format, TRUE, sMS, &dwQuality))) {
+ sMSOut = sMS;
+ }
+ }
+ if (0 != dwQuality) dwQuality -= 1;
+
+ sParams.MultiSampleQuality = dwQuality;
+ sParams.MultiSampleType = sMSOut;
+ }
+
+ // get the device capabilities. If the hardware vertex shader is too old, we prefer software vertex processing
+ g_piD3D->GetDeviceCaps(0, D3DDEVTYPE_HAL, &g_sCaps);
+ DWORD creationFlags = D3DCREATE_MULTITHREADED;
+ if (g_sCaps.VertexShaderVersion >= D3DVS_VERSION(2, 0))
+ creationFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ else
+ creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+
+ // create the D3D9 device object. with software-vertexprocessing if VS2.0 isn`t supported in hardware
+ if (FAILED(g_piD3D->CreateDevice(0, eType, g_hDlg, creationFlags, &sParams, &g_piDevice))) {
+ // if hardware fails use software rendering instead
+ if (bHW) return CreateDevice(p_bMultiSample, p_bSuperSample, false);
+ return 0;
+ }
+
+ // create a vertex declaration to match the vertex
+ D3DVERTEXELEMENT9 *vdecl = AssetHelper::Vertex::GetDeclarationElements();
+ if (FAILED(g_piDevice->CreateVertexDeclaration(vdecl, &gDefaultVertexDecl))) {
+ MessageBox(g_hDlg, "Failed to create vertex declaration", "Init", MB_OK);
+ return 0;
+ }
+ g_piDevice->SetVertexDeclaration(gDefaultVertexDecl);
+
+ // get the capabilities of the device object
+ g_piDevice->GetDeviceCaps(&g_sCaps);
+ if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(3, 0)) {
+ EnableWindow(GetDlgItem(g_hDlg, IDC_LOWQUALITY), FALSE);
+ }
+
+ // compile the default material shader (gray gouraud/phong)
+ ID3DXBuffer *piBuffer = nullptr;
+ if (FAILED(D3DXCreateEffect(g_piDevice,
+ g_szDefaultShader.c_str(),
+ (UINT)g_szDefaultShader.length(),
+ nullptr,
+ nullptr,
+ AI_SHADER_COMPILE_FLAGS,
+ nullptr,
+ &g_piDefaultEffect, &piBuffer))) {
+ if (piBuffer) {
+ MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
+ piBuffer->Release();
+ }
+ return 0;
+ }
+ if (piBuffer) {
+ piBuffer->Release();
+ piBuffer = nullptr;
+ }
+
+ // use Fixed Function effect when working with shaderless cards
+ if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
+ g_piDefaultEffect->SetTechnique("DefaultFXSpecular_FF");
+
+ // create the shader used to draw the HUD
+ if (FAILED(D3DXCreateEffect(g_piDevice,
+ g_szPassThroughShader.c_str(), (UINT)g_szPassThroughShader.length(),
+ nullptr, nullptr, AI_SHADER_COMPILE_FLAGS, nullptr, &g_piPassThroughEffect, &piBuffer))) {
+ if (piBuffer) {
+ MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
+ piBuffer->Release();
+ }
+ return 0;
+ }
+ if (piBuffer) {
+ piBuffer->Release();
+ piBuffer = nullptr;
+ }
+
+ // use Fixed Function effect when working with shaderless cards
+ if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
+ g_piPassThroughEffect->SetTechnique("PassThrough_FF");
+
+ // create the shader used to visualize normal vectors
+ if (FAILED(D3DXCreateEffect(g_piDevice,
+ g_szNormalsShader.c_str(), (UINT)g_szNormalsShader.length(),
+ nullptr, nullptr, AI_SHADER_COMPILE_FLAGS, nullptr, &g_piNormalsEffect, &piBuffer))) {
+ if (piBuffer) {
+ MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
+ piBuffer->Release();
+ }
+ return 0;
+ }
+ if (piBuffer) {
+ piBuffer->Release();
+ piBuffer = nullptr;
+ }
+
+ //MessageBox( g_hDlg, "Failed to create vertex declaration", "Init", MB_OK);
+
+ // use Fixed Function effect when working with shaderless cards
+ if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
+ g_piNormalsEffect->SetTechnique("RenderNormals_FF");
+
+ g_piDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE);
+
+ // create the texture for the HUD
+ CreateHUDTexture();
+ CBackgroundPainter::Instance().RecreateNativeResource();
+ CLogDisplay::Instance().RecreateNativeResource();
+
+ g_piPassThroughEffect->SetTexture("TEXTURE_2D", g_pcTexture);
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+int CreateDevice() {
+ return CreateDevice(g_sOptions.bMultiSample,
+ g_sOptions.bSuperSample);
+}
+
+//-------------------------------------------------------------------------------
+int GetProjectionMatrix(aiMatrix4x4 &p_mOut) {
+ const float fFarPlane = 100.0f;
+ const float fNearPlane = 0.1f;
+ const float fFOV = (float)(45.0 * 0.0174532925);
+
+ const float s = 1.0f / tanf(fFOV * 0.5f);
+ const float Q = fFarPlane / (fFarPlane - fNearPlane);
+
+ RECT sRect;
+ GetWindowRect(GetDlgItem(g_hDlg, IDC_RT), &sRect);
+ sRect.right -= sRect.left;
+ sRect.bottom -= sRect.top;
+ const float fAspect = (float)sRect.right / (float)sRect.bottom;
+
+ p_mOut = aiMatrix4x4(
+ s / fAspect, 0.0f, 0.0f, 0.0f,
+ 0.0f, s, 0.0f, 0.0f,
+ 0.0f, 0.0f, Q, 1.0f,
+ 0.0f, 0.0f, -Q * fNearPlane, 0.0f);
+ return 1;
+}
+
+//-------------------------------------------------------------------------------
+aiVector3D GetCameraMatrix(aiMatrix4x4 &p_mOut) {
+ D3DXMATRIX view;
+ D3DXMatrixIdentity(&view);
+
+ D3DXVec3Normalize((D3DXVECTOR3 *)&g_sCamera.vLookAt, (D3DXVECTOR3 *)&g_sCamera.vLookAt);
+ D3DXVec3Cross((D3DXVECTOR3 *)&g_sCamera.vRight, (D3DXVECTOR3 *)&g_sCamera.vUp, (D3DXVECTOR3 *)&g_sCamera.vLookAt);
+ D3DXVec3Normalize((D3DXVECTOR3 *)&g_sCamera.vRight, (D3DXVECTOR3 *)&g_sCamera.vRight);
+ D3DXVec3Cross((D3DXVECTOR3 *)&g_sCamera.vUp, (D3DXVECTOR3 *)&g_sCamera.vLookAt, (D3DXVECTOR3 *)&g_sCamera.vRight);
+ D3DXVec3Normalize((D3DXVECTOR3 *)&g_sCamera.vUp, (D3DXVECTOR3 *)&g_sCamera.vUp);
+
+ view._11 = g_sCamera.vRight.x;
+ view._12 = g_sCamera.vUp.x;
+ view._13 = g_sCamera.vLookAt.x;
+ view._14 = 0.0f;
+
+ view._21 = g_sCamera.vRight.y;
+ view._22 = g_sCamera.vUp.y;
+ view._23 = g_sCamera.vLookAt.y;
+ view._24 = 0.0f;
+
+ view._31 = g_sCamera.vRight.z;
+ view._32 = g_sCamera.vUp.z;
+ view._33 = g_sCamera.vLookAt.z;
+ view._34 = 0.0f;
+
+ view._41 = -D3DXVec3Dot((D3DXVECTOR3 *)&g_sCamera.vPos, (D3DXVECTOR3 *)&g_sCamera.vRight);
+ view._42 = -D3DXVec3Dot((D3DXVECTOR3 *)&g_sCamera.vPos, (D3DXVECTOR3 *)&g_sCamera.vUp);
+ view._43 = -D3DXVec3Dot((D3DXVECTOR3 *)&g_sCamera.vPos, (D3DXVECTOR3 *)&g_sCamera.vLookAt);
+ view._44 = 1.0f;
+
+ memcpy(&p_mOut, &view, sizeof(aiMatrix4x4));
+
+ return g_sCamera.vPos;
+}
+
+} // namespace AssimpView
diff --git a/libs/assimp/tools/assimp_view/assimp_view.h b/libs/assimp/tools/assimp_view/assimp_view.h
new file mode 100644
index 0000000..cbcee3c
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/assimp_view.h
@@ -0,0 +1,270 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+---------------------------------------------------------------------------
+*/
+
+#if (!defined AV_MAIN_H_INCLUDED)
+#define AV_MAIN_H_INCLUDED
+
+#define AI_SHADER_COMPILE_FLAGS D3DXSHADER_USE_LEGACY_D3DX9_31_DLL
+
+// Because Dx headers include windef.h with min/max redefinition
+#define NOMINMAX
+
+// include resource definitions
+#include "resource.h"
+
+#include <assert.h>
+#include <malloc.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tchar.h>
+#include <time.h>
+
+// Include ASSIMP headers (XXX: do we really need all of them?)
+#include <assimp/ai_assert.h>
+#include <assimp/cfileio.h>
+#include <assimp/cimport.h>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/IOStream.hpp>
+#include <assimp/IOSystem.hpp>
+#include <assimp/Importer.hpp>
+#include <assimp/LogStream.hpp>
+
+#include "Material/MaterialSystem.h" // aiMaterial class
+#include <assimp/StringComparison.h> // ASSIMP_stricmp and ASSIMP_strincmp
+
+#include <time.h>
+
+// default movement speed
+#define MOVE_SPEED 3.f
+
+#include "AssetHelper.h"
+#include "Background.h"
+#include "Camera.h"
+#include "Display.h"
+#include "LogDisplay.h"
+#include "LogWindow.h"
+#include "MaterialManager.h"
+#include "MeshRenderer.h"
+#include "RenderOptions.h"
+#include "Shaders.h"
+
+// outside of namespace, to help Intellisense and solve boost::metatype_stuff_miracle
+#include "AnimEvaluator.h"
+#include "SceneAnimator.h"
+
+namespace AssimpView {
+
+//-------------------------------------------------------------------------------
+// Function prototypes
+//-------------------------------------------------------------------------------
+int InitD3D(void);
+int ShutdownD3D(void);
+int CreateDevice(bool p_bMultiSample, bool p_bSuperSample, bool bHW = true);
+int CreateDevice(void);
+int ShutdownDevice(void);
+int GetProjectionMatrix(aiMatrix4x4 &p_mOut);
+int LoadAsset(void);
+int CreateAssetData(void);
+int DeleteAssetData(bool bNoMaterials = false);
+int ScaleAsset(void);
+int DeleteAsset(void);
+int SetupFPSView();
+
+aiVector3D GetCameraMatrix(aiMatrix4x4 &p_mOut);
+int CreateMaterial(AssetHelper::MeshHelper *pcMesh, const aiMesh *pcSource);
+
+void HandleMouseInputFPS(void);
+void HandleMouseInputLightRotate(void);
+void HandleMouseInputLocal(void);
+void HandleKeyboardInputFPS(void);
+void HandleMouseInputLightIntensityAndColor(void);
+void HandleMouseInputSkyBox(void);
+void HandleKeyboardInputTextureView(void);
+void HandleMouseInputTextureView(void);
+
+//-------------------------------------------------------------------------------
+//
+// Dialog procedure for the progress bar window
+//
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK ProgressMessageProc(HWND hwndDlg, UINT uMsg,
+ WPARAM wParam, LPARAM lParam);
+
+//-------------------------------------------------------------------------------
+// Main message procedure of the application
+//
+// The function handles all incoming messages for the main window.
+// However, if does not directly process input commands.
+// NOTE: Due to the impossibility to process WM_CHAR messages in dialogs
+// properly the code for all hotkeys has been moved to the WndMain
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK MessageProc(HWND hwndDlg, UINT uMsg,
+ WPARAM wParam, LPARAM lParam);
+
+//-------------------------------------------------------------------------------
+//
+// Dialog procedure for the about dialog
+//
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK AboutMessageProc(HWND hwndDlg, UINT uMsg,
+ WPARAM wParam, LPARAM lParam);
+
+//-------------------------------------------------------------------------------
+//
+// Dialog procedure for the help dialog
+//
+//-------------------------------------------------------------------------------
+INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg, UINT uMsg,
+ WPARAM wParam, LPARAM lParam);
+
+//-------------------------------------------------------------------------------
+// Handle command line parameters
+//
+// The function loads an asset specified on the command line as first argument
+// Other command line parameters are not handled
+//-------------------------------------------------------------------------------
+void HandleCommandLine(char *p_szCommand);
+
+//-------------------------------------------------------------------------------
+template <class type, class intype>
+type clamp(intype in) {
+ // for unsigned types only ...
+ intype mask = (0x1u << (sizeof(type) * 8)) - 1;
+ return (type)std::max((intype)0, std::min(in, mask));
+}
+
+//-------------------------------------------------------------------------------
+// Position of the cursor relative to the 3ds max' like control circle
+//-------------------------------------------------------------------------------
+enum EClickPos {
+ // The click was inside the inner circle (x,y axis)
+ EClickPos_Circle,
+ // The click was inside one of the vertical snap-ins
+ EClickPos_CircleVert,
+ // The click was inside onf of the horizontal snap-ins
+ EClickPos_CircleHor,
+ // the cklick was outside the circle (z-axis)
+ EClickPos_Outside
+};
+
+#if (!defined AI_VIEW_CAPTION_BASE)
+#define AI_VIEW_CAPTION_BASE "Open Asset Import Library : Viewer "
+#endif // !! AI_VIEW_CAPTION_BASE
+
+//-------------------------------------------------------------------------------
+// Evil globals
+//-------------------------------------------------------------------------------
+extern HINSTANCE g_hInstance /*= NULL*/;
+extern HWND g_hDlg /*= NULL*/;
+extern IDirect3D9 *g_piD3D /*= NULL*/;
+extern IDirect3DDevice9 *g_piDevice /*= NULL*/;
+extern IDirect3DVertexDeclaration9 *gDefaultVertexDecl /*= NULL*/;
+extern double g_fFPS /*= 0.0f*/;
+extern char g_szFileName[MAX_PATH];
+extern ID3DXEffect *g_piDefaultEffect /*= NULL*/;
+extern ID3DXEffect *g_piNormalsEffect /*= NULL*/;
+extern ID3DXEffect *g_piPassThroughEffect /*= NULL*/;
+extern ID3DXEffect *g_piPatternEffect /*= NULL*/;
+extern bool g_bMousePressed /*= false*/;
+extern bool g_bMousePressedR /*= false*/;
+extern bool g_bMousePressedM /*= false*/;
+extern bool g_bMousePressedBoth /*= false*/;
+extern float g_fElpasedTime /*= 0.0f*/;
+extern D3DCAPS9 g_sCaps;
+extern bool g_bLoadingFinished /*= false*/;
+extern HANDLE g_hThreadHandle /*= NULL*/;
+extern float g_fWheelPos /*= -10.0f*/;
+extern bool g_bLoadingCanceled /*= false*/;
+extern IDirect3DTexture9 *g_pcTexture /*= NULL*/;
+
+extern aiMatrix4x4 g_mWorld;
+extern aiMatrix4x4 g_mWorldRotate;
+extern aiVector3D g_vRotateSpeed /*= aiVector3D(0.5f,0.5f,0.5f)*/;
+
+extern aiVector3D g_avLightDirs[1] /* =
+ { aiVector3D(-0.5f,0.6f,0.2f) ,
+ aiVector3D(-0.5f,0.5f,0.5f)} */
+ ;
+
+extern POINT g_mousePos /*= {0,0};*/;
+extern POINT g_LastmousePos /*= {0,0}*/;
+extern bool g_bFPSView /*= false*/;
+extern bool g_bInvert /*= false*/;
+extern EClickPos g_eClick;
+extern unsigned int g_iCurrentColor /*= 0*/;
+
+// NOTE: The light intensity is separated from the color, it can
+// directly be manipulated using the middle mouse button.
+// When the user chooses a color from the palette the intensity
+// is reset to 1.0
+// index[2] is the ambient color
+extern float g_fLightIntensity /*=0.0f*/;
+extern D3DCOLOR g_avLightColors[3];
+
+extern RenderOptions g_sOptions;
+extern Camera g_sCamera;
+extern AssetHelper *g_pcAsset /*= NULL*/;
+
+//
+// Contains the mask image for the HUD
+// (used to determine the position of a click)
+//
+// The size of the image is identical to the size of the main
+// HUD texture
+//
+extern unsigned char *g_szImageMask /*= NULL*/;
+
+extern float g_fACMR /*= 3.0f*/;
+extern IDirect3DQuery9 *g_piQuery;
+
+extern bool g_bPlay /*= false*/;
+
+extern double g_dCurrent;
+extern float g_smoothAngle /*= 80.f*/;
+
+extern unsigned int ppsteps, ppstepsdefault;
+extern bool nopointslines;
+} // namespace AssimpView
+
+#endif // !! AV_MAIN_H_INCLUDED
diff --git a/libs/assimp/tools/assimp_view/assimp_view.rc b/libs/assimp/tools/assimp_view/assimp_view.rc
new file mode 100644
index 0000000..48d7c36
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/assimp_view.rc
@@ -0,0 +1,468 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ASSIMP_VIEW ICON "../shared/assimp_tools_icon.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOGEX 22, 17, 283, 149
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_CAPTION | WS_SYSMENU
+CAPTION "About Open Asset Import Library"
+FONT 9, "Courier New", 400, 0, 0x0
+BEGIN
+ LTEXT "Open Asset Import Library (Assimp)",IDC_STATIC,30,14,144,9
+ LTEXT "A free C/C++ library to read various well-known 3D model formats into a straightforward in-memory format for easy processing by applications. Licensed under a 3-clause BSD license and totally awesome.",IDC_STATIC,31,34,204,24
+ LTEXT "(c) 2008-2020. Assimp Development Team. See the CREDITS file for a list of all contributors.",IDC_STATIC,30,65,204,23
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,27,282,1
+ LTEXT "http://assimp.sourceforge.net http://www.zfx.info",IDC_STATIC,31,101,127,22
+ DEFPUSHBUTTON "Love this library",IDOK,186,110,84,14
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,148,283,1
+ CONTROL IDB_BITMAP1,IDC_STATIC,"Static",SS_BITMAP,0,129,514,20
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,10,281,1
+END
+
+IDD_DIALOGMAIN DIALOGEX 0, 0, 656, 450
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_ACCEPTFILES | WS_EX_WINDOWEDGE
+CAPTION "Open Asset Import Library - Model Viewer "
+MENU IDR_MENU1
+FONT 8, "Microsoft Sans Serif", 400, 0, 0x0
+BEGIN
+ CONTROL "",IDC_RT,"Static",SS_OWNERDRAW,0,0,513,324
+ CONTROL "",IDC_TREE1,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,513,0,143,450
+ CONTROL "<<",IDC_BLUBB,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,471,328,35,14
+ COMBOBOX IDC_COMBO1,367,328,100,14,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Play",IDC_PLAY,328,328,35,14
+ CONTROL "",IDC_SLIDERANIM,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,0,328,328,15
+ GROUPBOX "Display",IDC_STATIC,7,345,172,101
+ CONTROL "Multisampling [M]",IDC_TOGGLEMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,357,80,10
+ CONTROL "Wireframe [W]",IDC_TOGGLEWIRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,369,80,10
+ CONTROL "No materials [D]",IDC_TOGGLEMAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,381,80,10
+ CONTROL "Display normals [N]",IDC_TOGGLENORMALS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,393,80,10
+ CONTROL "Low quality [P]",IDC_LOWQUALITY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,405,80,10
+ CONTROL "No specular [S]",IDC_NOSPECULAR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,417,80,10
+ CONTROL "Show skeleton [K]",IDC_SHOWSKELETON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,429,80,10
+ CONTROL "AutoRotate [A]",IDC_AUTOROTATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,357,80,10
+ CONTROL "Zoom/Rotate [Z]",IDC_ZOOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,369,80,10
+ CONTROL "Rotate lights [R]",IDC_LIGHTROTATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,381,80,10
+ CONTROL "Two lights [L]",IDC_3LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,393,80,10
+ CONTROL "Backface culling [C]",IDC_BFCULL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,405,80,10
+ CONTROL "No transparency [T]",IDC_NOAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,417,80,10
+ GROUPBOX "Statistics",IDC_STATIC,186,345,164,63
+ LTEXT "Vertices:",IDC_NUMVERTS,192,357,35,8
+ LTEXT "Nodes:",IDC_NUMNODES,192,369,35,8
+ LTEXT "Shaders:",IDC_NUMSHADERS,192,381,35,8
+ LTEXT "Time:",IDC_LOADTIME,192,393,35,8
+ EDITTEXT IDC_EVERT,227,357,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_ENODEWND,227,369,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_ESHADER,227,381,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_ELOAD,227,393,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Faces:",IDC_NUMFACES,272,357,35,8
+ LTEXT "Materials:",IDC_NUMMATS,272,369,35,8
+ LTEXT "Meshes:",IDC_NUMMESHES,272,381,35,8
+ LTEXT "FPS:",IDC_FPS,272,393,35,8
+ EDITTEXT IDC_EFACE,307,357,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_EMAT,307,369,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_EMESH,307,381,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_EFPS,307,393,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_VIEWMATRIX,192,412,72,44,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_VISIBLE | NOT WS_BORDER
+ GROUPBOX "Colors",IDC_STATIC,357,345,109,87
+ LTEXT "Primary:",IDC_STATIC,363,360,48,8
+ LTEXT "Secondary:",IDC_STATIC,363,378,54,8
+ LTEXT "Ambient:",IDC_STATIC,363,396,54,8
+ CONTROL "Button1",IDC_LCOLOR1,"Button",BS_OWNERDRAW | WS_TABSTOP,423,357,35,14
+ CONTROL "Button1",IDC_LCOLOR2,"Button",BS_OWNERDRAW | WS_TABSTOP,423,375,35,14
+ CONTROL "Button1",IDC_LCOLOR3,"Button",BS_OWNERDRAW | WS_TABSTOP,423,393,35,14
+ PUSHBUTTON "Reset",IDC_LRESET,423,411,35,14
+END
+
+IDD_LOADDIALOG DIALOGEX 0, 0, 143, 60
+STYLE DS_SETFONT | DS_CENTER | WS_POPUP | WS_BORDER | WS_SYSMENU
+FONT 12, "Tahoma", 400, 0, 0x0
+BEGIN
+ DEFPUSHBUTTON "Cancel",IDOK,104,41,33,13
+ CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,6,30,130,8
+ LTEXT "Loading ...\nMay the force be with you ...",IDC_STATIC,8,9,123,16
+END
+
+IDD_AVHELP DIALOGEX 0, 0, 481, 346
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "ASSIMP Viewer: Help"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,420,324,50,14
+ CONTROL "",IDC_RICHEDIT21,"RichEdit20A",ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL | WS_TABSTOP,19,18,462,294
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,312,490,1
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,16,490,1
+END
+
+IDD_LOGVIEW DIALOGEX 0, 0, 365, 182
+STYLE DS_SETFONT | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_TOPMOST | WS_EX_WINDOWEDGE
+CAPTION "AssimpView Log Output"
+FONT 8, "Courier New", 400, 0, 0x0
+BEGIN
+ CONTROL "",IDC_EDIT1,"RichEdit20A",ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | ES_NUMBER | WS_VSCROLL | WS_TABSTOP,3,4,358,174,WS_EX_STATICEDGE
+END
+
+IDD_DIALOGSMOOTH DIALOGEX 0, 0, 278, 141
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Set smooth limit "
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,213,94,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,161,94,50,14
+ EDITTEXT IDC_EDITSM,99,7,175,14,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "Angle limit (in degrees):",IDC_STATIC,13,10,76,8
+ LTEXT "The angle limit defines the maximum angle that may be between two adjacent face normals that they're smoothed together.",IDC_STATIC,13,31,253,19
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,113,278,1
+ LTEXT "Also used during import, but can be overridden by single model importers to match the original look of a model as close as possible. Examples includes 3DS, ASE and LWO, all of them relying on smoothing groups and their own angle limits. ",IDC_STATIC,13,51,254,33
+ LTEXT "NOTE: New settings don't take effect immediately, use 'Smooth Normals' or 'Reload' to update the model.",IDC_STATIC,14,118,254,22
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,90,277,1
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,1,700,0
+ PRODUCTVERSION 1,1,700,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040704b0"
+ BEGIN
+ VALUE "CompanyName", "assimp team"
+ VALUE "FileDescription", "ASSIMP Viewer Application"
+ VALUE "FileVersion", "1, 1, SVNRevision, 0"
+ VALUE "InternalName", "assimp_view"
+ VALUE "LegalCopyright", "Licensed under the LGPL"
+ VALUE "OriginalFilename", "assimpview32.exe"
+ VALUE "ProductName", "ASSIMP Viewer Application"
+ VALUE "ProductVersion", "1, 1, SVNRevision, 0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x407, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ TOPMARGIN, 1
+ BOTTOMMARGIN, 138
+ END
+
+ IDD_DIALOGMAIN, DIALOG
+ BEGIN
+ RIGHTMARGIN, 623
+ END
+
+ IDD_LOADDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ TOPMARGIN, 7
+ END
+
+ IDD_AVHELP, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 474
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 339
+ END
+
+ IDD_LOGVIEW, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 358
+ TOPMARGIN, 14
+ BOTTOMMARGIN, 175
+ END
+
+ IDD_DIALOGSMOOTH, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 271
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 134
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BITMAP1 BITMAP "banner.bmp"
+
+IDB_BANIM BITMAP "base_anim.bmp"
+
+IDB_BDISPLAY BITMAP "base_display.bmp"
+
+IDB_BINTER BITMAP "base_inter.bmp"
+
+IDB_BRENDERING BITMAP "base_rendering.bmp"
+
+IDB_BSTATS BITMAP "base_stats.bmp"
+
+IDB_BTX BITMAP "tx.bmp"
+
+IDB_BFX BITMAP "fx.bmp"
+
+IDB_BNODE BITMAP "n.bmp"
+
+IDB_BROOT BITMAP "root.bmp"
+
+IDB_BTXI BITMAP "txi.bmp"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU1 MENU
+BEGIN
+ POPUP "Viewer"
+ BEGIN
+ MENUITEM "Open Asset", ID_VIEWER_OPEN
+ MENUITEM "Close Asset", ID_VIEWER_CLOSEASSET
+ MENUITEM "Reload", ID_VIEWER_RELOAD
+ POPUP "Import settings"
+ BEGIN
+ MENUITEM "Calculate Tangent Space", ID_VIEWER_PP_CTS
+ MENUITEM "Compute Indexed Meshes", ID_VIEWER_PP_JIV
+ MENUITEM "Optimize Materials", ID_VIEWER_PP_RRM2
+ MENUITEM "Optimize Meshes", ID_VIEWER_PP_OM
+ MENUITEM "Optimize Scenegraph", ID_VIEWER_PP_OG
+ MENUITEM "Find Instanced Meshes", ID_VIEWER_PP_FIM
+ MENUITEM "Run Full Validation", ID_VIEWER_PP_VDS
+ MENUITEM "Pretransform Vertices", ID_VIEWER_PP_PTV
+ MENUITEM "VCache Optimization", ID_VIEWER_PP_ICL
+ MENUITEM "Fix Infacing Normals", ID_VIEWER_PP_FIN
+ MENUITEM "Find Degenerates", ID_VIEWER_PP_FD
+ MENUITEM "Find Invalid Data", ID_VIEWER_PP_FID
+ MENUITEM "Generate UV Coords", ID_VIEWER_PP_GUV
+ MENUITEM "Transform UV Coords", ID_VIEWER_PP_TUV
+ MENUITEM "Remove Lines and Points", ID_VIEWER_PP_RLINE_PNT, GRAYED
+ MENUITEM "Remove dummy bones (De-bone)", ID_VIEWER_PP_DB
+ MENUITEM SEPARATOR
+ MENUITEM "(required) Triangulate", ID_VIEWER_PP_JIV, GRAYED
+ MENUITEM "(required) Limit Bone Weights", ID_VIEWER_PP_JIV, GRAYED
+ MENUITEM "(required) Split Large Meshes", ID_VIEWER_PP_JIV, GRAYED
+ MENUITEM "(required) Sort by primitive type", ID_VIEWER_PP_JIV, GRAYED
+ MENUITEM "(required) Convert to Left-Handed", ID_VIEWER_PP_JIV, GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Reset to default", ID_IMPORTSETTINGS_RESETTODEFAULT
+ MENUITEM "Open Post-Process Short Reference", ID_IMPORTSETTINGS_OPENPOST
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Save Screenshot", ID_VIEWER_SAVESCREENSHOTTOFILE
+ MENUITEM "Reset view", ID_VIEWER_RESETVIEW
+ MENUITEM "Memory consumption", ID_VIEWER_MEMORYCONSUMATION
+ MENUITEM SEPARATOR
+ MENUITEM "Setup file associations", ID_VIEWER_H
+ MENUITEM SEPARATOR
+ MENUITEM "Recent files ", ID_VIEWER_RECENTFILES
+ MENUITEM "Clear history", ID_VIEWER_CLEARHISTORY
+ MENUITEM SEPARATOR
+ MENUITEM "Quit", ID_VIEWER_QUIT
+ END
+ POPUP "Tools"
+ BEGIN
+ MENUITEM "Log window", ID_TOOLS_LOGWINDOW
+ MENUITEM "Save log to file", ID_TOOLS_SAVELOGTOFILE
+ MENUITEM "Clear log", ID_TOOLS_CLEARLOG
+ MENUITEM SEPARATOR
+ MENUITEM "Original normals", ID_TOOLS_ORIGINALNORMALS, CHECKED
+ MENUITEM "Hard normals", ID_TOOLS_HARDNORMALS
+ MENUITEM "Smooth normals", ID_TOOLS_SMOOTHNORMALS
+ MENUITEM SEPARATOR
+ MENUITEM "Set angle limit ...", ID_TOOLS_SETANGLELIMIT
+ MENUITEM "Flip normals", ID_TOOLS_FLIPNORMALS
+ MENUITEM SEPARATOR
+ MENUITEM "Stereo view", ID_TOOLS_STEREOVIEW
+ END
+ POPUP "Background"
+ BEGIN
+ MENUITEM "Set color", ID_BACKGROUND_SETCOLOR
+ MENUITEM "Load skybox", ID_BACKGROUND_LOADSKYBOX
+ MENUITEM "Load texture", ID_BACKGROUND_LOADTEXTURE
+ MENUITEM SEPARATOR
+ MENUITEM "Clear", ID_BACKGROUND_CLEAR
+ END
+ MENUITEM "Export", 32878
+ POPUP "?"
+ BEGIN
+ POPUP "Feedback"
+ BEGIN
+ MENUITEM "Report bug", ID_REPORTBUG
+ MENUITEM "Feature request/discuss", ID_FR
+ END
+ MENUITEM "Help", ID__HELP
+ MENUITEM SEPARATOR
+ MENUITEM "About", ID__ABOUT
+ MENUITEM SEPARATOR
+ MENUITEM "Website", ID__WEBSITE
+ MENUITEM "SF.net Project Page", ID__WEBSITESF
+ END
+END
+
+IDR_TXPOPUP MENU
+BEGIN
+ POPUP "Hey"
+ BEGIN
+ MENUITEM "Replace texture", ID_HEY_REPLACE
+ MENUITEM "Export texture", ID_HEY_EXPORT
+ MENUITEM "Remove texture", ID_HEY_REMOVE
+ MENUITEM SEPARATOR
+ MENUITEM "Reset texture", ID_HEY_RESETTEXTURE
+ END
+ MENUITEM "This is not an easter egg", 0
+END
+
+IDR_MATPOPUP MENU
+BEGIN
+ POPUP "So long"
+ BEGIN
+ MENUITEM "Add diffuse texture", ID_SOLONG_ADDDIFFUSETEXTURE
+ MENUITEM "Add specular texture", ID_SOLONG_ADDSPECULARTEXTURE
+ MENUITEM "Add ambient texture", ID_SOLONG_ADDAMBIENTTEXTURE
+ MENUITEM "Add emissive texture", ID_SOLONG_ADDEMISSIVETEXTURE
+ MENUITEM "Add opacity texture", ID_SOLONG_ADDOPACITYTEXTURE
+ MENUITEM "Add normal/height texture", ID_SOLONG_ADDNORMAL
+ MENUITEM "Add shininess texture", ID_SOLONG_ADDSHININESSTEXTURE
+ MENUITEM SEPARATOR
+ MENUITEM "Set diffuse color", ID_SOLONG_CLEARDIFFUSECOLOR
+ MENUITEM "Set specular color", ID_SOLONG_CLEARSPECULARCOLOR
+ MENUITEM "Set ambient color", ID_SOLONG_CLEARAMBIENTCOLOR
+ MENUITEM "Set emissive color", ID_SOLONG_CLEAREMISSIVECOLOR
+ MENUITEM "Set transparency", ID_SOLONG_CLEARTRANSPARENCY
+ MENUITEM SEPARATOR
+ MENUITEM "Make default material", ID_SOLONG_MAKEDEFAULTMATERIAL
+ POPUP "Set shading mode"
+ BEGIN
+ MENUITEM "Gouraud", ID_SETSHADINGMODE_GOURAUD
+ MENUITEM "Phong (specular)", ID_SETSHADINGMODE_PHONG
+ END
+ END
+ MENUITEM "and thanks for all the fish", 0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXT
+//
+
+IDR_TEXT1 TEXT "text1.bin"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RCDATA
+//
+
+IDR_HUD RCDATA "HUD.png"
+
+IDR_HUDMASK RCDATA "HUDMask.png"
+
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/libs/assimp/tools/assimp_view/banner.bmp b/libs/assimp/tools/assimp_view/banner.bmp
new file mode 100644
index 0000000..419b97d
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/banner.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/banner_pure.bmp b/libs/assimp/tools/assimp_view/banner_pure.bmp
new file mode 100644
index 0000000..e274a14
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/banner_pure.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/base.PNG b/libs/assimp/tools/assimp_view/base.PNG
new file mode 100644
index 0000000..ed91063
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/base.PNG
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/base_anim.bmp b/libs/assimp/tools/assimp_view/base_anim.bmp
new file mode 100644
index 0000000..e65478c
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/base_anim.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/base_display.bmp b/libs/assimp/tools/assimp_view/base_display.bmp
new file mode 100644
index 0000000..f13410a
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/base_display.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/base_inter.bmp b/libs/assimp/tools/assimp_view/base_inter.bmp
new file mode 100644
index 0000000..0731369
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/base_inter.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/base_rendering.bmp b/libs/assimp/tools/assimp_view/base_rendering.bmp
new file mode 100644
index 0000000..bec8699
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/base_rendering.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/base_stats.bmp b/libs/assimp/tools/assimp_view/base_stats.bmp
new file mode 100644
index 0000000..130ce53
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/base_stats.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/fx.bmp b/libs/assimp/tools/assimp_view/fx.bmp
new file mode 100644
index 0000000..c001aae
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/fx.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/help.rtf b/libs/assimp/tools/assimp_view/help.rtf
new file mode 100644
index 0000000..3f0bb42
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/help.rtf
@@ -0,0 +1,418 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi0\deflang1031\deflangfe1031\themelang1031\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}
+{\f39\fbidi \fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}MS Reference Sans Serif;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f41\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f42\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f44\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f45\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f46\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f47\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f48\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f49\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f381\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f382\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}
+{\f384\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f385\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f388\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f431\fbidi \fswiss\fcharset238\fprq2 MS Reference Sans Serif CE;}
+{\f432\fbidi \fswiss\fcharset204\fprq2 MS Reference Sans Serif Cyr;}{\f434\fbidi \fswiss\fcharset161\fprq2 MS Reference Sans Serif Greek;}{\f435\fbidi \fswiss\fcharset162\fprq2 MS Reference Sans Serif Tur;}
+{\f438\fbidi \fswiss\fcharset186\fprq2 MS Reference Sans Serif Baltic;}{\f439\fbidi \fswiss\fcharset163\fprq2 MS Reference Sans Serif (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1031\langfe1031\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1031\langfenp1031
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \fs22\lang1031\langfe1031\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1031\langfenp1031
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid2432159\rsid3942873\rsid5053873\rsid5113869\rsid5338181\rsid6912689\rsid6976329\rsid7213193\rsid8068556\rsid9465848\rsid13463017}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0
+\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator Alexander Gessler}{\creatim\yr2008\mo5\dy13\hr12\min5}{\revtim\yr2008\mo7\dy8\hr13\min6}{\version11}{\edmins0}{\nofpages5}{\nofwords1505}{\nofchars7670}
+{\nofcharsws9157}{\vern32895}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1417\margr1417\margt1417\margb1134\gutter0\ltrsect
+\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120
+\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale91\viewzk1\rsidroot13463017 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang
+{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}
+{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9
+\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0
+\fs22\lang1031\langfe1031\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1031\langfenp1031 {\rtlch\fcs1 \ab\af39\afs32 \ltrch\fcs0 \b\f39\fs32\lang1033\langfe1031\langnp1033\insrsid5338181
+\par \hich\af39\dbch\af31505\loch\f39 ASSIMP Viewer Utility
+\par }{\rtlch\fcs1 \ab\af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Document version 1.0, April 2008
+\par }{\rtlch\fcs1 \ab\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 I.\tab
+Usage
+\par }\pard \ltrpar\qj \li340\ri850\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin850\lin340\itap0\pararsid5338181 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+The ASSIMP Viewer Utility is a small and fast stand-alone viewer utility which is us\hich\af39\dbch\af31505\loch\f39
+ing the ASSIMP library to import assets from files. It consists of a single executable file and has no external dependencies. It displays assets with even highly complex materials and bone animations correctly.
+\par \hich\af39\dbch\af31505\loch\f39 AssimpView allows you to modify the textures \hich\af39\dbch\af31505\loch\f39 and material properties sets of your models at runtime, }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid6976329 \hich\af39\dbch\af31505\loch\f39 easily}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+ and fast per Drag&Drop. Furthermore it can visualize normals, UV sets, bounding boxes ... It allows artists and engine }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39
+programmers}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 to work together with maximal efficiency and find the ideal mode\hich\af39\dbch\af31505\loch\f39
+l format for your internal workflow.
+\par }{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 System requirements}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+\hich\af39\dbch\af31505\loch\f39 :
+\par }\pard \ltrpar\qj \fi-360\li700\ri850\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin850\lin700\itap0\pararsid5338181 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 -\tab
+\hich\af39\dbch\af31505\loch\f39 A Direct3D 9.0c compliant video card with }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid6976329 \hich\af39\dbch\af31505\loch\f39 at least}{\rtlch\fcs1 \af39\afs20
+\ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 support for Shader Model 2.0.}{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 -\tab \hich\af39\dbch\af31505\loch\f39 Shader Model 3.0 cards are recommended. Shader Model 2.0 cards always render the lighting in low-quality and have
+\hich\af39\dbch\af31505\loch\f39 some limitations concerning complex materials.
+\par -\tab \hich\af39\dbch\af31505\loch\f39 Windows 2000 or higher. AssimpView should also run on older versions, with DirectX 9 installed, but this has never been tested. If you're a proud owner of such a version and AssimpView works for you, let u
+\hich\af39\dbch\af31505\loch\f39 s know.}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid8068556
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 II.\tab
+User interface
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 The viewer\hich\f39 \rquote
+\loch\f39 s user interface mainly consists of three components:
+\par }\pard \ltrpar\ql \fi340\li0\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+The menu bar provides access to the viewer\hich\f39 \rquote \loch\f39 s basic options.
+\par }\pard \ltrpar\ql \fi-360\li720\ri850\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin850\lin720\itap0\pararsid5338181 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 -\tab }{\rtlch\fcs1 \af39\afs20
+\ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ab\ai\af39\afs20 \ltrch\fcs0 \b\i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181
+\hich\af39\dbch\af31505\loch\f39 Viewer}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39
+: Items to load / unload assets, take screenshots and open the viewer\hich\f39 \rquote \loch\f39 s options dialog.
+\par }\pard \ltrpar\qj \fi-360\li720\ri1206\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1206\lin720\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 * \hich\af39\dbch\af31505\loch\f39 "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Open Asset}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+": Displays the file system dialog where you can choose a new asset to load. Note that you can also Drag&Drop models onto the viewer panel.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Close Asset}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Closes the current asset and releases all resources associated with it. No action if no\hich\af39\dbch\af31505\loch\f39 asset is loaded.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Screenshot}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+": Save a snapshot of the viewer to a file. The snapshot does only include the preview panel, the rest of the user interface is not visible. Saved screenshots have no watermarks. This is }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Open Source}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Software!
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Reset View}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 "\hich\af39\dbch\af31505\loch\f39 : Reset the viewing position and direction to the default settings. This is: Camera position at 0|0|0, looking at 0|0|1.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Memory consumption}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Display a box with approximated memory statistics. Note that the total memory consumption needn't be equal to \hich\af39\dbch\af31505\loch\f39
+the physical memory allocated to the process (as displayed by Windows }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Task Manager}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ). The memory consumption does only refer to the memory required for the asset itself, not for the rest of the viewer.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Setup file associations}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Associate all file format\hich\af39\dbch\af31505\loch\f39 s which can be read by ASSIMP with the viewer. If you double }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 click}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+ on such a file in Windows Explorer, it will be automatically opened with AssimpView.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Recent files}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Displays a popup menu with a list of recently opened assets. Simply click on one to r\hich\af39\dbch\af31505\loch\f39 eload it.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Clear history}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Clear the file history
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Quit}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": What do you think?
+\par }\pard \ltrpar\ql \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 - \tab }{\rtlch\fcs1
+\ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \hich\af39\dbch\af31505\loch\f39 "}{\rtlch\fcs1 \ab\ai\af39\afs20 \ltrch\fcs0 \b\i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181
+\hich\af39\dbch\af31505\loch\f39 Tools}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \hich\af39\dbch\af31505\loch\f39 "}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \hich\af39\dbch\af31505\loch\f39 : Additional utilities like stereo view, normal type.
+\par }\pard \ltrpar\qj \fi-360\li720\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin720\itap0\pararsid3942873 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39
+Log window}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Displays the output window of the logger. Warnings are displayed in orange/yel\hich\af39\dbch\af31505\loch\f39
+low, errors in red, debug messages in blue and status }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid7213193 \hich\af39\dbch\af31505\loch\f39 information}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39 messages}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 in green.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Save log to file}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Saves the contents of the log window to a file.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Clear log}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 " Clear the contents of the log window
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Original normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Specifies that the origin\hich\af39\dbch\af31505\loch\f39
+al normal set from the model file is used in the preview. Normally this is the best choice, as smoothing groups etc. are handled correctly, but there are many models out there which have invalid or corrupt normal sets. However, if a model has no normal se
+\hich\af39\dbch\af31505\loch\f39 t\hich\af39\dbch\af31505\loch\f39 , ASSIMP computes a smooth normal set for it. "Original normals" is in this case equivalent to "Smooth normals"
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Smooth normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Specifies that a smoothed, per-vertex, normal set is used in the preview window.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Hard normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Specifies that a hard, \hich\af39\dbch\af31505\loch\f39 per-face, normal set is used
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Flip normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": Flip all normal vectors
+\par }\pard \ltrpar\qj \fi-360\li720\ri850\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin850\lin720\itap0\pararsid5338181 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 -}{\rtlch\fcs1 \af39\afs20
+\ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \tab \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ab\ai\af39\afs20 \ltrch\fcs0 \b\i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181
+\hich\af39\dbch\af31505\loch\f39 Background}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 : Set the background color or use a texture (}{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid9465848\charrsid5338181 \hich\af39\dbch\af31505\loch\f39 cube maps}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5338181 \hich\af39\dbch\af31505\loch\f39 are supported as skyboxes) as background image for the viewer.
+\par }\pard \ltrpar\qj \fi-360\li720\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin720\itap0\pararsid3942873 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Set color}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39
+": Displays a color picker where you can choose a new background color for the viewer.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Load skybox}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Opens a file system dialog where you can select a skybox as background image. Accepted file formats are: *.dds, *.hdr.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Load texture}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Opens a \hich\af39\dbch\af31505\loch\f39
+file system dialog where you can select a texture as background image. If the format of the texture doesn't fit to the proportions of the preview window, the texture will be stretched. }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid3942873
+\par }\pard \ltrpar\qj \fi-12\li720\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin720\itap0\pararsid3942873 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Accepted file formats are: *.jpg;*.png;*.tif;*.tga;*.dds;*.hdr;*.ppm;*\hich\af39\dbch\af31505\loch\f39 .bmp
+\par }\pard \ltrpar\ql \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 - "}{\rtlch\fcs1
+\ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ?}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 ": }{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Help and feedback}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+
+\par \tab }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Feedback}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 ": Opens a popup menu with two options:
+\par }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{
+\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Report bug}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Report a bug in AssimpView or in Assimp
+\par }\pard \ltrpar\qj \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Feature request}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Tell us what}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39 you'd like us to support. Any }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 exotic file formats?
+\par }\pard \ltrpar\qj \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 \hich\f39
+The side panel \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Statistics}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+\loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 di\hich\af39\dbch\af31505\loch\f39 splays rendering statistics. The meanings of the fields change if you change between normal}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 , node a\hich\af39\dbch\af31505\loch\f39 nd texture or }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+\hich\af39\dbch\af31505\loch\f39 material}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 view}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 mode.
+\par }\pard \ltrpar\qj \li340\ri1474\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1474\lin340\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+Normal view mode:
+\par }\pard \ltrpar\qj \li340\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin340\itap0\pararsid5053873 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 Verts}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of unique vertices in the asset
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Faces}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 ": Numb}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39
+er of faces (= triangles) in the asset
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Nodes}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of nodes in the scenegraph, including the root node
+\par }\pard \ltrpar\qj \fi-368\li708\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin708\itap0\pararsid5053873 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \tab
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Mats:}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 " Number of different materials f}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159
+\hich\af39\dbch\af31505\loch\f39 ound in the mesh. Most loaders }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 remove unreferenced materials.
+\par }\pard \ltrpar\qj \li700\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin700\itap0\pararsid5053873 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Mesh}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 sub meshes}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 . Each mesh h}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 as only one material \tab assigned, so }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 this number\hich\af39\dbch\af31505\loch\f39 is in most cas}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329 \hich\af39\dbch\af31505\loch\f39 es equal to or higher than the }{
+\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 number of materials.
+\par \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Shd}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of unique shaders created}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873
+\hich\af39\dbch\af31505\loch\f39 for this asset. If AssimpView }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39
+detects that two materials can be rendered using }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 the same }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Shader}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 code, but with }{\rtlch\fcs1
+\af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 different}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 parameterizations}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 , it do}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 es
+\hich\af39\dbch\af31505\loch\f39 n't create the }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Shader}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 twice. }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39
+Most engines do so, too. }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329 \hich\af39\dbch\af31505\loch\f39 This allows you to \hich\af39\dbch\af31505\loch\f39 approximate\hich\af39\dbch\af31505\loch\f39 the
+\hich\af39\dbch\af31505\loch\f39 rendering const for the asset.}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873
+\par \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Time}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Time required for loading, in seco}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873
+\hich\af39\dbch\af31505\loch\f39 nds. This time is the raw time }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 the process spent in Assimp loading the mod}{
+\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 el itself, it does not include }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 texture loading, }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 Shader}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5113869\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 compilation...}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181
+\par }\pard \ltrpar\qj \li340\ri1474\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1474\lin340\itap0\pararsid6976329 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid6976329 \hich\af39\dbch\af31505\loch\f39
+Texture view mode\hich\af39\dbch\af31505\loch\f39 :
+\par }\pard \ltrpar\qj \li340\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin340\itap0\pararsid6976329 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid6976329 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39
+Width}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159
+\hich\af39\dbch\af31505\loch\f39 Width of the texture, in pixels}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329\charrsid5053873
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 Height}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329 \hich\af39\dbch\af31505\loch\f39 ":}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39
+Height of the texture in pixels
+\par }\pard \ltrpar\qj \li708\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin708\itap0\pararsid2432159 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 Format}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39
+Format of the texture. This will normally be ARGB8. Other possible \hich\af39\dbch\af31505\loch\f39 valu\hich\af39\dbch\af31505\loch\f39 e\hich\af39\dbch\af31505\loch\f39 s are:\hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39 RRG565
+\hich\af39\dbch\af31505\loch\f39 , ARGB16f\hich\af39\dbch\af31505\loch\f39 , ARGB32F. Embedded textures are always converted \hich\af39\dbch\af31505\loch\f39 to ARGB8 format, even if they\loch\af39\dbch\af31505\hich\f39 \rquote
+\hich\af39\dbch\af31505\loch\f39 re stored\hich\af39\dbch\af31505\loch\f39 in the file\hich\af39\dbch\af31505\loch\f39 with a higher color\hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39 depth.}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329
+\par }\pard \ltrpar\qj \fi368\li340\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin340\itap0\pararsid2432159 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 UV}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39
+UV channel used by the texture. Normally this is the first channel.}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159\charrsid5053873
+\par }\pard \ltrpar\qj \li340\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin340\itap0\pararsid2432159 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159\charrsid5053873 \tab
+\hich\af39\dbch\af31505\loch\f39 * }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 MIPs}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 ":
+\hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39 Number of MIP map levels created for the textur\hich\af39\dbch\af31505\loch\f39 e
+\par }\pard \ltrpar\qj \li708\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin708\itap0\pararsid2432159 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 * }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 Blend}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 ":
+\hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39 Strength of the texture. The \hich\af39\dbch\af31505\loch\f39 color value obtained from\hich\af39\dbch\af31505\loch\f39 the texture is \hich\af39\dbch\af31505\loch\f39 multiplied
+\hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39 with this factor to calculate the final color.
+\par }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159
+\hich\af39\dbch\af31505\loch\f39 Op}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid2432159 \hich\af39\dbch\af31505\loch\f39 Blend operation used to combine this texture with the corresponding \hich\af39\dbch\af31505\loch\f39 material color \hich\af39\dbch\af31505\loch\f39 (
+\hich\af39\dbch\af31505\loch\f39 or the previous texture\hich\af39\dbch\af31505\loch\f39 ).
+\par }\pard \ltrpar\qj \li340\ri1474\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1474\lin340\itap0\pararsid6976329 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid6976329 \hich\af39\dbch\af31505\loch\f39
+Always visible\hich\af39\dbch\af31505\loch\f39 :}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid6976329\charrsid6976329
+\par }\pard \ltrpar\qj \li700\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin700\itap0\pararsid9465848 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 FPS}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Cur\hich\af39\dbch\af31505\loch\f39 rent frame rate, in frames per se}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 cond. Note that this number }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid13463017\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 is }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 not really exact.}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 It is only an approximation to the real frame rate. The maximum frame rate will never be reached since there is a 10 ms blocker included (to work around good }{
+\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6976329 \hich\af39\dbch\af31505\loch\f39 our }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873
+\hich\af39\dbch\af31505\loch\f39 old AMD timing b\hich\af39\dbch\af31505\loch\f39 ug)}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5338181\charrsid9465848
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 \hich\f39 The \'93}{
+\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Rendering}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+\loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 panel provides rendering-related options, such as wireframe/normal visualization.}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid9465848
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 \hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+\hich\af39\dbch\af31505\loch\f39 Interaction}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 bundles all input related options.
+\par \hich\af39\dbch\af31505\loch\f39 The main \hich\af39\dbch\af31505\loch\f39 component is the large viewer panel where the assets are displayed. Status messages (e.g. if a texture could not be loaded)}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39 are displayed in the upper-right}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 edge.
+}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39 Yellow messages are simple information messages, red messages are error messages. Green messa\hich\af39\dbch\af31505\loch\f39
+ges, however, are coming from heart ;-)}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+\par }{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 III.\tab Input
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 \hich\f39
+The input mode depends on the selected input behavior. If \'84}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Zoom/Rotate}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 is }{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 NOT}{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 selected the following scheme applies:
+\par }\pard \ltrpar\ql \fi368\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1
+\ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Arrow up}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39
+\rquote \loch\f39 \tab = Move forwards
+\par \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Arrow left\hich\f39 \rquote }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 \tab = Move to the left
+\par \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Arrow down}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \rquote \loch\f39 \tab \hich\af39\dbch\af31505\loch\f39 = Move backwards
+\par \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Arrow right}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \rquote \loch\f39 \tab = Move to the right
+\par }\pard \ltrpar\ql \fi340\li0\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+The mouse specifies the view direction. This is the typical FPS input behavior.
+\par }{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 \hich\f39 Otherwise, if \'84}{\rtlch\fcs1 \ab\ai\af39\afs20 \ltrch\fcs0
+\b\i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Zoom/Rotate}{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39
+ is enabled:
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1
+\ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Left Mouse Button}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181
+\loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse to rotate the asset around its\hich\af39\dbch\af31505\loch\f39
+ local axes. Inside the yellow circle: x/y-axis, outside: Z-axis. To rotate around one axis only use the axis snap-ins (yellow squares with a cross inside).
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Right Mouse Button}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse to rotate the light source(s) around their x\hich\af39\dbch\af31505\loch\f39 and y axes.
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Middle Mouse Button}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse from the left to the right or the other way round to increase/decrease the intensity of the light source(s)
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Right }{\rtlch\fcs1 \ab\ai\af39\afs20 \ltrch\fcs0
+\b\i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 AND}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Left Mouse Button}{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse to rotate skybo\hich\af39\dbch\af31505\loch\f39
+x (if existing) around the global x/y axes.
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Mouse wheel}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Zoom in/out
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 IV.\tab }{\rtlch\fcs1
+\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Rendering
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+Enabling MultiSampling improves rendering quality. MultiSampling is activated by default. The highest quality MultiSampling mode supported by the video card is used.
+\par \hich\af39\dbch\af31505\loch\f39 Mult\hich\af39\dbch\af31505\loch\f39 iSampling is especially useful to remove line artifacts in wireframe/normals mode. Note that the transition between normal and multisampled rendering may take a few seconds.
+\par \hich\af39\dbch\af31505\loch\f39 \hich\f39 Rendering is done via Direct3D\'99\loch\f39 \hich\f39 9.0c. Note that the \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39
+Low-quality lighting}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 -Option \hich\af39\dbch\af31505\loch\f39
+is not available for PS 2.0 cards. Lighting on PS 2.0 cards is always low quality.
+\par
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 V.\tab }{\rtlch\fcs1
+\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181 \hich\af39\dbch\af31505\loch\f39 Known issues
+\par }\pard \ltrpar\ql \fi-360\li700\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin700\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 -\tab \hich\af39\dbch\af31505\loch\f39
+If a loading process is canceled it is not guaranteed that further loading processes will succeed. ASSIMP Viewer might even crash in this case. }{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 -\tab \hich\af39\dbch\af31505\loch\f39 Some v\hich\af39\dbch\af31505\loch\f39
+ery complex materials involving real time reflection/refraction are not displayed properly.}{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid5338181 -\tab \hich\af39\dbch\af31505\loch\f39 When rendering non-opaque objects some triangle artifacts might occur.}{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0
+\f39\fs24\lang1033\langfe1031\langnp1033\insrsid5338181
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f000000000000000000000000b080
+05aceae0c801feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file
diff --git a/libs/assimp/tools/assimp_view/n.bmp b/libs/assimp/tools/assimp_view/n.bmp
new file mode 100644
index 0000000..e3afa63
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/n.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/resource.h b/libs/assimp/tools/assimp_view/resource.h
new file mode 100644
index 0000000..754eb69
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/resource.h
@@ -0,0 +1,235 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by assimp_view.rc
+//
+#define IDC_MYICON 2
+#define IDD_ASSIMP_VIEW_DIALOG 102
+#define IDD_ABOUTBOX 103
+#define IDI_ASSIMP_VIEW 107
+#define IDI_SMALL 108
+#define IDR_MAINFRAME 128
+#define IDD_DIALOGMAIN 129
+#define IDB_BITMAP1 130
+#define IDR_MENU1 131
+#define IDD_LOADDIALOG 132
+#define IDB_BITMAP2 134
+#define IDD_AVHELP 135
+#define IDR_TEXT1 138
+#define IDR_MAX 140
+#define IDB_MAXCIRCLEMASK 141
+#define IDB_MAXCIRCLE 142
+#define IDR_HUD 143
+#define IDR_HUDMASK 144
+#define IDB_BANIM 145
+#define IDB_BITMAP4 146
+#define IDB_BDISPLAY 146
+#define IDB_BITMAP5 147
+#define IDB_BINTER 147
+#define IDB_BITMAP6 148
+#define IDB_BRENDERING 148
+#define IDB_BITMAP7 149
+#define IDB_BSTATS 149
+#define IDB_BTX 150
+#define IDB_BITMAP8 151
+#define IDB_BFX 151
+#define IDB_BITMAP9 152
+#define IDB_BNODE 152
+#define IDB_BITMAP10 153
+#define IDB_BROOT 153
+#define IDD_LOGVIEW 154
+#define IDB_BTXI 155
+#define IDR_TXPOPUP 156
+#define IDR_MATPOPUP 157
+#define IDD_DIALOGSMOOTH 159
+#define SVNRevision 700
+#define IDC_CHECK1 1000
+#define IDC_TOGGLEMS 1000
+#define IDC_CHECK2 1001
+#define IDC_TOGGLEWIRE 1001
+#define IDC_CHECK3 1002
+#define IDC_TOGGLEMAT 1002
+#define IDC_CHECK4 1003
+#define IDC_TOGGLENORMALS 1003
+#define IDC_CHECK5 1004
+#define IDC_AUTOROTATE 1004
+#define IDC_RT 1006
+#define IDC_NUMVERTS 1007
+#define IDC_NUMFACES 1008
+#define IDC_NUMMATS 1009
+#define IDC_FPS 1010
+#define IDC_EFPS 1011
+#define IDC_EMAT 1012
+#define IDC_EFACE 1013
+#define IDC_EVERT 1014
+#define IDC_CHECK6 1015
+#define IDC_LIGHTROTATE 1015
+#define IDC_3LIGHTS 1016
+#define IDC_PROGRESS 1016
+#define IDC_LOADTIME 1017
+#define IDC_ELOAD 1018
+#define IDC_CHECK7 1019
+#define IDC_ZOOM 1019
+#define IDC_CHECK8 1020
+#define IDC_LOWQUALITY 1020
+#define IDC_NUMMATS2 1021
+#define IDC_NUMSHADERS 1021
+#define IDC_ESHADER 1022
+#define IDC_RICHEDIT21 1023
+#define IDC_EMESH 1023
+#define IDC_CHECK9 1024
+#define IDC_NOSPECULAR 1024
+#define IDC_PLAYANIM 1025
+#define IDC_3LIGHTS2 1025
+#define IDC_NOAB 1025
+#define IDC_SPEED 1026
+#define IDC_COMBO1 1027
+#define IDC_PINORDER 1028
+#define IDC_NOSPECULAR2 1028
+#define IDC_SSPEED 1029
+#define IDC_SANIM 1030
+#define IDC_SANIMGB 1031
+#define IDC_ENODE 1031
+#define IDC_ESHADER2 1032
+#define IDC_ETEX 1032
+#define IDC_TREE1 1033
+#define IDC_EDIT1 1034
+#define IDC_BLUBB 1037
+#define IDC_BLABLA 1038
+#define IDC_NUMNODES 1038
+#define IDC_LCOLOR1 1041
+#define IDC_LCOLOR2 1042
+#define IDC_ENODEWND 1043
+#define IDC_LCOLOR3 1044
+#define IDC_LRESET 1046
+#define IDC_NUMMESHES 1047
+#define IDC_VIEWMAT 1048
+#define IDC_VIEWMATRIX 1048
+#define IDC_SLIDERANIM 1052
+#define IDC_PLAY 1053
+#define IDC_SHOWSKELETON 1054
+#define IDC_BFCULL 1055
+#define IDC_EDITSM 1056
+#define ID_VIEWER_OPEN 32771
+#define ID_VIEWER_CLOSETHIS 32772
+#define ID_VIEWER_CLOSEASSET 32773
+#define ID_VIEWER_QUIT 32774
+#define ID__ABOUT 32775
+#define ID__HELP 32776
+#define ID_VIEWER_SAVESCREENSHOTTOFILE 32777
+#define ID_VIEWER_RESETVIEW 32778
+#define ID_BACKGROUND_LOADTEXTURE 32779
+#define ID_BACKGROUND_CLEAR 32780
+#define ID_BACKGROUND_SETCOLOR 32781
+#define ID_Menu 32782
+#define ID_BACKGROUND_LOADSKYBOX 32783
+#define ID_VIEWER_H 32784
+#define ID_TOOLS_LOGWINDOW 32785
+#define ID_TOOLS_SAVELOGTOFILE 32786
+#define ID_TOOLS_CLEARLOG 32787
+#define ID_VIEWER_RECENTFILES 32788
+#define ID_VIEWER_MEMORYCONSUMATION 32789
+#define ID_VIEWER_CLEARHISTORY 32790
+#define ID_TOOLS_ORIGINALNORMALS 32791
+#define ID_TOOLS_SMOOTHNORMALS 32792
+#define ID_TOOLS_HARDNORMALS 32793
+#define ID_TOOLS_FLIPNORMALS 32794
+#define ID__S 32795
+#define ID__FEEDBACK 32796
+#define ID_FEEDBACK_GH 32797
+#define ID_FEEDBACK_FEATUREREQUEST 32798
+#define ID_FEEDBACK_DONATE 32799
+#define ID_ANIMATION_PLAYALLINORDER 32800
+#define ID_TOOLS_STEREOVIEW 32801
+#define ID_EGNEKLGEG_EGEG 32802
+#define ID_HEY_REPLACE 32803
+#define ID_HEY_EXPORT 32804
+#define ID_HEY_REMOVE 32805
+#define ID_SOLONG_ADDDIFFUSETEXTURE 32806
+#define ID_SOLONG_ADDSPECULARTEXTURE 32807
+#define ID_SOLONG_ADDAMBIENTTEXTURE 32808
+#define ID_SOLONG_ADDEMISSIVETEXTURE 32809
+#define ID_SOLONG_ADDOPACITYTEXTURE 32810
+#define ID_SOLONG_ADDNORMAL 32811
+#define ID_SOLONG_ADDSHININESSTEXTURE 32812
+#define ID_SOLONG_CLEARDIFFUSECOLOR 32813
+#define ID_SOLONG_CLEARSPECULARCOLOR 32814
+#define ID_SOLONG_CLEARAMBIENTCOLOR 32815
+#define ID_SOLONG_CLEAREMISSIVECOLOR 32816
+#define ID_SOLONG_CLEARTRANSPARENCY 32817
+#define ID_SOLONG_MAKEDEFAULTMATERIAL 32818
+#define ID_HEY_RESETTEXTURE 32819
+#define ID_SOLONG_SETSHADINGMODE 32820
+#define ID_SETSHADINGMODE_GOURAUD 32821
+#define ID_SETSHADINGMODE_PHONG 32822
+#define ID_OPTIMIZE_OPTIMIZEACMR 32823
+#define ID_OPTIMIZE_OPTIMIZEOVERDRAW 32824
+#define ID_OPTIMIZE_OPTIMIZEBOTH 32825
+#define ID_VERTEXCACHELOCALITY_FINDCURRENT 32826
+#define ID_VERTEXCACHELOCALITY_OPTIMIZE 32827
+#define ID_VERTEXCACHELOCALITY_FINDBEST 32828
+#define ID_OPTIMIZE_SCENEGRAPH 32829
+#define ID_SCENEGRAPH_SMALLESTPOSSIBLEGRAPH 32830
+#define ID_SMOOTHNORMALS_5 32831
+#define ID_SMOOTHNORMALS_6 32832
+#define ID_SMOOTHNORMALS_MAXANGLE60 32833
+#define ID_SMOOTHNORMALS_MAXANGLE90 32834
+#define ID_SMOOTHNORMALS_MAXANGLE120 32835
+#define ID_SMOOTHNORMALS_NOLIMIT 32836
+#define ID_SMOOTHNORMALS_30 32837
+#define ID_SMOOTHNORMALS_40 32838
+#define ID_SMOOTHNORMALS_60 32839
+#define ID_SMOOTHNORMALS_90 32840
+#define ID_SMOOTHNORMALS_120 32841
+#define ID_Menu32842 32842
+#define ID_SMOOTHANGLE_30 32843
+#define ID_SMOOTHANGLE_40 32844
+#define ID_SMOOTHANGLE_50 32845
+#define ID_SMOOTHANGLE_60 32846
+#define ID_SMOOTHANGLE_70 32847
+#define ID_SMOOTHANGLE_90 32848
+#define ID_SMOOTHANGLE_120 32849
+#define ID_SMOOTHANGLE_NONE 32850
+#define ID_TOOLS_SETANGLELIMIT 32851
+#define ID_VIEWER_PP_JIV 32852
+#define ID_VIEWER_PP_RRM 32852
+#define ID_VIEWER_PP_OM 32853
+#define ID_VIEWER_PP_OG 32854
+#define ID_VIEWER_PP_FIM 32855
+#define ID_VIEWER_PP_VDS 32856
+#define ID_VIEWER_PP_PTV 32857
+#define ID_VIEWER_PP_ICL 32858
+#define ID_VIEWER_PP_FIN 32859
+#define ID_VIEWER_PP_FD 32860
+#define ID_VIEWER_PP_FID 32861
+#define ID_VIEWER_PP_GUV 32862
+#define ID_VIEWER_PP_TUV 32863
+#define ID_VIEWER_PP_RLINE_PNT 32864
+#define ID_REPORTBUG 32865
+#define ID_FR 32866
+#define ID__WEBSITE 32867
+#define ID__SF 32868
+#define ID__ 32869
+#define ID__WEBSITESF 32870
+#define ID_IMPORTSETTINGS_CALCULATETANGENTSPACE 32871
+#define ID_VIEWER_CTS 32872
+#define ID_VIEWER_PP_CTS 32873
+#define ID_VIEWER_RELOAD 32874
+#define ID_VIEWER_PP_RRM2 32875
+#define ID_IMPORTSETTINGS_RESETTODEFAULT 32876
+#define ID_IMPORTSETTINGS_OPENPOST 32877
+#define ID_EXPORT 32878
+#define ID_IMPORTSETTINGS_REMOVEDUMMYBONES 32879
+#define ID_VIEWER_PP_DB 32880
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 160
+#define _APS_NEXT_COMMAND_VALUE 32881
+#define _APS_NEXT_CONTROL_VALUE 1059
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/libs/assimp/tools/assimp_view/root.bmp b/libs/assimp/tools/assimp_view/root.bmp
new file mode 100644
index 0000000..b45baeb
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/root.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/stdafx.cpp b/libs/assimp/tools/assimp_view/stdafx.cpp
new file mode 100644
index 0000000..bbbb7e0
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : Quelldatei, die nur die Standard-Includes einbindet.
+// assimp_view.pch ist der vorkompilierte Header.
+// stdafx.obj enthält die vorkompilierten Typinformationen.
+
+#include "stdafx.h"
+
+// TODO: Auf zusätzliche Header verweisen, die in STDAFX.H
+// und nicht in dieser Datei erforderlich sind.
diff --git a/libs/assimp/tools/assimp_view/stdafx.h b/libs/assimp/tools/assimp_view/stdafx.h
new file mode 100644
index 0000000..d3f4692
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/stdafx.h
@@ -0,0 +1,73 @@
+// stdafx.h : Includedatei für Standardsystem-Includedateien
+// oder häufig verwendete projektspezifische Includedateien,
+// die nur in unregelmäßigen Abständen geändert werden.
+//
+
+#pragma once
+
+// Ändern Sie folgende Definitionen für Plattformen, die älter als die unten angegebenen sind.
+// In MSDN finden Sie die neuesten Informationen über die entsprechenden Werte für die unterschiedlichen Plattformen.
+#ifndef WINVER // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu.
+# define WINVER 0x0501 // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows.
+#endif
+
+#ifndef _WIN32_WINNT // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu.
+# define _WIN32_WINNT 0x0501 // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows.
+#endif
+
+#ifndef _WIN32_WINDOWS // Lassen Sie die Verwendung spezifischer Features von Windows 98 oder später zu.
+# define _WIN32_WINDOWS 0x0410 // Ändern Sie dies in den geeigneten Wert für Windows Me oder höher.
+#endif
+
+#ifndef _WIN32_IE // Lassen Sie die Verwendung spezifischer Features von IE 6.0 oder später zu.
+#define _WIN32_IE 0x0600 // Ändern Sie dies in den geeigneten Wert für andere Versionen von IE.
+#endif
+
+// Windows-Headerdateien:
+#include <windows.h>
+
+// C RunTime-Headerdateien
+#include <assert.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <time.h>
+
+// D3D9 includes
+
+#if (defined _DEBUG)
+# define D3D_DEBUG_INFO
+#endif
+
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <d3dx9mesh.h>
+
+// ShellExecute()
+#include <shellapi.h>
+#include <commctrl.h>
+
+// GetOpenFileName()
+#include <commdlg.h>
+#include <algorithm>
+#include <mmsystem.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <list>
+#include <vector>
+
+#if defined _MSC_VER
+// Windows CommonControls 6.0 Manifest Extensions
+# if defined _M_IX86
+# pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
+# elif defined _M_IA64
+# pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
+# elif defined _M_X64
+# pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
+# else
+# pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
+# endif
+#endif
diff --git a/libs/assimp/tools/assimp_view/test.xcf b/libs/assimp/tools/assimp_view/test.xcf
new file mode 100644
index 0000000..9710dfe
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/test.xcf
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/text1.bin b/libs/assimp/tools/assimp_view/text1.bin
new file mode 100644
index 0000000..0116460
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/text1.bin
@@ -0,0 +1,373 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1031\deflangfe1031\themelang1031\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}
+{\f39\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}MS Reference Sans Serif;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f40\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f41\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f43\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f44\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f45\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f46\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f47\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f48\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f430\fbidi \fswiss\fcharset238\fprq2 MS Reference Sans Serif CE;}
+{\f431\fbidi \fswiss\fcharset204\fprq2 MS Reference Sans Serif Cyr;}{\f433\fbidi \fswiss\fcharset161\fprq2 MS Reference Sans Serif Greek;}{\f434\fbidi \fswiss\fcharset162\fprq2 MS Reference Sans Serif Tur;}
+{\f437\fbidi \fswiss\fcharset186\fprq2 MS Reference Sans Serif Baltic;}{\f438\fbidi \fswiss\fcharset163\fprq2 MS Reference Sans Serif (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1031\langfe1031\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1031\langfenp1031
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1031\langfe1031\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1031\langfenp1031
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid3942873\rsid5053873\rsid6912689\rsid7213193\rsid8068556\rsid9465848\rsid13463017}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1
+\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator Alexander Gessler}{\creatim\yr2008\mo5\dy13\hr12\min5}{\revtim\yr2008\mo5\dy13\hr12\min20}{\version7}{\edmins0}{\nofpages4}{\nofwords1365}{\nofchars6975}{\nofcharsws8324}{\vern32893}}
+{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1417\margr1417\margt1417\margb1134\gutter0\ltrsect
+\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120
+\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale91\viewzk1\rsidroot13463017 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang
+{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}
+{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9
+\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0
+\fs22\lang1031\langfe1031\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1031\langfenp1031 {\rtlch\fcs1 \ab\af39\afs32 \ltrch\fcs0 \b\f39\fs32\lang1033\langfe1031\langnp1033\insrsid8068556
+\par \hich\af39\dbch\af31505\loch\f39 ASSIMP Viewer Utility
+\par }{\rtlch\fcs1 \ab\af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Document version 1.0, April 2008
+\par }{\rtlch\fcs1 \ab\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 I.\tab
+\hich\af39\dbch\af31505\loch\f39 Usage\hich\af39\dbch\af31505\loch\f39
+\par }\pard \ltrpar\qj \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+The ASSIMP Viewer Utility is a small and fast stand-alone viewer utility which is us\hich\af39\dbch\af31505\loch\f39
+ing the ASSIMP library to import assets from files. It consists of a single executable file and has no external dependencies. It displays assets with even highly complex materials and bone animations correctly.
+\par \hich\af39\dbch\af31505\loch\f39 AssimpView allows you to modify the textures \hich\af39\dbch\af31505\loch\f39
+and material properties sets of your models at runtime, easy and fast per Drag&Drop. Furthermore it can visualize normals, UV sets, bounding boxes ... It allows artists and engine }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 programmers}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+ to work together with maximal efficiency and find the ideal mod\hich\af39\dbch\af31505\loch\f39 el format for your internal workflow.
+\par }{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 System requirements}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\hich\af39\dbch\af31505\loch\f39 :
+\par }\pard \ltrpar\qj \fi-360\li700\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin700\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab \hich\af39\dbch\af31505\loch\f39
+A Direct3D 9.0c compliant video card with at least support for Shader Model 2.0.}{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab \hich\af39\dbch\af31505\loch\f39 Shader Model 3.0 cards are recommended. Shader Model 2.0 cards always render the lighting in low-quality and hav
+\hich\af39\dbch\af31505\loch\f39 e some limitations concerning complex materials.}{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }\pard \ltrpar\qj \fi-360\li700\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin700\itap0\pararsid8068556 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab \hich\af39\dbch\af31505\loch\f39
+Windows 2000 or higher. AssimpView should also run on older versions, with DirectX 9 installed, but this has never been tested. If you're a proud owner of such a version and AssimpView works for you, let u\hich\af39\dbch\af31505\loch\f39 s know.}{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid8068556
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 II.\tab
+User interface
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 The viewer\hich\f39 \rquote
+\loch\f39 s user interface mainly consists of three components:
+\par }\pard \ltrpar\ql \fi340\li0\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+The menu bar provides access to the viewer\hich\f39 \rquote \loch\f39 s basic options.
+\par }\pard \ltrpar\ql \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab }{\rtlch\fcs1 \af39 \ltrch\fcs0
+\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ab\ai\af39 \ltrch\fcs0 \b\i\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Viewer}
+{\rtlch\fcs1 \af39 \ltrch\fcs0 \f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 : Items to load / unload assets, take screenshots and open the viewer\hich\f39 \rquote \loch\f39
+s options dialog.}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }\pard \ltrpar\qj \fi-360\li720\ri1206\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1206\lin720\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 * \hich\af39\dbch\af31505\loch\f39 "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Open Asset}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+": Displays the file system dialog where you can choose a new asset to load. Note that you can also Drag&Drop models onto the viewer panel.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Close Asset}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Closes the current asset and releases all resources associated with it. No action if no\hich\af39\dbch\af31505\loch\f39 asset is loaded.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Screenshot}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+": Save a snapshot of the viewer to a file. The snapshot does only include the preview panel, the rest of the user interface is not visible. Saved screenshots have no watermarks. This is }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Open Source}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Software!
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Reset View}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Reset the viewing position and direction to the default settings. This is: Camera position at 0|0|0, looking at 0|0|1.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Memory consumption}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Display a box with approximated memory statistics. Note that the total memory consumption needn'\hich\af39\dbch\af31505\loch\f39
+t be equal to the physical memory allocated to the process (as displayed by Windows }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Task Manager}{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ). The memory consumption does only refer to the memory required for the asset itself, not for the rest of the viewer.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Setup file associations}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Associate al\hich\af39\dbch\af31505\loch\f39 l file formats which can be read by ASSIMP with the viewer. If you double }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 click}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+ on such a file in Windows Explorer, it will be automatically opened with AssimpView.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Recent files}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Displays a popup menu with a list of recently opened assets. Simply cli\hich\af39\dbch\af31505\loch\f39 ck on one to reload it.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Clear history}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Clear the file history
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Quit}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": What do you think?
+\par }\pard \ltrpar\ql \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 - \tab }{\rtlch\fcs1
+\ai\af39 \ltrch\fcs0 \i\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 "}{\rtlch\fcs1 \ab\ai\af39 \ltrch\fcs0 \b\i\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Tools}{\rtlch\fcs1 \ai\af39 \ltrch\fcs0 \i\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 "}{\rtlch\fcs1 \af39 \ltrch\fcs0
+\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 : Additional utilities like stereo view, normal type.
+\par }\pard \ltrpar\qj \fi-360\li720\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin720\itap0\pararsid3942873 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39
+Log window}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Displays the output window of the logger. Warnings are displayed in orange/yel\hich\af39\dbch\af31505\loch\f39
+low, errors in red, debug messages in blue and status }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid7213193 \hich\af39\dbch\af31505\loch\f39 information}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39 messages}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 in green.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Save log to file}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Saves the contents of the log window to a file.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Clear log}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 " Clear the contents of the log window
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Original normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Specifies that the original norma\hich\af39\dbch\af31505\loch\f39
+l set from the model file is used in the preview. Normally this is the best choice, as smoothing groups etc. are handled correctly, but there are many models out there which have invalid or corrupt normal sets. However, if a model has no normal set, ASSIM
+\hich\af39\dbch\af31505\loch\f39 P\hich\af39\dbch\af31505\loch\f39 computes a smooth normal set for it. "Original normals" is in this case equivalent to "Smooth normals"
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Smooth normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Specifies that a smoothed, per-vertex, normal set is used in the preview window.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Hard normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Specifies that a hard, per-face\hich\af39\dbch\af31505\loch\f39 , normal set is used
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Flip normals}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": Flip all normal vectors
+\par }\pard \ltrpar\ql \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab }{\rtlch\fcs1 \af39 \ltrch\fcs0
+\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ab\ai\af39 \ltrch\fcs0 \b\i\f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39
+Background}{\rtlch\fcs1 \af39 \ltrch\fcs0 \f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 : Set the background color or use a texture (}{\rtlch\fcs1 \af39 \ltrch\fcs0
+\f39\lang1033\langfe1031\langnp1033\insrsid9465848\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 cube maps}{\rtlch\fcs1 \af39 \ltrch\fcs0 \f39\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39
+ are supported as skyboxes) as background image for the viewer.
+\par }\pard \ltrpar\qj \fi-360\li720\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin720\itap0\pararsid3942873 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Set color}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Displays a color picker where you can choose
+\hich\af39\dbch\af31505\loch\f39 a new background color for the viewer.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Load skybox}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Opens a file system dialog where you can select a skybox as background image. Accepted file formats are: *.dds, *.hdr.
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Load texture}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Opens a file system dialog where you can select a texture as \hich\af39\dbch\af31505\loch\f39
+background image. If the format of the texture doesn't fit to the proportions of the preview window, the texture will be stretched. }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid3942873
+\par }\pard \ltrpar\qj \fi-12\li720\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin720\itap0\pararsid3942873 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Accepted file formats are: *.jpg;*.png;*.tif;*.tga;*.dds;*.hdr;*.ppm;*.bmp
+\par }\pard \ltrpar\ql \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 - "}{\rtlch\fcs1
+\ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ?}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 ": }{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Help and feedback}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+
+\par \tab }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Feedback}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 ": Opens a p\hich\af39\dbch\af31505\loch\f39 opup menu with two options:
+\par }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{
+\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 Report bug}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Report a bug in AssimpView or in Assimp
+\par }\pard \ltrpar\qj \fi-360\li720\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 Feature request}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017 \hich\af39\dbch\af31505\loch\f39 ": Tell us what}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39 you'd like us to support. Any }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid13463017
+\hich\af39\dbch\af31505\loch\f39 exotic file formats?
+\par }\pard \ltrpar\qj \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 \hich\f39
+The side panel \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Statistics}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 displays rendering statistics. The meanings of the fi\hich\af39\dbch\af31505\loch\f39 elds change if you change between normal and texture/material mode.
+\par }\pard \ltrpar\qj \li340\ri1474\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1474\lin340\itap0\pararsid13463017 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+Normal view mode:
+\par }\pard \ltrpar\qj \li340\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin340\itap0\pararsid5053873 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \tab }{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 Verts}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of unique vertices in the asset
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Faces}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 ": Numb}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39
+er of faces (= triangles) in the asset
+\par \tab \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Nodes}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of nodes in the scenegraph, including the root node
+\par }\pard \ltrpar\qj \fi-368\li708\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin708\itap0\pararsid5053873 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \tab
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Mats:}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 " Number of different materials found in the mesh. Most loaders \tab remove unreferenced materials.
+\par }\pard \ltrpar\qj \li700\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin700\itap0\pararsid5053873 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Mesh}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 sub meshes}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 . Each mesh has only one material \tab assigned, so thi
+\hich\af39\dbch\af31505\loch\f39 s number is in most cases equal to or higher than the \tab number of materials.
+\par \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Shd}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Number of unique shaders created}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873
+\hich\af39\dbch\af31505\loch\f39 for this asset. If AssimpView }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39
+detects that two materials can be rendered using }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 the same }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Shader}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 code,
+\hich\af39\dbch\af31505\loch\f39 but \hich\af39\dbch\af31505\loch\f39 with }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 different}{\rtlch\fcs1 \af39\afs16
+\ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 parameterizations}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 , it do}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 esn't create the }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689 \hich\af39\dbch\af31505\loch\f39 Shader}{\rtlch\fcs1
+\af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 twice. }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 Most engines do so, too.
+\par \hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 Time}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Time required for loading, in seco}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873
+\hich\af39\dbch\af31505\loch\f39 nds. This time is the raw time }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 the process spent in Assimp loading the mod}{
+\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39 el itself, it does not include }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 texture loading, }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid6912689\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 Shader}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 compilation ...
+\par }\pard \ltrpar\qj \li700\ri1208\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin1208\lin700\itap0\pararsid9465848 {\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873
+\hich\af39\dbch\af31505\loch\f39 * "}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \b\i\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 FPS}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 ": Current frame rate, in frames per se}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873
+\hich\af39\dbch\af31505\loch\f39 cond. Note that this number }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid13463017\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 is }{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0
+\f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid5053873 \hich\af39\dbch\af31505\loch\f39 not really exact.}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid5053873 \hich\af39\dbch\af31505\loch\f39
+ It is only an approximation to the real frame rate. The maximum frame rate \hich\af39\dbch\af31505\loch\f39 will\hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39 never be reached since there is a 10 ms blocker included (
+\hich\af39\dbch\af31505\loch\f39 to work around good old AMD timing bug\hich\af39\dbch\af31505\loch\f39 )}{\rtlch\fcs1 \af39\afs16 \ltrch\fcs0 \f39\fs16\lang1033\langfe1031\langnp1033\insrsid8068556\charrsid9465848
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 \hich\f39 The \'93}{
+\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Rendering}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 panel provides rendering-related options, such as wireframe/normal visualization.}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid9465848
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 \hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\hich\af39\dbch\af31505\loch\f39 Interaction}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 bundles all input related options.
+\par \hich\af39\dbch\af31505\loch\f39 The main \hich\af39\dbch\af31505\loch\f39 component is the large viewer panel where the assets are displayed. Status messages (e.g. if a texture could not be loaded)}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39 \hich\af39\dbch\af31505\loch\f39 are displayed in the upper-right}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\hich\af39\dbch\af31505\loch\f39 edge.}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid9465848 \hich\af39\dbch\af31505\loch\f39
+ Yellow messages are simple information messages, red messages are error messages. Green messages\hich\af39\dbch\af31505\loch\f39 , however, are coming from heart ;-)}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 III.\tab Input
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 \hich\f39
+The input mode depends on the selected input behavior. If \'84}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Zoom/Rotate}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 is }{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 NOT}{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 selected the following scheme applies:
+\par }\pard \ltrpar\ql \fi368\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1
+\ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Arrow up}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39
+\rquote \loch\f39 \tab = Move forwards
+\par \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Arrow left\hich\f39 \rquote }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 \tab = Move to the left
+\par \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Arrow down}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \rquote \loch\f39 \tab = Move backwards
+\par \loch\af39\dbch\af31505\hich\f39 \lquote }{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Arrow right}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \rquote \loch\f39 \tab = Move to the right
+\par }\pard \ltrpar\ql \fi340\li0\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+The mouse specifies the view direction. This is the typical FPS input behavior.
+\par }{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Otherwise\hich\af39\dbch\af31505\loch\f39 \hich\f39 , if \'84}{\rtlch\fcs1 \ab\ai\af39\afs20 \ltrch\fcs0
+\b\i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Zoom/Rotate}{\rtlch\fcs1 \ab\af39\afs20 \ltrch\fcs0 \b\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39
+ is enabled:
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1
+\ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Left Mouse Button}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556
+\loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse to rotate the asset around its local axes. Inside the yellow circle: x/y-axis, outside: Z-axis. To rotate around one axis only use the axis snap-ins (yellow squares with a
+\hich\af39\dbch\af31505\loch\f39 cross inside).
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Right Mouse Button}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse to rotate the light source(s) around their x and y axes.
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Middle Mouse Button}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse from the left to the right or the other way round to increase/decrease t\hich\af39\dbch\af31505\loch\f39
+he intensity of the light source(s)
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Right }{\rtlch\fcs1 \ab\ai\af39\afs20 \ltrch\fcs0
+\b\i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 AND}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Left Mouse Button}{
+\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Keep pressed and move the mouse to rotate skybox (if existing) around the global x/y axes.
+\par \loch\af39\dbch\af31505\hich\f39 \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Mouse wheel}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0
+\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 = Zoom in/out
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 IV.\tab }{\rtlch\fcs1
+\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Rendering
+\par }\pard \ltrpar\ql \li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+Enabling MultiSampling improves rendering\hich\af39\dbch\af31505\loch\f39 quality. MultiSampling is activated by default. The highest quality MultiSampling mode supported by the video card is used.
+\par \hich\af39\dbch\af31505\loch\f39 MultiSampling is especially useful to remove line artifacts in wireframe/normals mode. Note that the transition between normal and \hich\af39\dbch\af31505\loch\f39 multisampled rendering may take a few seconds.
+\par \hich\af39\dbch\af31505\loch\f39 \hich\f39 Rendering is done via Direct3D\'99\loch\f39 \hich\f39 9.0c. Note that the \'93}{\rtlch\fcs1 \ai\af39\afs20 \ltrch\fcs0 \i\f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39
+Low-quality lighting}{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \loch\af39\dbch\af31505\hich\f39 \'94\loch\f39 -Option is not available for PS 2.0 cards. Lighting on PS 2.0 cards is always low quality.
+
+\par
+\par }\pard \ltrpar\ql \fi-360\li340\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin340\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 V.\tab }{\rtlch\fcs1
+\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556 \hich\af39\dbch\af31505\loch\f39 Known issues
+\par }\pard \ltrpar\ql \fi-360\li700\ri0\sa200\sl276\slmult1\nowidctlpar\wrapdefault\faauto\rin0\lin700\itap0 {\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab \hich\af39\dbch\af31505\loch\f39
+If a loading process is \hich\af39\dbch\af31505\loch\f39 canceled it is not guaranteed that further loading processes will succeed. ASSIMP Viewer might even crash in this case. }{\rtlch\fcs1 \af39\afs24 \ltrch\fcs0
+\f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab \hich\af39\dbch\af31505\loch\f39 Some very complex materials involving real time reflection/refraction are not displayed properly.}{\rtlch\fcs1
+\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }{\rtlch\fcs1 \af39\afs20 \ltrch\fcs0 \f39\fs20\lang1033\langfe1031\langnp1033\insrsid8068556 -\tab \hich\af39\dbch\af31505\loch\f39 When rendering non-opaque objects\hich\af39\dbch\af31505\loch\f39 some triangle artifacts might occur.}{\rtlch\fcs1
+\af39\afs24 \ltrch\fcs0 \f39\fs24\lang1033\langfe1031\langnp1033\insrsid8068556
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f0000000000000000000000004091
+1ff3e2b4c801feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}}
diff --git a/libs/assimp/tools/assimp_view/tx.bmp b/libs/assimp/tools/assimp_view/tx.bmp
new file mode 100644
index 0000000..4c303b6
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/tx.bmp
Binary files differ
diff --git a/libs/assimp/tools/assimp_view/txi.bmp b/libs/assimp/tools/assimp_view/txi.bmp
new file mode 100644
index 0000000..541243b
--- /dev/null
+++ b/libs/assimp/tools/assimp_view/txi.bmp
Binary files differ