网格模型高级技术5

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,&g_mesh_attr_sort));
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_STRIPREORDER | D3DXMESH_MANAGED,&g_mesh_strip_reorder));
	
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_VERTEXCACHE | D3DXMESH_MANAGED,&g_mesh_vertex_cache));

渲染优化后的网格模型与未优化的网格模型相比没有任何区别:

// Clear the render target and the zbuffer 
V( pd3dDevice->Clear(0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_ARGB(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,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",&g_adj_buffer,&material_buffer,
&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,
&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,
&g_mesh_attr_sort));

V_RETURN(g_mesh
->Optimize(D3DXMESHOPT_STRIPREORDER | D3DXMESH_MANAGED,
&g_mesh_strip_reorder));

V_RETURN(g_mesh
->Optimize(D3DXMESHOPT_VERTEXCACHE | D3DXMESH_MANAGED,
&g_mesh_vertex_cache));

return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_DEFAULT resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
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);
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, 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.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) );
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,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) );
text_helper.DrawTextLine(L
"Press F1 for help");
}

text_helper.End();
}

//--------------------------------------------------------------------------------------
// Render the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice,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,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_ARGB(0,0),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,lParam);
return 0;
}

*pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd,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)",y += 24,height);
g_button_dlg.AddButton(IDC_CHANGE_DEVICE,L
"Change device (F2)",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,
640, 480,IsDeviceAcceptable,ModifyDeviceSettings );

// Start the render loop
DXUTMainLoop();

// Todo: Perform any application-level cleanup here

return DXUTGetExitCode();
}

下载示例工程

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")