summaryrefslogtreecommitdiff
path: root/src/mesh/assimp-master/tools/assimp_view/Display.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesh/assimp-master/tools/assimp_view/Display.cpp')
-rw-r--r--src/mesh/assimp-master/tools/assimp_view/Display.cpp2302
1 files changed, 2302 insertions, 0 deletions
diff --git a/src/mesh/assimp-master/tools/assimp_view/Display.cpp b/src/mesh/assimp-master/tools/assimp_view/Display.cpp
new file mode 100644
index 0000000..95ed416
--- /dev/null
+++ b/src/mesh/assimp-master/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;
+}
+
+}
+