123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077 |
- /*
- ---------------------------------------------------------------------------
- Open Asset Import Library (assimp)
- ---------------------------------------------------------------------------
- Copyright (c) 2006-2024, 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.; // Animation time
- // 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) {
- // 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 variable g_szFileName
- //-------------------------------------------------------------------------------
- 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;
- 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 if 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;
- g_szFileName[0] = '\0';
- // 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() {
- 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
|