立体纹理(volume texture)是一组应用到二维图元(如一个三角形或一条直线)的三维纹理元素的集合,可以使用立体纹理实现一些特殊效果,如迷雾、爆炸等。当对一个图元使用立体纹理时,它的每个顶点都需要一组三元纹理坐标。当绘制该图元时,它中间的每个像素都将用立体纹理中的一些纹理元素的颜色值进行填充,这与二维纹理映射的情况相似。
立体纹理以薄片为单元组织起来,可以把它想象成将(宽 x 高)的二维表面转换成(宽 x 高 x 深)的三维立体,每个薄片是单独的一行,立体纹理可以有一系列级别,每一级都较上一级缩小一倍,如下图所示:
要创建立体纹理,首先必须检查显卡是否支持立体纹理:
// check whether device support volume texture
if((pCaps->TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0)
return false;
接着,我们需要在灵活顶点格式中指定每个顶点都需要三个纹理坐标,如下所示:
struct sCustomVertex
{
float x, y, z;
float u, v, w;
};
#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0))
D3DFVF_TEXCOORDSIZEN
Constructs bit patterns that are used to identify texture coordinate formats within a FVF description. The results of these macros can be combined within a FVF description by using the OR operator.
#define D3DFVF_TEXCOORDSIZEN(CoordIndex)
#define D3DFVF_TEXCOORDSIZE1(CoordIndex) (D3DFVF_TEXTUREFORMAT1 << (CoordIndex*2 + 16))
#define D3DFVF_TEXCOORDSIZE2(CoordIndex) (D3DFVF_TEXTUREFORMAT2)
#define D3DFVF_TEXCOORDSIZE3(CoordIndex) (D3DFVF_TEXTUREFORMAT3 << (CoordIndex*2 + 16))
#define D3DFVF_TEXCOORDSIZE4(CoordIndex) (D3DFVF_TEXTUREFORMAT4 << (CoordIndex*2 + 16))
Parameters
- CoordIndex
- Value that identifies the texture coordinate set at which the texture coordinate size (1-, 2-, 3-, or 4Dimensional) applies.
Remarks
The D3DFVF_TEXCOORDSIZEN macros use the following constants.
#define D3DFVF_TEXTUREFORMAT1 3 // one floating point value
#define D3DFVF_TEXTUREFORMAT2 0 // two floating point values
#define D3DFVF_TEXTUREFORMAT3 1 // three floating point values
#define D3DFVF_TEXTUREFORMAT4 2 // four floating point values
The following FVF description identifies a vertex format that has a position; a normal; diffuse and specular colors; and two sets of texture coordinates. The first set of texture coordinates includes a single element, and the second set includes two elements:
DWORD dwFVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE |
D3DFVF_SPECULAR | D3DFVF_TEX2 |
D3DFVF_TEXCOORDSIZE1(0) | // Uses 1D texture coordinates for texture coordinate set 1 (index 0).
D3DFVF_TEXCOORDSIZE2(1); // And 2D texture coordinates for texture coordinate set 2 (index 1).
接着,为每个顶点指定数据,创建顶点缓冲区并填充它:
// create vertex buffer and fill data
sCustomVertex vertices[] =
{
{ -3.0f, -3.0f, 0.0f, 0.0f, 1.0f, 0.0f},
{ -3.0f, 3.0f, 0.0f, 0.0f, 0.0f, 0.0f},
{ 3.0f, -3.0f, 0.0f, 1.0f, 1.0f, 0.0f},
{ 3.0f, 3.0f, 0.0f, 1.0f, 0.0f, 0.0f}
};
pd3dDevice->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_MANAGED, &g_vertex_buffer, NULL);
void* ptr;
g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);
memcpy(ptr, vertices, sizeof(vertices));
g_vertex_buffer->Unlock();
可通过IDirect3DDevice9::CreateVolumeTexture()来创建立体纹理,该函数声明如下:
Creates a volume texture resource.
HRESULT CreateVolumeTexture(
UINT Width,
UINT Height,
UINT Depth,
UINT Levels,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DVolumeTexture9** ppVolumeTexture,
HANDLE* pSharedHandle
);
Parameters
- Width
- [in] Width of the top-level of the volume texture, in pixels. This value must be a power of two if the D3DPTEXTURECAPS_VOLUMEMAP_POW2 member of D3DCAPS9 is set. The pixel dimensions of subsequent levels will be the truncated value of half of the previous level's pixel dimension (independently). Each dimension clamps at a size of 1 pixel. Thus, if the division by two results in 0 (zero), 1 will be taken instead. The maximum dimension that a driver supports (for width, height, and depth) can be found in MaxVolumeExtent in D3DCAPS9.
- Height
- [in] Height of the top-level of the volume texture, in pixels. This value must be a power of two if the D3DPTEXTURECAPS_VOLUMEMAP_POW2 member of D3DCAPS9 is set. The pixel dimensions of subsequent levels will be the truncated value of half of the previous level's pixel dimension (independently). Each dimension clamps at a size of 1 pixel. Thus, if the division by 2 results in 0 (zero), 1 will be taken instead. The maximum dimension that a driver supports (for width, height, and depth) can be found in MaxVolumeExtent in D3DCAPS9.
- Depth
- [in] Depth of the top-level of the volume texture, in pixels. This value must be a power of two if the D3DPTEXTURECAPS_VOLUMEMAP_POW2 member of D3DCAPS9 is set. The pixel dimensions of subsequent levels will be the truncated value of half of the previous level's pixel dimension (independently). Each dimension clamps at a size of 1 pixel. Thus, if the division by 2 results in 0 (zero), 1 will be taken instead. The maximum dimension that a driver supports (for width, height, and depth) can be found in MaxVolumeExtent in D3DCAPS9.
- Levels
- [in] Number of levels in the texture. If this is zero, Direct3D will generate all texture sublevels down to 1x1 pixels for hardware that supports mipmapped volume textures. Call IDirect3DBaseTexture9::GetLevelCount to see the number of levels generated.
- Usage
- [in] Usage can be 0, which indicates no usage value. If usage is desired, use D3DUSAGE_DYNAMIC or D3DUSAGE_SOFTWAREPROCESSING. For more information, see D3DUSAGE.
- Format
- [in] Member of the D3DFORMAT enumerated type, describing the format of all levels in the volume texture.
- Pool
- [in] Member of the D3DPOOL enumerated type, describing the memory class into which the volume texture should be placed.
- ppVolumeTexture
- [out, retval] Address of a pointer to an IDirect3DVolumeTexture9 interface, representing the created volume texture resource.
- pSharedHandle
- [in] Reserved. Set this parameter to NULL.
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, D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY.
示例代码如下:
HRESULT hr;
UINT width = 16, height = 16, depth = 16;
V_RETURN(device->CreateVolumeTexture(width, height, depth, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
&g_volume_texture, NULL));
接着调用IDirect3DVolumeTexture9::LockBox()来锁定立体纹理顶点缓冲区,该函数的声明如下:
Locks a box on a volume texture resource.
HRESULT LockBox(
UINT Level,
D3DLOCKED_BOX * pLockedVolume,
CONST D3DBOX * pBox,
DWORD Flags
);
Parameters
- Level
- [in] Specifies the level of the volume texture resource to lock.
- pLockedVolume
- [out] Pointer to a D3DLOCKED_BOX structure, describing the locked region.
- pBox
- [in] Pointer to the volume to lock. This parameter is specified by a pointer to a D3DBOX structure. Specifying NULL for this parameter locks the entire volume level.
- Flags
- [in] Combination of zero or more locking flags that describe the type of lock to perform. For this method, the valid flags are:
- D3DLOCK_DISCARD
- D3DLOCK_NO_DIRTY_UPDATE
- D3DLOCK_NOSYSLOCK
- D3DLOCK_READONLY
Return Values
If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.
Remarks
For performance reasons, dirty regions are only recorded for level zero of a texture. Dirty regions are automatically recorded when IDirect3DVolumeTexture9::LockBox is called without D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_READONLY. For more information, see IDirect3DDevice9::UpdateTexture.
D3DLOCKED_BOX
Describes a locked box (volume).
typedef struct D3DLOCKED_BOX {
int RowPitch;
int SlicePitch;
void * pBits;
} D3DLOCKED_BOX, *LPD3DLOCKED_BOX;
Members
- RowPitch
- Byte offset from the left edge of one row to the left edge of the next row.
- SlicePitch
- Byte offset from the top-left of one slice to the top-left of the next deepest slice.
- pBits
- Pointer to the beginning of the volume box. If a D3DBOX was provided to the LockBox call, pBits will be appropriately offset from the start of the volume.
Remarks
Volumes can be visualized as being organized into slices of width x height 2D surfaces stacked up to make a width x height x depth volume. For more information, see Volume Texture Resources (Direct3D 9).
D3DBOX
Defines a volume.
typedef struct D3DBOX {
UINT Left;
UINT Top;
UINT Right;
UINT Bottom;
UINT Front;
UINT Back;
} D3DBOX, *LPD3DBOX;
Members
- Left
- Position of the left side of the box on the x-axis.
- Top
- Position of the top of the box on the y-axis.
- Right
- Position of the right side of the box on the x-axis.
- Bottom
- Position of the bottom of the box on the y-axis.
- Front
- Position of the front of the box on the z-axis.
- Back
- Position of the back of the box on the z-axis.
Remarks
D3DBOX includes the left, top, and front edges; however, the right, bottom, and back edges are not included. For example, a box that is 100 units wide and begins at 0 (thus, including the points up to and including 99) would be expressed with a value of 0 for the Left member and a value of 100 for the Right member. Note that a value of 99 is not used for the Right member.
The restrictions on side ordering observed for D3DBOX are left to right, top to bottom, and front to back.
示例代码如下:
D3DLOCKED_BOX locked_box;
g_volume_texture->LockBox(0, &locked_box, NULL, 0);
for(UINT w = 0; w < depth; w++)
{
BYTE* slice_start = (BYTE*) locked_box.pBits;
for(UINT v = 0; v < height; v++)
{
for(UINT u = 0; u < width; u++)
{
// create texel color and fill it
float du = (u - 7.5f) / 7.5f;
float dv = (v - 7.5f) / 7.5f;
float dw = (w - 7.5f) / 7.5f;
float scale = sqrt(du * du + dv * dv + dw * dw);
if(scale > 1.0f)
scale = 0.0f;
else
scale = 1.0f - scale;
DWORD r = (DWORD)((w << 4) * scale);
DWORD g = (DWORD)((v << 4) * scale);
DWORD b = (DWORD)((u << 4) * scale);
((DWORD*) locked_box.pBits)[u] = 0xFF000000 + (r << 16) + (g << 8) + b;
}
locked_box.pBits = (BYTE*) locked_box.pBits + locked_box.RowPitch;
}
locked_box.pBits = slice_start + locked_box.SlicePitch;
}
g_volume_texture->UnlockBox(0);
还必须对立体纹理缓冲区进行解锁,这需要调用IDirect3DVolumeTexture9::UnlockBox(),代码如上所示,该函数声明如下:
Unlocks a box on a volume texture resource.
HRESULT UnlockBox(
UINT Level
);
Parameters
- Level
- [in] Specifies the level of the volume texture resource to unlock.
Return Values
If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.
为了生成立体纹理,还必须改变纹理的w坐标:
//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
// change w coordinate of volume texture
float angle = (float) fTime / 2.0f;
sCustomVertex* ptr;
g_vertex_buffer->Lock(0, 0, (void**)&ptr, 0);
for(int i = 0; i < 4; i++)
ptr[i].w = sin(angle) * sin(angle);
g_vertex_buffer->Unlock();
}
最后设置要渲染的纹理层和立体纹理,纹理阶段混合方法,顶点数据,并渲染它:
// set textue and stream source and vertex format
pd3dDevice->SetTexture(0, g_volume_texture);
pd3dDevice->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
pd3dDevice->SetFVF(D3DFVF_CUSTOM_VERTEX);
// set texture color blend method
pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
// 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() ) )
{
pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
RenderText();
V(g_button_dlg.OnRender(fElapsedTime));
V( pd3dDevice->EndScene() );
}
运行效果图:
立体纹理和普通二维纹理的主要区别是:顶点纹理坐标是三维的,纹理对象指针的类型不同,立体纹理的创建也不同,而立体纹理在使用上和普通二维纹理基本相同。
在示例程序中,立体纹理是由程序生成的,比较复杂。Direct3D提供了辅助函数D3DXCreateVolumeTextureFromFile()来从图片文件中生成立体纹理,该函数的声明如下:
Creates a volume texture from a file.
HRESULT D3DXCreateVolumeTextureFromFile(
LPDIRECT3DDEVICE9 pDevice,
LPCTSTR pSrcFile,
LPDIRECT3DVOLUMETEXTURE9 * ppVolumeTexture
);
Parameters
- pDevice
- [in] Pointer to an IDirect3DDevice9 interface, representing the device to be associated with the volume texture.
- pSrcFile
- [in] Pointer to a string that specifies the file name. If the compiler settings require Unicode, the data type LPCTSTR resolves to LPCWSTR. Otherwise, the string data type resolves to LPCSTR. See Remarks.
- ppVolumeTexture
- [out] Address of a pointer to an IDirect3DVolumeTexture9 interface representing the created texture object.
Return Values
If the function succeeds, the return value is D3D_OK. If the function fails, the return value can be one of the following:
D3DERR_NOTAVAILABLED3DERR_OUTOFVIDEOMEMORY
D3DERR_INVALIDCALL
D3DXERR_INVALIDDATAE_OUTOFMEMORY
Remarks
The compiler setting also determines the function version. If Unicode is defined, the function call resolves to D3DXCreateVolumeTextureFromFileW. Otherwise, the function call resolves to D3DXCreateVolumeTextureFromFileA because ANSI strings are being used.
The function is equivalent to D3DXCreateVolumeTextureFromFileEx(pDevice, pSrcFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, ppVolumeTexture).
This function supports the following file formats: .bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm, and .tga. See D3DXIMAGE_FILEFORMAT.
Mipmapped textures automatically have each level filled with the loaded texture.
When loading images into mipmapped textures, some devices are unable to go to a 1x1 image and this function will fail. If this happens, then the images need to be loaded manually.
Note that a resource created with this function will be placed in the memory class denoted by D3DPOOL_MANAGED.
Filtering is automatically applied to a texture created using this method. The filtering is equivalent to D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER in D3DX_FILTER.
通过文件创建立体纹理时文件格式必须是立体纹理格式,对于普通格式的图片文件,可以通过DirectX提供的纹理工具"DirectX Texture Tool"转换成立体纹理格式的文件。
主程序:
#include "resource.h"
#pragma warning(disable : 4127 4995 4996)
#define release_com(p) do { if(p) { (p)->Release(); (p) = NULL; } } while(0)
#define IDC_TOGGLE_FULLSCREEN 1
#define IDC_TOGGLE_REF 2
#define IDC_CHANGE_DEVICE 3
struct sCustomVertex
{
float x, y, z;
float u, v, w;
};
#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0))
const D3DXCOLOR FONT_COLOR(1.0f, 0.5f, 0.25f, 1.0f);
ID3DXFont* g_font;
ID3DXSprite* g_text_sprite;
bool g_show_help;
CDXUTDialogResourceManager g_dlg_resource_manager;
CD3DSettingsDlg g_settings_dlg;
CDXUTDialog g_button_dlg;
IDirect3DVertexBuffer9* g_vertex_buffer;
IDirect3DVolumeTexture9* g_volume_texture;
//--------------------------------------------------------------------------------------
// 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;
// check whether device support volume texture
if((pCaps->TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0)
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;
}
//--------------------------------------------------------------------------------------
// Create volume texture and fill data.
//--------------------------------------------------------------------------------------
HRESULT CreateVolumeTexture(IDirect3DDevice9* device)
{
HRESULT hr;
UINT width = 16, height = 16, depth = 16;
V_RETURN(device->CreateVolumeTexture(width, height, depth, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
&g_volume_texture, NULL));
D3DLOCKED_BOX locked_box;
g_volume_texture->LockBox(0, &locked_box, NULL, 0);
for(UINT w = 0; w < depth; w++)
{
BYTE* slice_start = (BYTE*) locked_box.pBits;
for(UINT v = 0; v < height; v++)
{
for(UINT u = 0; u < width; u++)
{
// create texel color and fill it
float du = (u - 7.5f) / 7.5f;
float dv = (v - 7.5f) / 7.5f;
float dw = (w - 7.5f) / 7.5f;
float scale = sqrt(du * du + dv * dv + dw * dw);
if(scale > 1.0f)
scale = 0.0f;
else
scale = 1.0f - scale;
DWORD r = (DWORD)((w << 4) * scale);
DWORD g = (DWORD)((v << 4) * scale);
DWORD b = (DWORD)((u << 4) * scale);
((DWORD*) locked_box.pBits)[u] = 0xFF000000 + (r << 16) + (g << 8) + b;
}
locked_box.pBits = (BYTE*) locked_box.pBits + locked_box.RowPitch;
}
locked_box.pBits = slice_start + locked_box.SlicePitch;
}
g_volume_texture->UnlockBox(0);
return S_OK;
}
//--------------------------------------------------------------------------------------
// 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);
// create vertex buffer and fill data
sCustomVertex vertices[] =
{
{ -3.0f, -3.0f, 0.0f, 0.0f, 1.0f, 0.0f},
{ -3.0f, 3.0f, 0.0f, 0.0f, 0.0f, 0.0f},
{ 3.0f, -3.0f, 0.0f, 1.0f, 1.0f, 0.0f},
{ 3.0f, 3.0f, 0.0f, 1.0f, 0.0f, 0.0f}
};
pd3dDevice->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_MANAGED, &g_vertex_buffer, NULL);
void* ptr;
g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);
memcpy(ptr, vertices, sizeof(vertices));
g_vertex_buffer->Unlock();
return CreateVolumeTexture(pd3dDevice);
}
//--------------------------------------------------------------------------------------
// 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 world matrix
D3DXMATRIX mat_world;
D3DXMatrixIdentity(&mat_world);
pd3dDevice->SetTransform(D3DTS_WORLD, &mat_world);
// setup view matrix
D3DXMATRIX mat_view;
D3DXVECTOR3 eye(0.0f, 0.0f, -8.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);
// set textue and stream source and vertex format
pd3dDevice->SetTexture(0, g_volume_texture);
pd3dDevice->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
pd3dDevice->SetFVF(D3DFVF_CUSTOM_VERTEX);
// set texture color blend method
pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
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();
release_com(g_font);
release_com(g_vertex_buffer);
release_com(g_volume_texture);
}
//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
// change w coordinate of volume texture
float angle = (float) fTime / 2.0f;
sCustomVertex* ptr;
g_vertex_buffer->Lock(0, 0, (void**)&ptr, 0);
for(int i = 0; i < 4; i++)
ptr[i].w = sin(angle) * sin(angle);
g_vertex_buffer->Unlock();
}
//--------------------------------------------------------------------------------------
// 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(FONT_COLOR);
text_helper.DrawTextLine( DXUTGetFrameStats(true) );
text_helper.DrawTextLine( DXUTGetDeviceStats() );
// show helper information
const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();
if(g_show_help)
{
text_helper.SetInsertionPos(10, surface_desc->Height - 18 * 5);
text_helper.SetForegroundColor(FONT_COLOR);
text_helper.DrawTextLine(L"Controls (F1 to hide):");
text_helper.SetInsertionPos(40, surface_desc->Height - 18 * 4);
text_helper.DrawTextLine(L"Quit: ESC");
}
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() ) )
{
pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
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;
}
}
}
//--------------------------------------------------------------------------------------
// 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"Create Volume Texture" );
DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
// Start the render loop
DXUTMainLoop();
// TODO: Perform any application-level cleanup here
return DXUTGetExitCode();
}