Direct3D对加载到内存中的网格模型提供了优化功能,通过网格模型优化可以明显提高三维模型的渲染速度,这对渲染速度要求较高的三维图形程序和游戏具有非常重要的现实意义。
对于程序员而言,对网格模型进行优化是比较简单的,只需调用接口ID3DXMesh的方法Optimize(),该函数的声明如下:
Generates a new mesh with reordered faces and vertices
to optimize drawing performance.
HRESULT Optimize(
DWORD Flags,
CONST DWORD * pAdjacencyIn,
DWORD * pAdjacencyOut,
DWORD * pFaceRemap,
LPD3DXBUFFER * ppVertexRemap,
LPD3DXMESH * ppOptMesh
);
Parameters
- Flags
- [in] Specifies the type of optimization to
perform. This parameter can be set to a combination of one or more flags
from D3DXMESHOPT and D3DXMESH (except D3DXMESH_32BIT, D3DXMESH_IB_WRITEONLY,
and D3DXMESH_WRITEONLY).
- pAdjacencyIn
- [in] Pointer to an array of three DWORDs per face
that specifies the three neighbors for each face in the source mesh. If the
edge has no adjacent faces, the value is 0xffffffff. See Remarks.
- pAdjacencyOut
- [in, out] Pointer to an array of three DWORDs per
face that specifies the three neighbors for each face in the optimized mesh.
If the edge has no adjacent faces, the value is 0xffffffff.
- pFaceRemap
- [in, out] An array of DWORDs, one per face, that
identifies the original mesh face that corresponds to each face in the
optimized mesh. If the value supplied for this argument is NULL, face remap
data is not returned.
- ppVertexRemap
- [out] Address of a pointer to an ID3DXBuffer
interface, which contains a DWORD for each vertex that specifies how the new
vertices map to the old vertices. This remap is useful if you need to alter
external data based on the new vertex mapping.
- ppOptMesh
- [out] Address of a pointer to an ID3DXMesh
interface, representing the optimized mesh.
Return Values
If the method succeeds, the return value is D3D_OK. If
the method fails, the return value can be one of the following:
D3DERR_INVALIDCALL, E_OUTOFMEMORY.
Remarks
This method generates a new mesh. Before running
Optimize, an application must generate an adjacency buffer by calling
ID3DXBaseMesh::GenerateAdjacency. The adjacency buffer contains adjacency data,
such as a list of edges and the faces that are adjacent to each other.
This method is very similar to the
ID3DXBaseMesh::CloneMesh method, except that it can perform optimization while
generating the new clone of the mesh. The output mesh inherits all of the
creation parameters of the input mesh.
Direct3D提供了7种网格模型优化方式,由枚举常量D3DXMESHOPT定义:
Specifies the type of mesh optimization to be
performed.
typedef enum D3DXMESHOPT
{
D3DXMESHOPT_COMPACT = 0x01000000,
D3DXMESHOPT_ATTRSORT = 0x02000000,
D3DXMESHOPT_VERTEXCACHE = 0x04000000,
D3DXMESHOPT_STRIPREORDER = 0x08000000,
D3DXMESHOPT_IGNOREVERTS = 0x10000000,
D3DXMESHOPT_DONOTSPLIT = 0x20000000,
D3DXMESHOPT_DEVICEINDEPENDENT = 0x40000000,
} D3DXMESHOPT, *LPD3DXMESHOPT;
Constants
- D3DXMESHOPT_COMPACT
- Reorders faces to remove unused vertices and
faces.
- D3DXMESHOPT_ATTRSORT
- Reorders faces to optimize for fewer attribute
bundle state changes and enhanced ID3DXBaseMesh::DrawSubset performance.
- D3DXMESHOPT_VERTEXCACHE
- Reorders faces to increase the cache hit rate of
vertex caches.
- D3DXMESHOPT_STRIPREORDER
- Reorders faces to maximize length of adjacent
triangles.
- D3DXMESHOPT_IGNOREVERTS
- Optimize the faces only; do not optimize the
vertices.
- D3DXMESHOPT_DONOTSPLIT
- While attribute sorting, do not split vertices
that are shared between attribute groups.
- D3DXMESHOPT_DEVICEINDEPENDENT
- Affects the vertex cache size. Using this flag
specifies a default vertex cache size that works well on legacy hardware.
Remarks
The D3DXMESHOPT_STRIPREORDER and
D3DXMESHOPT_VERTEXCACHE optimization flags are mutually exclusive.
The D3DXMESHOPT_SHAREVB flag has been removed from this
enumeration. Use D3DXMESH_VB_SHARE instead, in D3DXMESH.
D3DXMESH
Flags used to specify creation options for a mesh.
typedef enum D3DXMESH
{
D3DXMESH_32BIT = 0x001,
D3DXMESH_DONOTCLIP = 0x002,
D3DXMESH_POINTS = 0x004,
D3DXMESH_RTPATCHES = 0x008,
D3DXMESH_NPATCHES = 0x4000,
D3DXMESH_VB_SYSTEMMEM = 0x010,
D3DXMESH_VB_MANAGED = 0x020,
D3DXMESH_VB_WRITEONLY = 0x040,
D3DXMESH_VB_DYNAMIC = 0x080,
D3DXMESH_VB_SOFTWAREPROCESSING = 0x8000,
D3DXMESH_IB_SYSTEMMEM = 0x100,
D3DXMESH_IB_MANAGED = 0x200,
D3DXMESH_IB_WRITEONLY = 0x400,
D3DXMESH_IB_DYNAMIC = 0x800,
D3DXMESH_IB_SOFTWAREPROCESSING = 0x10000,
D3DXMESH_VB_SHARE = 0x1000,
D3DXMESH_USEHWONLY = 0x2000,
D3DXMESH_SYSTEMMEM = 0x110,
D3DXMESH_MANAGED = 0x220,
D3DXMESH_WRITEONLY = 0x440,
D3DXMESH_DYNAMIC = 0x880,
D3DXMESH_SOFTWAREPROCESSING = 0x18000,
} D3DXMESH, *LPD3DXMESH;
Constants
- D3DXMESH_32BIT
- The mesh has 32-bit indices instead of 16-bit
indices. See Remarks.
- D3DXMESH_DONOTCLIP
- Use the D3DUSAGE_DONOTCLIP usage flag for vertex
and index buffers.
- D3DXMESH_POINTS
- Use the D3DUSAGE_POINTS usage flag for vertex and
index buffers.
- D3DXMESH_RTPATCHES
- Use the D3DUSAGE_RTPATCHES usage flag for vertex
and index buffers.
- D3DXMESH_NPATCHES
- Specifying this flag causes the vertex and index
buffer of the mesh to be created with D3DUSAGE_NPATCHES flag. This is
required if the mesh object is to be rendered using N-patch enhancement
using Direct3D.
- D3DXMESH_VB_SYSTEMMEM
- Use the D3DPOOL_SYSTEMMEM usage flag for vertex
buffers.
- D3DXMESH_VB_MANAGED
- Use the D3DPOOL_MANAGED usage flag for vertex
buffers.
- D3DXMESH_VB_WRITEONLY
- Use the D3DUSAGE_WRITEONLY usage flag for vertex
buffers.
- D3DXMESH_VB_DYNAMIC
- Use the D3DUSAGE_DYNAMIC usage flag for vertex
buffers.
- D3DXMESH_VB_SOFTWAREPROCESSING
- Use the D3DUSAGE_SOFTWAREPROCESSING usage flag for
vertex buffers.
- D3DXMESH_IB_SYSTEMMEM
- Use the D3DPOOL_SYSTEMMEM usage flag for index
buffers.
- D3DXMESH_IB_MANAGED
- Use the D3DPOOL_MANAGED usage flag for index
buffers.
- D3DXMESH_IB_WRITEONLY
- Use the D3DUSAGE_WRITEONLY usage flag for index
buffers.
- D3DXMESH_IB_DYNAMIC
- Use the D3DUSAGE_DYNAMIC usage flag for index
buffers.
- D3DXMESH_IB_SOFTWAREPROCESSING
- Use the D3DUSAGE_SOFTWAREPROCESSING usage flag for
index buffers.
- D3DXMESH_VB_SHARE
- Forces the cloned meshes to share vertex buffers.
- D3DXMESH_USEHWONLY
- Use hardware processing only. For mixed-mode
device, this flag will cause the system to use hardware (if supported in
hardware) or will default to software processing.
- D3DXMESH_SYSTEMMEM
- Equivalent to specifying both
D3DXMESH_VB_SYSTEMMEM and D3DXMESH_IB_SYSTEMMEM.
- D3DXMESH_MANAGED
- Equivalent to specifying both D3DXMESH_VB_MANAGED
and D3DXMESH_IB_MANAGED.
- D3DXMESH_WRITEONLY
- Equivalent to specifying both
D3DXMESH_VB_WRITEONLY and D3DXMESH_IB_WRITEONLY.
- D3DXMESH_DYNAMIC
- Equivalent to specifying both D3DXMESH_VB_DYNAMIC
and D3DXMESH_IB_DYNAMIC.
- D3DXMESH_SOFTWAREPROCESSING
- Equivalent to specifying both
D3DXMESH_VB_SOFTWAREPROCESSING and D3DXMESH_IB_SOFTWAREPROCESSING.
Remarks
A 32-bit mesh (D3DXMESH_32BIT) can theoretically
support (2^32)-1 faces and vertices. However, allocating memory for a mesh that
large on a 32-bit operating system is not practical.
因为调用ID3DXMesh::Optimize()函数对网格模型进行优化时,需要用到网格模型中每个面的三个邻接信息,该信息在加载网格模型时得到:
ID3DXBuffer* material_buffer;
V_RETURN(D3DXLoadMeshFromXW(L"Dwarf.x", D3DXMESH_MANAGED, pd3dDevice, &g_adj_buffer, &material_buffer, NULL,
&g_num_materials, &g_mesh));
D3DXMATERIAL* xmaterials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();
g_mesh_materials = new D3DMATERIAL9[g_num_materials];
g_mesh_textures = new IDirect3DTexture9*[g_num_materials];
for(DWORD i = 0; i < g_num_materials; i++)
{
g_mesh_materials[i] = xmaterials[i].MatD3D;
g_mesh_materials[i].Ambient = g_mesh_materials[i].Diffuse;
WCHAR wfilename[256];
RemovePathFromFileName(xmaterials[i].pTextureFilename, wfilename);
g_mesh_textures[i] = NULL;
if(xmaterials[i].pTextureFilename != NULL && lstrlen(wfilename) > 0)
{
V_RETURN(D3DXCreateTextureFromFileW(pd3dDevice, wfilename, &g_mesh_textures[i]));
}
}
material_buffer->Release();
接着我们以三种方式对原始网格模型进行了优化:
DWORD* adj_in = (DWORD*) g_adj_buffer->GetBufferPointer();
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
&g_mesh_attr_sort));
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_STRIPREORDER | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
&g_mesh_strip_reorder));
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_VERTEXCACHE | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
&g_mesh_vertex_cache));
渲染优化后的网格模型与未优化的网格模型相比没有任何区别:
// Clear the render target and the zbuffer
V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) );
// Render the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
for(DWORD i = 0; i < g_num_materials; i++)
{
pd3dDevice->SetMaterial(&g_mesh_materials[i]);
pd3dDevice->SetTexture(0, g_mesh_textures[i]);
switch(g_render_flag)
{
case OPT_NONE:
g_mesh->DrawSubset(i);
break;
case OPT_ATTR_SORT:
g_mesh_attr_sort->DrawSubset(i);
break;
case OPT_STRIP_REORDER:
g_mesh_strip_reorder->DrawSubset(i);
break;
case OPT_VERTEX_CACHE:
g_mesh_vertex_cache->DrawSubset(i);
break;
}
}
RenderText();
V(g_button_dlg.OnRender(fElapsedTime));
V( pd3dDevice->EndScene() );
}
运行效果图:
主程序:
#include "dxstdafx.h"
#include "resource.h"
#pragma warning(disable : 4127 4995)
#define IDC_TOGGLE_FULLSCREEN 1
#define IDC_TOGGLE_REF 2
#define IDC_CHANGE_DEVICE 3
#define OPT_NONE 0
#define OPT_ATTR_SORT 1
#define OPT_STRIP_REORDER 2
#define OPT_VERTEX_CACHE 3
#define release_com(p) do { if(p) { (p)->Release(); (p) = NULL; } } while(0)
ID3DXFont* g_font;
ID3DXSprite* g_text_sprite;
bool g_show_help = true;
CDXUTDialogResourceManager g_dlg_resource_manager;
CD3DSettingsDlg g_settings_dlg;
CDXUTDialog g_button_dlg;
ID3DXMesh* g_mesh;
D3DMATERIAL9* g_mesh_materials;
IDirect3DTexture9** g_mesh_textures;
DWORD g_num_materials;
ID3DXBuffer* g_adj_buffer;
ID3DXMesh* g_mesh_attr_sort;
ID3DXMesh* g_mesh_strip_reorder;
ID3DXMesh* g_mesh_vertex_cache;
WCHAR g_opt_info[256];
int g_render_flag = OPT_NONE;
//--------------------------------------------------------------------------------------
// Rejects any devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
// Typically want to skip backbuffer formats that don't support alpha blending
IDirect3D9* pD3D = DXUTGetD3DObject();
if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
return false;
return true;
}
//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )
{
// If video card does not support hardware vertex processing, then uses sofaware vertex processing.
if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
static bool is_first_time = true;
if(is_first_time)
{
is_first_time = false;
// if using reference device, then pop a warning message box.
if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
DXUTDisplaySwitchingToREFWarning();
}
return true;
}
//--------------------------------------------------------------------------------------
// Remove path from fullname, and convert filename from multibyte to wchar.
//--------------------------------------------------------------------------------------
void RemovePathFromFileName(LPSTR fullname, LPWSTR wfilename)
{
WCHAR wbuf[MAX_PATH] = {0};
MultiByteToWideChar(CP_ACP, 0, fullname, -1, wbuf, MAX_PATH);
LPWSTR w_last_back_slash = wcsrchr(wbuf, '\\');
if(w_last_back_slash)
lstrcpy(wfilename, ++w_last_back_slash);
else
lstrcpy(wfilename, wbuf);
}
//--------------------------------------------------------------------------------------
// Create any D3DPOOL_MANAGED resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext )
{
HRESULT hr;
V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice));
V_RETURN(g_settings_dlg.OnCreateDevice(pd3dDevice));
D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_font);
ID3DXBuffer* material_buffer;
V_RETURN(D3DXLoadMeshFromXW(L"Dwarf.x", D3DXMESH_MANAGED, pd3dDevice, &g_adj_buffer, &material_buffer, NULL,
&g_num_materials, &g_mesh));
D3DXMATERIAL* xmaterials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();
g_mesh_materials = new D3DMATERIAL9[g_num_materials];
g_mesh_textures = new IDirect3DTexture9*[g_num_materials];
for(DWORD i = 0; i < g_num_materials; i++)
{
g_mesh_materials[i] = xmaterials[i].MatD3D;
g_mesh_materials[i].Ambient = g_mesh_materials[i].Diffuse;
WCHAR wfilename[256];
RemovePathFromFileName(xmaterials[i].pTextureFilename, wfilename);
g_mesh_textures[i] = NULL;
if(xmaterials[i].pTextureFilename != NULL && lstrlen(wfilename) > 0)
{
V_RETURN(D3DXCreateTextureFromFileW(pd3dDevice, wfilename, &g_mesh_textures[i]));
}
}
material_buffer->Release();
lstrcpy(g_opt_info, L"optimize method: none");
DWORD* adj_in = (DWORD*) g_adj_buffer->GetBufferPointer();
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
&g_mesh_attr_sort));
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_STRIPREORDER | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
&g_mesh_strip_reorder));
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_VERTEXCACHE | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
&g_mesh_vertex_cache));
return S_OK;
}
//--------------------------------------------------------------------------------------
// Create any D3DPOOL_DEFAULT resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext )
{
HRESULT hr;
V_RETURN(g_dlg_resource_manager.OnResetDevice());
V_RETURN(g_settings_dlg.OnResetDevice());
V_RETURN(g_font->OnResetDevice());
V_RETURN(D3DXCreateSprite(pd3dDevice, &g_text_sprite));
// set dialog position and size
g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0);
g_button_dlg.SetSize(170, 170);
// setup view matrix
D3DXMATRIX mat_view;
D3DXVECTOR3 eye(0.0f, 0.0f, -4.0f);
D3DXVECTOR3 at(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&mat_view, &eye, &at, &up);
pd3dDevice->SetTransform(D3DTS_VIEW, &mat_view);
// set projection matrix
D3DXMATRIX mat_proj;
float aspect = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, aspect, 1.0f, 100.0f);
pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_proj);
pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0xFFFFFFFF);
return S_OK;
}
//--------------------------------------------------------------------------------------
// Release resources created in the OnResetDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
g_dlg_resource_manager.OnLostDevice();
g_settings_dlg.OnLostDevice();
g_font->OnLostDevice();
release_com(g_text_sprite);
}
//--------------------------------------------------------------------------------------
// Release resources created in the OnCreateDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
g_dlg_resource_manager.OnDestroyDevice();
g_settings_dlg.OnDestroyDevice();
delete[] g_mesh_materials;
g_mesh_materials = NULL;
if(g_mesh_textures)
{
for(DWORD i = 0; i < g_num_materials; i++)
release_com(g_mesh_textures[i]);
delete[] g_mesh_textures;
g_mesh_textures = NULL;
}
release_com(g_font);
release_com(g_adj_buffer);
release_com(g_mesh);
release_com(g_mesh_attr_sort);
release_com(g_mesh_strip_reorder);
release_com(g_mesh_vertex_cache);
}
//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
D3DXMATRIX mat_world, mat_translation, mat_rotation;
D3DXMatrixTranslation(&mat_translation, 0, -0.7f, 0);
D3DXMatrixRotationY(&mat_rotation, timeGetTime() / 1000.0f);
mat_world = mat_translation * mat_rotation;
pd3dDevice->SetTransform(D3DTS_WORLD, &mat_world);
}
//--------------------------------------------------------------------------------------
// Render the helper information
//--------------------------------------------------------------------------------------
void RenderText()
{
CDXUTTextHelper text_helper(g_font, g_text_sprite, 20);
text_helper.Begin();
// show frame and device states
text_helper.SetInsertionPos(5, 5);
text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
text_helper.DrawTextLine( DXUTGetFrameStats(true) );
text_helper.DrawTextLine( DXUTGetDeviceStats() );
// show other simple information
text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
text_helper.DrawTextLine(g_opt_info);
// show helper information
const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();
if(g_show_help)
{
text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 6);
text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
text_helper.DrawTextLine(L"Controls (F1 to hide):");
text_helper.SetInsertionPos(40, surface_desc->Height - 15 * 4);
text_helper.DrawTextLine(L"Quit: ESC");
text_helper.SetInsertionPos(40, surface_desc->Height - 15 * 3);
text_helper.DrawTextLine(L"0, 1, 2, 3: switch optimize method");
}
else
{
text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 4);
text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
text_helper.DrawTextLine(L"Press F1 for help");
}
text_helper.End();
}
//--------------------------------------------------------------------------------------
// Render the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
HRESULT hr;
if(g_settings_dlg.IsActive())
{
g_settings_dlg.OnRender(fElapsedTime);
return;
}
// Clear the render target and the zbuffer
V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) );
// Render the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
for(DWORD i = 0; i < g_num_materials; i++)
{
pd3dDevice->SetMaterial(&g_mesh_materials[i]);
pd3dDevice->SetTexture(0, g_mesh_textures[i]);
switch(g_render_flag)
{
case OPT_NONE:
g_mesh->DrawSubset(i);
break;
case OPT_ATTR_SORT:
g_mesh_attr_sort->DrawSubset(i);
break;
case OPT_STRIP_REORDER:
g_mesh_strip_reorder->DrawSubset(i);
break;
case OPT_VERTEX_CACHE:
g_mesh_vertex_cache->DrawSubset(i);
break;
}
}
RenderText();
V(g_button_dlg.OnRender(fElapsedTime));
V( pd3dDevice->EndScene() );
}
}
//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
bool* pbNoFurtherProcessing, void* pUserContext )
{
*pbNoFurtherProcessing = g_dlg_resource_manager.MsgProc(hWnd, uMsg, wParam, lParam);
if(*pbNoFurtherProcessing)
return 0;
if(g_settings_dlg.IsActive())
{
g_settings_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
return 0;
}
*pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
if(*pbNoFurtherProcessing)
return 0;
return 0;
}
//--------------------------------------------------------------------------------------
// Handle keybaord event
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboardProc(UINT charater, bool is_key_down, bool is_alt_down, void* user_context)
{
if(is_key_down)
{
switch(charater)
{
case VK_F1:
g_show_help = !g_show_help;
break;
case 48: // press key "0"
g_render_flag = OPT_NONE;
lstrcpy(g_opt_info, L"optimize method: none");
break;
case 49: // press key "1"
g_render_flag = OPT_ATTR_SORT;
lstrcpy(g_opt_info, L"optimize method: D3DXMESHOPT_ATTRSORT");
break;
case 50: // press key "2"
g_render_flag = OPT_STRIP_REORDER;
lstrcpy(g_opt_info, L"optimize method: D3DXMESHOPT_STRIPREORDER");
break;
case 51: // press key "3"
g_render_flag = OPT_VERTEX_CACHE;
lstrcpy(g_opt_info, L"optimize method: D3DXMESHOPT_VERTEXCACHE");
break;
}
}
}
//--------------------------------------------------------------------------------------
// Handle events for controls
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent(UINT event, int control_id, CDXUTControl* control, void* user_context)
{
switch(control_id)
{
case IDC_TOGGLE_FULLSCREEN:
DXUTToggleFullScreen();
break;
case IDC_TOGGLE_REF:
DXUTToggleREF();
break;
case IDC_CHANGE_DEVICE:
g_settings_dlg.SetActive(true);
break;
}
}
//--------------------------------------------------------------------------------------
// Initialize dialogs
//--------------------------------------------------------------------------------------
void InitDialogs()
{
g_settings_dlg.Init(&g_dlg_resource_manager);
g_button_dlg.Init(&g_dlg_resource_manager);
g_button_dlg.SetCallback(OnGUIEvent);
int x = 35, y = 10, width = 125, height = 22;
g_button_dlg.AddButton(IDC_TOGGLE_FULLSCREEN, L"Toggle full screen", x, y, width, height);
g_button_dlg.AddButton(IDC_TOGGLE_REF, L"Toggle REF (F3)", x, y += 24, width, height);
g_button_dlg.AddButton(IDC_CHANGE_DEVICE, L"Change device (F2)", x, y += 24, width, height, VK_F2);
}
//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// Set the callback functions
DXUTSetCallbackDeviceCreated( OnCreateDevice );
DXUTSetCallbackDeviceReset( OnResetDevice );
DXUTSetCallbackDeviceLost( OnLostDevice );
DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackFrameRender( OnFrameRender );
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackKeyboard(OnKeyboardProc);
// TODO: Perform any application-level initialization here
InitDialogs();
// Initialize DXUT and create the desired Win32 window and Direct3D device for the application
DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
DXUTCreateWindow( L"OptimizedMesh" );
DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
// Start the render loop
DXUTMainLoop();
// TODO: Perform any application-level cleanup here
return DXUTGetExitCode();
}
下载示例工程