#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#if defined(_DEBUG)
#define D3D_DEBUG_INFO
#endif
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <sstream>
#include <stdexcept>
#include <string>
#if defined(_DEBUG)
#include <crtdbg.h>
#endif
//-----------------------------------------------------------------------------
// Macros.
//-----------------------------------------------------------------------------
#define SAFE_RELEASE(x) if ((x) != 0) { (x)->Release(); (x) = 0; }
//-----------------------------------------------------------------------------
// Constants.
//-----------------------------------------------------------------------------
#if !defined(CLEARTYPE_QUALITY)
#define CLEARTYPE_QUALITY 5
#endif
#if !defined(WHEEL_DELTA)
#define WHEEL_DELTA 120
#endif
#if !defined(WM_MOUSEWHEEL)
#define WM_MOUSEWHEEL 0x020A
#endif
#define APP_TITLE "D3D9 Normal Mapping"
#define EARTH_MESH "D:/Media/general.x"
const float CAMERA_FOVY = D3DXToRadian(45.0f);
const float CAMERA_ZNEAR = 0.1f;
const float CAMERA_ZFAR = 100.0f;
const float DOLLY_MIN = 0.0f;
const float DOLLY_MAX = 10.0f;
const float MOUSE_ROTATE_SPEED = 0.30f;
const float MOUSE_DOLLY_SPEED = 0.02f;
const float MOUSE_TRACK_SPEED = 0.005f;
const float MOUSE_WHEEL_DOLLY_SPEED = 0.005f;
const float LIGHT_RADIUS = 10.0f;
const float LIGHT_SPOT_INNER_CONE = D3DXToRadian(10.0f);
const float LIGHT_SPOT_OUTER_CONE = D3DXToRadian(30.0f);
LPDIRECT3DTEXTURE9 g_pBaseTexture = NULL; // base map texture surfaces
LPDIRECT3DTEXTURE9 g_pBaseNormal = NULL; // normal / height map texture surfaces
//-----------------------------------------------------------------------------
// User Defined Types.
//-----------------------------------------------------------------------------
struct Vertex
{
float pos[3];
float texCoord[2];
float normal[3];
float tangent[4];
};
struct Light
{
enum {DIR_LIGHT, POINT_LIGHT, SPOT_LIGHT};
int type;
float dir[3];
float pos[3];
float ambient[4];
float diffuse[4];
float specular[4];
float spotInnerCone;
float spotOuterCone;
float radius;
};
struct Material
{
float ambient[4];
float diffuse[4];
float emissive[4];
float specular[4];
float shininess;
};
//-----------------------------------------------------------------------------
// Globals.
//-----------------------------------------------------------------------------
HWND g_hWnd;
HINSTANCE g_hInstance;
IDirect3D9 *g_pDirect3D;
IDirect3DDevice9 *g_pDevice;
ID3DXFont *g_pFont;
ID3DXEffect *g_pEffect;
IDirect3DVertexDeclaration9 *g_pVertexDecl;
IDirect3DVertexBuffer9 *g_pVertexBuffer;
IDirect3DTexture9 *g_pNullTexture;
IDirect3DTexture9 *g_pColorMap;
IDirect3DTexture9 *g_pNormalMap;
DWORD g_msaaSamples;
DWORD g_maxAnisotrophy;
int g_framesPerSecond;
int g_windowWidth;
int g_windowHeight;
bool g_enableVerticalSync;
bool g_isFullScreen;
bool g_hasFocus;
bool g_wireframe;
bool g_displayHelp;
float g_pitch;
float g_heading;
float g_sceneAmbient[4] = {0.2f, 0.2f, 0.2f, 1.0f};
D3DPRESENT_PARAMETERS g_params;
D3DXVECTOR3 g_cameraPos(0.0f, 0.0f, -2.5f);
D3DXVECTOR3 g_cubePos(0.0f, 0.0f, 2.0f);
Light g_light =
{
Light::DIR_LIGHT,
0.0f, 0.0f, 1.0f, // dir
0.0f, 0.0f, 0.0f, //g_cameraPos.x, g_cameraPos.y, g_cameraPos.z, // pos
1.0f, 1.0f, 1.0f, 0.0f, // ambient
1.0f, 1.0f, 1.0f, 0.0f, // diffuse
1.0f, 1.0f, 1.0f, 0.0f, // specular
LIGHT_SPOT_INNER_CONE, // spotInnerCone
LIGHT_SPOT_OUTER_CONE, // spotOuterCone
LIGHT_RADIUS // radius
};
Material g_material =
{
0.2f, 0.2f, 0.2f, 1.0f, // ambient
0.8f, 0.8f, 0.8f, 1.0f, // diffuse
0.0f, 0.0f, 0.0f, 1.0f, // emissive
0.7f, 0.7f, 0.7f, 1.0f, // specular
90.0f // shininess
};
/*
D3DVERTEXELEMENT9 g_vertexElements[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
{0, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
D3DDECL_END()
};*/
const D3DVERTEXELEMENT9 g_vertexElements[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, 32, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 },
{ 0, 44, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },
D3DDECL_END()
};
ID3DXMesh* g_pMesh = NULL; // Mesh object
//-----------------------------------------------------------------------------
// Function Prototypes.
//-----------------------------------------------------------------------------
...
//-----------------------------------------------------------------------------
// Functions.
//-----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
...
g_hWnd = CreateAppWindow(wcl, APP_TITLE);
if (g_hWnd)
{
SetProcessorAffinity();
if (Init())
{
ShowWindow(g_hWnd, nShowCmd);
UpdateWindow(g_hWnd);
while (true)
{
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
break;
if (g_hasFocus)
{
if (DeviceIsValid())
RenderTUT();
}
else
{
WaitMessage();
}
}
}
Cleanup();
UnregisterClass(wcl.lpszClassName, hInstance);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
...
}
void ChooseBestMSAAMode(D3DFORMAT backBufferFmt, D3DFORMAT depthStencilFmt,
BOOL windowed, D3DMULTISAMPLE_TYPE &type,
DWORD &qualityLevels, DWORD &samplesPerPixel)
{
...
}
void Cleanup()
{
...
}
void CleanupApp()
{
...
}
HWND CreateAppWindow(const WNDCLASSEX &wcl, const char *pszTitle)
{
...
return hWnd;
}
bool CreateNullTexture(int width, int height, LPDIRECT3DTEXTURE9 &pTexture)
{
// Create an empty white texture. This texture is applied to geometry
// that doesn't have any texture maps. This trick allows the same shader to
// be used to draw the geometry with and without textures applied.
HRESULT hr = D3DXCreateTexture(g_pDevice, width, height, 0, 0,
D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &pTexture);
if (FAILED(hr))
return false;
LPDIRECT3DSURFACE9 pSurface = 0;
if (SUCCEEDED(pTexture->GetSurfaceLevel(0, &pSurface)))
{
D3DLOCKED_RECT rcLock = {0};
if (SUCCEEDED(pSurface->LockRect(&rcLock, 0, 0)))
{
BYTE *pPixels = static_cast<BYTE*>(rcLock.pBits);
int widthInBytes = width * 4;
if (widthInBytes == rcLock.Pitch)
{
memset(pPixels, 0xff, widthInBytes * height);
}
else
{
for (int y = 0; y < height; ++y)
memset(&pPixels[y * rcLock.Pitch], 0xff, rcLock.Pitch);
}
pSurface->UnlockRect();
pSurface->Release();
return true;
}
pSurface->Release();
}
pTexture->Release();
return false;
}
bool DeviceIsValid()
{
HRESULT hr = g_pDevice->TestCooperativeLevel();
if (FAILED(hr))
{
if (hr == D3DERR_DEVICENOTRESET)
return ResetDevice();
}
return true;
}
float GetElapsedTimeInSeconds()
{
// Returns the elapsed time (in seconds) since the last time this function
...
return actualElapsedTimeSec;
}
bool Init()
{
if (!InitD3D())
{
Log("Direct3D initialization failed!");
return false;
}
try
{
InitApp();
return true;
}
catch (const std::exception &e)
{
std::ostringstream msg;
msg << "Application initialization failed!" << std::endl << std::endl;
msg << e.what();
Log(msg.str().c_str());
return false;
}
}
void InitApp()
{
if (!InitFont("Arial", 10, g_pFont))
throw std::runtime_error("Failed to create font.");
if (!CreateNullTexture(2, 2, g_pNullTexture))
throw std::runtime_error("Failed to create null texture.");
//if (FAILED(D3DXCreateTextureFromFile(g_pDevice, "Content/Textures/color_map.jpg", &g_pColorMap)))
if (FAILED(D3DXCreateTextureFromFile(g_pDevice, "D:/BoD/Programming/Client/Media/white.tga", &g_pColorMap)))
throw std::runtime_error("Failed to load texture: color_map.jpg.");
//if (FAILED(D3DXCreateTextureFromFile(g_pDevice, "Content/Textures/normal_map.jpg", &g_pNormalMap)))
if (FAILED(D3DXCreateTextureFromFile(g_pDevice, "D:/BoD/Programming/Client/Media/white.tga", &g_pNormalMap)))
throw std::runtime_error("Failed to load texture: normal_map.jpg.");
if (!LoadShader("Content/Shaders/ParallaxOcclusionMapping.fx", g_pEffect))
throw std::runtime_error("Failed to load shader: normal_mapping.fx.");
LoadMesh( g_pDevice, &g_pMesh );
}
bool InitD3D()
{
HRESULT hr = 0;
D3DDISPLAYMODE desktop = {0};
g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!g_pDirect3D)
return false;
// Just use the current desktop display mode.
hr = g_pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &desktop);
if (FAILED(hr))
{
g_pDirect3D->Release();
g_pDirect3D = 0;
return false;
}
// Setup Direct3D for windowed rendering.
g_params.BackBufferWidth = 0;
g_params.BackBufferHeight = 0;
g_params.BackBufferFormat = desktop.Format;
g_params.BackBufferCount = 1;
g_params.hDeviceWindow = g_hWnd;
g_params.Windowed = TRUE;
g_params.EnableAutoDepthStencil = TRUE;
g_params.AutoDepthStencilFormat = D3DFMT_D24S8;
g_params.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
g_params.FullScreen_RefreshRateInHz = 0;
if (g_enableVerticalSync)
g_params.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
else
g_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// Swap effect must be D3DSWAPEFFECT_DISCARD for multi-sampling support.
g_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
// Select the highest quality multi-sample anti-aliasing (MSAA) mode.
ChooseBestMSAAMode(g_params.BackBufferFormat, g_params.AutoDepthStencilFormat,
g_params.Windowed, g_params.MultiSampleType, g_params.MultiSampleQuality,
g_msaaSamples);
// Most modern video cards should have no problems creating pure devices.
// Note that by creating a pure device we lose the ability to debug vertex
// and pixel shaders.
hr = g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
&g_params, &g_pDevice);
if (FAILED(hr))
{
// Fall back to software vertex processing for less capable hardware.
// Note that in order to debug vertex shaders we must use a software
// vertex processing device.
hr = g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &g_params, &g_pDevice);
}
if (FAILED(hr))
{
g_pDirect3D->Release();
g_pDirect3D = 0;
return false;
}
D3DCAPS9 caps;
// Prefer anisotropic texture filtering if it's supported.
if (SUCCEEDED(g_pDevice->GetDeviceCaps(&caps)))
{
if (caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY)
g_maxAnisotrophy = caps.MaxAnisotropy;
else
g_maxAnisotrophy = 1;
}
return true;
}
bool InitFont(const char *pszFont, int ptSize, LPD3DXFONT &pFont)
{
...
return SUCCEEDED(hr) ? true : false;
}
bool LoadShader(const char *pszFilename, LPD3DXEFFECT &pEffect)
{
ID3DXBuffer *pCompilationErrors = 0;
DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE | D3DXSHADER_NO_PRESHADER;
// Both vertex and pixel shaders can be debugged. To enable shader
// debugging add the following flag to the dwShaderFlags variable:
// dwShaderFlags |= D3DXSHADER_DEBUG;
//
// Vertex shaders can be debugged with either the REF device or a device
// created for software vertex processing (i.e., the IDirect3DDevice9
// object must be created with the D3DCREATE_SOFTWARE_VERTEXPROCESSING
// behavior). Pixel shaders can be debugged only using the REF device.
//
// To enable vertex shader debugging add the following flag to the
// dwShaderFlags variable:
// dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
//
// To enable pixel shader debugging add the following flag to the
// dwShaderFlags variable:
// dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
HRESULT hr = D3DXCreateEffectFromFile(g_pDevice, pszFilename, 0, 0,
dwShaderFlags, 0, &pEffect, &pCompilationErrors);
if (FAILED(hr))
{
if (pCompilationErrors)
{
std::string compilationErrors(static_cast<const char *>(
pCompilationErrors->GetBufferPointer()));
pCompilationErrors->Release();
throw std::runtime_error(compilationErrors);
}
}
if (pCompilationErrors)
pCompilationErrors->Release();
//CHANGES
D3DXCreateTextureFromFile( g_pDevice, "C:/Users/X/Desktop/Content/Textures/color_map.jpg", &g_pBaseTexture );
D3DXCreateTextureFromFile( g_pDevice, "C:/Users/X/Desktop/Content/Textures/normal_map.jpg", &g_pBaseNormal );
g_pEffect->SetTexture( "g_baseTexture", g_pBaseTexture );
g_pEffect->SetTexture( "g_nmhTexture", g_pBaseNormal );
return pEffect != 0;
}
void Log(const char *pszMessage)
{
MessageBox(0, pszMessage, "Error", MB_ICONSTOP);
}
void ProcessMouseInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
...
}
bool ResetDevice()
{
...
}
void SetProcessorAffinity()
{
...
}
void ToggleFullScreen()
{
...
}
void RenderTUT()
{
static D3DXMATRIX world, view, proj;
static D3DXMATRIX xRot, yRot, translation;
static D3DXMATRIX worldViewProjectionMatrix;
static D3DXMATRIX worldInverseTransposeMatrix;
// Calculate the perspective projection matrix.
D3DXMatrixPerspectiveFovLH(&proj, CAMERA_FOVY,
static_cast<float>(g_windowWidth) / static_cast<float>(g_windowHeight),
CAMERA_ZNEAR, CAMERA_ZFAR);
// Calculate the view matrix.
D3DXMatrixLookAtLH(&view, &g_cameraPos, &D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
// Calculate world matrix to transform the cube.
D3DXMatrixRotationX(&xRot, D3DXToRadian(g_pitch));
D3DXMatrixRotationY(&yRot, D3DXToRadian(g_heading));
D3DXMatrixMultiply(&world, &yRot, &xRot);
D3DXMatrixTranslation(&translation, g_cubePos.x, g_cubePos.y, g_cubePos.z);
D3DXMatrixMultiply(&world, &world, &translation);
// Calculate combined world-view-projection matrix.
worldViewProjectionMatrix = world * view * proj;
// Calculate the transpose of the inverse of the world matrix.
D3DXMatrixInverse(&worldInverseTransposeMatrix, 0, &world);
D3DXMatrixTranspose(&worldInverseTransposeMatrix, &worldInverseTransposeMatrix);
/*
float lightDir[4];
lightDir[0]=g_light.dir[0];
lightDir[1]=g_light.dir[1];
lightDir[2]=g_light.dir[2];
lightDir[3]=0.0f;*/
D3DXVECTOR3 lightDir;
lightDir.x=g_light.dir[0];
lightDir.y=g_light.dir[1];
lightDir.z=g_light.dir[2];
lightDir[3]=0.0f;
D3DXCOLOR vLightDiffuse;
float g_fLightScale = 1.0f;
vLightDiffuse = g_fLightScale * D3DXCOLOR( 1, 1, 1, 1 );
g_pEffect->SetValue( "g_LightDir", &lightDir, sizeof( D3DXVECTOR3 ) );
g_pEffect->SetValue( "g_LightDiffuse", &vLightDiffuse, sizeof( D3DXVECTOR4 ) );
// Set the matrices for the shader.
//g_pEffect->SetMatrix("worldMatrix", &world);
g_pEffect->SetMatrix("g_mWorldViewProjection", &worldViewProjectionMatrix);
g_pEffect->SetMatrix( "g_mWorld", &world );
g_pEffect->SetMatrix( "g_mView", &view );
D3DXVECTOR4 vEye;
/*D3DXVECTOR3 vTemp = ( *g_Camera.GetEyePt() );
vEye.x = vTemp.x;
vEye.y = vTemp.y;
vEye.z = vTemp.z;
vEye.w = 1.0;*/
vEye.x = g_cameraPos.x;
vEye.y = g_cameraPos.y;
vEye.z = g_cameraPos.z;
vEye.w = 1.0;
g_pEffect->SetVector( "g_vEye", &vEye );
//strzal ;-)
float g_fHeightScale = 100.0f;
g_pEffect->SetValue( "g_fHeightMapScale", &g_fHeightScale, sizeof( float ) );
g_pEffect->SetTechnique( "RenderSceneWithPOM" );
/*
UINT iPass, cPasses;
g_pEffect->Begin( &cPasses, 0 );
for( iPass = 0; iPass < cPasses; iPass++ )
{
g_pEffect->BeginPass( iPass );
g_pMesh->DrawSubset( 0 );
g_pEffect->EndPass();
}
g_pEffect->End();
}
*/
g_pDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(100, 149, 237), // CornflowerBlue
1.0f, 0);
if (FAILED(g_pDevice->BeginScene()))
return;
UINT totalPasses;
if (SUCCEEDED(g_pEffect->Begin(&totalPasses, 0)))
{
for( UINT iPass = 0; iPass < totalPasses; iPass++ )
{
g_pEffect->BeginPass( iPass );
g_pMesh->DrawSubset( 0 );
g_pEffect->EndPass();
}
g_pEffect->End();
}
g_pDevice->EndScene();
g_pDevice->Present(0, 0, 0, 0);
}
//--------------------------------------------------------------------------------------
// This function loads the mesh and ensures the mesh has normals; it also
// optimizes the mesh for the graphics card's vertex cache, which improves
// performance by organizing the internal triangle list for less cache misses.
//--------------------------------------------------------------------------------------
HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, ID3DXMesh** ppMesh )
{
ID3DXMesh* pMesh = NULL;
HRESULT hr;
//====================================================================//
// Load the mesh with D3DX and get back a ID3DXMesh*. For this //
// sample we'll ignore the X file's embedded materials since we know //
// exactly the model we're loading. See the mesh samples such as //
// "OptimizedMesh" for a more generic mesh loading example. //
//====================================================================//
HRESULT hResult = D3DXLoadMeshFromX( EARTH_MESH, D3DXMESH_SYSTEMMEM, g_pDevice, NULL,
NULL, NULL, NULL, &pMesh );
// Create a new vertex declaration to hold all the required data
const D3DVERTEXELEMENT9 vertexDecl[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 0, 20, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, 32, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 },
{ 0, 44, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },
D3DDECL_END()
};
LPD3DXMESH pTempMesh = NULL;
// Clone mesh to match the specified declaration:
if( FAILED( pMesh->CloneMesh( pMesh->GetOptions(), vertexDecl, pd3dDevice, &pTempMesh ) ) )
{
SAFE_RELEASE( pTempMesh );
return E_FAIL;
}
//====================================================================//
// Check if the old declaration contains normals, tangents, binormals //
//====================================================================//
bool bHadNormal = false;
bool bHadTangent = false;
bool bHadBinormal = false;
D3DVERTEXELEMENT9 vertexOldDecl[ MAX_FVF_DECL_SIZE ];
if( pMesh && SUCCEEDED( pMesh->GetDeclaration( vertexOldDecl ) ) )
{
// Go through the declaration and look for the right channels, hoping for a match:
for( UINT iChannelIndex = 0; iChannelIndex < D3DXGetDeclLength( vertexOldDecl ); iChannelIndex++ )
{
if( vertexOldDecl[iChannelIndex].Usage == D3DDECLUSAGE_NORMAL )
{
bHadNormal = true;
}
if( vertexOldDecl[iChannelIndex].Usage == D3DDECLUSAGE_TANGENT )
{
bHadTangent = true;
}
if( vertexOldDecl[iChannelIndex].Usage == D3DDECLUSAGE_BINORMAL )
{
bHadBinormal = true;
}
}
}
if( pTempMesh == NULL && ( bHadNormal == false || bHadTangent == false || bHadBinormal == false ) )
{
// We failed to clone the mesh and we need the tangent space for our effect:
return E_FAIL;
}
//==============================================================//
// Generate normals / tangents / binormals if they were missing //
//==============================================================//
SAFE_RELEASE( pMesh );
pMesh = pTempMesh;
if( !bHadNormal )
{
// Compute normals in case the meshes have them
D3DXComputeNormals( pMesh, NULL );
}
DWORD* rgdwAdjacency = NULL;
rgdwAdjacency = new DWORD[ pMesh->GetNumFaces() * 3 ];
if( rgdwAdjacency == NULL )
{
return E_OUTOFMEMORY;
}
pMesh->GenerateAdjacency( 1e-6f, rgdwAdjacency );
// Optimize the mesh for this graphics card's vertex cache
// so when rendering the mesh's triangle list the vertices will
// cache hit more often so it won't have to re-execute the vertex shader
// on those vertices so it will improve perf.
pMesh->OptimizeInplace( D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL );
if( !bHadTangent || !bHadBinormal )
{
ID3DXMesh* pNewMesh;
// Compute tangents, which are required for normal mapping
if( FAILED( D3DXComputeTangentFrameEx( pMesh, D3DDECLUSAGE_TEXCOORD, 0, D3DDECLUSAGE_TANGENT, 0,
D3DDECLUSAGE_BINORMAL, 0,
D3DDECLUSAGE_NORMAL, 0, 0, rgdwAdjacency, -1.01f,
-0.01f, -1.01f, &pNewMesh, NULL ) ) )
{
return E_FAIL;
}
SAFE_RELEASE( pMesh );
pMesh = pNewMesh;
}
// SAFE_DELETE_ARRAY( rgdwAdjacency );
*ppMesh = pMesh;
return S_OK;
}