//-----------------------------------------------------------------------------
// File: Vertices.cpp
//
// Desc: In this tutorial, we are rendering some vertices. This introduces the
// concept of the vertex buffer, a Direct3D object used to store
// vertices. Vertices can be defined any way we want by defining a
// custom structure and a custom FVF (flexible vertex format). In this
// tutorial, we are using vertices that are transformed (meaning they
// are already in 2D window coordinates) and lit (meaning we are not
// using Direct3D lighting, but are supplying our own colors).
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
// D3D 디바이스를 생성할 D3D 객체 변수
LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
// 랜더링에 사용될 D3D 디바이스
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
// A structure for our custom vertex type
struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw; // The transformed position for the vertex
DWORD color; // The vertex color
};
// Our custom FVF, which describes our custom vertex structure
// 사용자 정점 구조체에 관한 정보를 나타내는 FVF 값
// 구조체는 X, Y, Z, RHW 값과 Diffuse 색깔값으로 이루어져 있음을 알 수 있다.
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
// Create the D3D object.
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) ); // 사용전 깨끗이~!
d3dpp.Windowed = TRUE; // 창모드로 생성
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 가장 효율적인 SWAP효과
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 현재 바탕화면 모드에 맞춰서 후면 버퍼를 생성
// Create the D3DDevice
// 디바이스를 다음과 같은 설정으로 생성한다.
// 1. 디폴트 비디오카드를 사용한다( 대부분은 비디오 카드가 한개)
// 2. HAL 디바이스를 생성한다( HW 가속장치를 사용하겠다는 의미)
// 3. 정점 처리는 모든 카드에서 지원하는 SW 처리로 생성한다( HW로 생성할경우 더 높은 성능을 냄)
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
// Device state would normally be set here
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InitVB()
// Desc: Creates a vertex buffer and fills it with our vertices. The vertex
// buffer is basically just a chuck of memory that holds vertices. After
// creating it, we must Lock()/Unlock() it to fill it. For indices, D3D
// also uses index buffers. The special thing about vertex and index
// buffers is that they can be created in device memory, allowing some
// cards to process them in hardware, resulting in a dramatic
// performance gain.
//-----------------------------------------------------------------------------
// 정점버퍼(기본적으로 정점 정보를 갖고있는 메모리 블럭 - 정점정보를 정점버퍼에 써넣어야 한다)를
// 생성하고 정점값을 채워넣는다.
// 또한 D3D는 인덱스 버퍼도 사용 가능하다는 것을 명심
// 정점버퍼나 인덱스 버퍼는 기본 시스템 메모리 외에 디바이스 메모리( 비디오카드 메모리)에
// 생성될 수 있는데, 대부분의 비디오카드에서는 이렇게 할 경우 엄청난 속도의 향상을 얻을 수 있다.
//-----------------------------------------------------------------------------
HRESULT InitVB()
{
// Initialize three vertices for rendering a triangle
CUSTOMVERTEX vertices[] =
{
{ 150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
{ 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, }, // 색깔의 경우 0xAARRGGBB의 순서로 값을줌
{ 50.0f, 250.0f, 0.5f, 1.0f, 0xff0000ff, },
};
// Create the vertex buffer. Here we are allocating enough memory
// (from the default pool) to hold all our 3 custom vertices. We also
// specify the FVF, so the vertex buffer knows what data it contains.
// 정점 버퍼를 생성한다.
// * 정점 버퍼는 new나 malloc()등과 다르게 정점처리만을 위해 만들어진 특수한 메모리임.
// 3개의 사용자 정점을 보관할 메모리를 할당한다.
// FVF를 지정하여 보관할 데이터 형식을 지정한다.
// FVF : 사용자가 정점의 구조를 직접 정의하여 사용할 수 있는 방식인
// 사용자 정의 정점형식( Flexible Vertex Format )
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3 * sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
{
return E_FAIL;
}
// Now we fill the vertex buffer. To do this, we need to Lock() the VB to
// gain access to the vertices. This mechanism is required becuase vertex
// buffers may be in device memory.
// 정점 버퍼를 값으로 채운다.
// 정점 버퍼의 Lock() 함수를 호출하여 포인터를 얻어온다.
VOID* pVertices;
// 일단 생성한 정점 버퍼는 쓰레기 값으로 차있기 때문에 값을 넣어줘야한다.
// 그러기 위해서 Lock()을 사용하여 - 실제 정점을 읽고 쓸 수 있도록 "메모리 포인터"를 얻어내야한다.
if( FAILED( g_pVB->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 ) ) )
return E_FAIL;
memcpy( pVertices, vertices, sizeof(vertices) );
g_pVB->Unlock();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
if( g_pVB != NULL )
g_pVB->Release();
if( g_pd3dDevice != NULL ) // g_pd3dDevice는 D3D인터페이스보다 나중에 생성되었다
g_pd3dDevice->Release(); // 해제할때는 반드시 생성순서의 역순으로 해제해줘야한다.
if( g_pD3D != NULL )
g_pD3D->Release();
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
// Clear the backbuffer to a blue color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// Draw the triangles in the vertex buffer. This is broken into a few
// steps. We are passing the vertices down a "stream", so first we need
// to specify the source of that stream, which is our vertex buffer. Then
// we need to let D3D know what vertex shader to use. Full, custom vertex
// shaders are an advanced topic, but in most cases the vertex shader is
// just the FVF, so that D3D knows what type of vertices we are dealing
// with. Finally, we call DrawPrimitive() which does the actual rendering
// of our geometry (in this case, just one triangle).
// 1. 정점 정보가 담겨 있는 정점 버퍼를 출력 스트림으로 할당한다.
// SetStreamSource() 출력할 정점버퍼를 디바이스에 바인딩(결합)한다
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
// 2. D3D에게 정점 셰이더 정보를 지정한다. 대부분의 경우에는 FVF만 지정한다
// SetVertexShader() 로 정점 포맷을 디바이스에 지정한다.
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
// 3. 기하 정보를 출력하기 위한 DrawPrimitive() 함수 호출
// DrawPrimitive()로 정점 버퍼의 폴리곤을 그린다.
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );
// End the scene 랜더링 종료
g_pd3dDevice->EndScene();
}
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
// 간단하다. WM_DESTROY의 처리도 필요없지만 최소한의 함수 모양새를 위해 남겨놓은것임.
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
// Register the window class
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"D3D Tutorial", NULL };
RegisterClassEx( &wc );
// Create the application's window
HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 02: Vertices",
WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
// Initialize Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Create the vertex buffer
if( SUCCEEDED( InitVB() ) )
{
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// Enter the message loop
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
{
// 메시지 큐에 메시지가 있으면 메시지 처리
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
// 처리할 메시지가 없으면 Render() 함수 호출
Render();
}
}
}
// 등록된 클래스 소거
UnregisterClass( "D3D Tutorial", wc.hInstance );
return 0;
}
*******************************
typedef struct _D3DPRESENT_PARAMETERS_
{
UINT BackBufferWidth;
UINT BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
/* FullScreen_RefreshRateInHz must be zero for Windowed mode */
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS;
*******************************
IDirect3D9::CreateDevice Method
HRESULT CreateDevice(
UINT Adapter, // 디바이스를 생성할 화면의 순서번호, 모니터가 두대 이상일때 사용
D3DDEVTYPE DeviceType, // 출력 디바이스의 종류 HAL , SW, REF.
HWND hFocusWindow, // 디바이스가 출력할 윈도우의 핸들, 전체화면일경우 최상위윈도우만 가능
DWORD BehaviorFlags, // 정점셰이더지원때.. ??? 모르겠다. ㅎ
D3DPRESENT_PARAMETERS *pPresentationParameters, // 앞에서 선언한 구조체의 포인터
IDirect3DDevice9** ppReturnedDeviceInterface // IDirect3DDevice9의 인터페이스를 갖고있는 포인터가 담겨돌아온다.
);
*******************************
IDirect3DDevice9::CreateVertexBuffer Method
HRESULT CreateVertexBuffer(
UINT Length, // 생성할 정점버퍼의 바이트 단위 크기
DWORD Usage, // 정점 버퍼의 종류 혹은 처리 방식(SW, HW)지정
DWORD FVF, // 정점 정보 구조체에 따라 선언된 FVF 플래그 값
D3DPOOL Pool, // 정점 버퍼가 저장될 메모리의 위치( 비디오카드, 시스템 메모리)와 관리방식 지정
IDirect3DVertexBuffer9** ppVertexBuffer, // 반환될 정점 버퍼의 인터페이스
HANDLE* pSharedHandle
);
*******************************
IDirect3DVertexBuffer9::Lock Method
HRESULT Lock(
UINT OffsetToLock, // Lock을 할 버퍼의 시작점, SizeToLock과 함께 양쪽 모두 0이면 버퍼 전체
UINT SizeToLock, // Lock을 할 버퍼의 크기, OffsetToLock과 함게 양쪽 모두 0이면 버퍼 점체
VOID **ppbData, // 읽고 쓸 수 있게 된 메모리 영역의 포인터
DWORD Flags // Lock을 수행할 때 함께 사용하는 플래그
);
*******************************
IDirect3DDevice9::DrawPrimitive Method
HRESULT DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType, // 첫번째 전달인자에 따라 다양한 모양의 선을 그림
UINT StartVertex,
UINT PrimitiveCount
);