display.h
来自「一个纹理地形渲染器」· C头文件 代码 · 共 1,043 行 · 第 1/2 页
H
1,043 行
// DirectX Display
#pragma once
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "Light.h"
#include "Material.h"
#include "Texture.h"
#include "Mesh.h"
#include "Utility.h"
#include "Timer.h"
#include "LineEmitter.h"
#include "QuadEmitter.h"
#include "System/Key.h"
#include "System/Mouse.h"
#include "System/DisplayAdapter.h"
namespace DirectX
{
typedef System::DisplayAdapter SystemDisplay;
/// %DirectX implementation of %Display
class Display : public System::DisplayAdapter
{
LPDIRECT3D9 _d3d; ///< d3d object
LPDIRECT3DDEVICE9 _device; ///< d3d device
LPD3DXFONT _font; ///< d3dx font to be used for fps rendering
HWND _window; ///< display window handle
typedef std::vector<Light*> Lights; ///< convenient array of lights type
Texture *_texture; ///< current selected texture
Material *_material; ///< current selected material
Lights _lights; ///< array of current selected lights
Mesh *_mesh; ///< current selected mesh
int _translate[256]; ///< translation mapping for key codes
bool _active; ///< true if the window is currently active (in foreground)
bool _stats; ///< controls if rendering stats are displayed
Timer _timer; ///< timer used for fps stats
double _fps; ///< most recent smoothed fps
bool _wireframe; ///< controls if wireframe render mode is engaged
LineEmitter _lineEmitter; ///< line emitter
QuadEmitter _quadEmitter; ///< quad emitter
protected:
/// set members data to defaults
void defaults()
{
_device = 0;
_font = 0;
_window = 0;
_texture = 0;
_material = 0;
_mesh = 0;
_lights.clear();
for (int i=0; i<8; i++) _lights.push_back(0);
_stats = true;
_fps = 60;
_wireframe = false;
_active = false;
}
/// static window procedure mapping to display instance WindowProc via window class user data.
static LRESULT CALLBACK StaticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LONG_PTR extra = GetWindowLongPtr(hWnd, GWL_USERDATA);
if (!extra) return DefWindowProc(hWnd,uMsg,wParam,lParam);
Display *display = (Display*) extra;
return display->WindowProc(hWnd, uMsg, wParam, lParam);
}
/// the actual display instance window procedure
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
ValidateRect(hWnd, NULL);
}
break;
case WM_KEYDOWN:
{
notifyKeyDown(_translate[wParam&0xFF]);
switch (wParam)
{
case VK_DELETE:
_stats = !_stats;
break;
case VK_INSERT:
_wireframe = !_wireframe;
if (_wireframe)
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
else
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
break;
}
}
break;
case WM_KEYUP:
{
notifyKeyUp(_translate[wParam&0xFF]);
}
break;
case WM_LBUTTONDOWN:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
notifyMouseDown(System::Mouse(System::Mouse::LEFT),x,y);
SetCapture(_window);
}
break;
case WM_MBUTTONDOWN:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
notifyMouseDown(System::Mouse(System::Mouse::MIDDLE),x,y);
SetCapture(_window);
}
break;
case WM_RBUTTONDOWN:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
notifyMouseDown(System::Mouse(System::Mouse::RIGHT),x,y);
SetCapture(_window);
}
break;
case WM_LBUTTONUP:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
notifyMouseUp(System::Mouse(System::Mouse::LEFT),x,y);
ReleaseCapture();
}
break;
case WM_MBUTTONUP:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
notifyMouseUp(System::Mouse(System::Mouse::MIDDLE),x,y);
ReleaseCapture();
}
break;
case WM_RBUTTONUP:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
notifyMouseUp(System::Mouse(System::Mouse::RIGHT),x,y);
ReleaseCapture();
}
break;
case WM_MOUSEMOVE:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
notifyMouseMove(System::Mouse(System::Mouse()),x,y);
}
break;
case WM_ACTIVATE:
{
_active = wParam != WA_INACTIVE;
notifyActivate(_active);
}
break;
case WM_CLOSE:
{
if (notifyClose())
{
close();
exit(0);
}
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
public:
/// default constructor.
/// clears member data to defaults and creates d3d object.
Display()
{
defaults();
_d3d = Direct3DCreate9(D3D_SDK_VERSION);
}
/// destructor.
/// closes display and releases d3d object.
virtual ~Display()
{
close();
_d3d->Release();
_d3d = 0;
}
virtual void open(const char title[], int width, int height, bool windowed)
{
close();
SystemDisplay::open(title, width, height, windowed);
// register window class
LOGBRUSH description;
description.lbStyle = BS_SOLID;
description.lbColor = DIB_RGB_COLORS;
description.lbHatch = 0;
HBRUSH black = CreateBrushIndirect(&description);
WNDCLASSEX winclass;
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS;
winclass.lpfnWndProc = &StaticWindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
HINSTANCE instance = GetModuleHandle(0);
winclass.hInstance = instance;
winclass.hIcon = LoadIcon(instance,"SYSTEM_ICON");
winclass.hCursor = LoadCursor(NULL,IDC_ARROW);
winclass.hbrBackground = black;
winclass.lpszMenuName = NULL;
winclass.lpszClassName = title;
winclass.hIconSm = NULL;
UnregisterClass(title, instance);
if (!RegisterClassEx(&winclass)) throw Error("failed to register window class");
// create window
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = width;
rect.bottom = height;
AdjustWindowRect(&rect,WS_OVERLAPPEDWINDOW,0);
rect.right -= rect.left;
rect.bottom -= rect.top;
int x = (GetSystemMetrics(SM_CXSCREEN) - rect.right) >> 1;
int y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) >> 1;
HWND hWnd = CreateWindow(title,title,WS_OVERLAPPEDWINDOW,x,y,rect.right,rect.bottom,NULL,NULL,instance,NULL);
if (!hWnd) throw Error("failed to create window");
SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG)(LONG_PTR) this);
ShowWindow(hWnd,SW_NORMAL);
_window = hWnd;
// create device
if (!_d3d)
throw Error("invalid d3d device");
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
if (!windowed)
{
d3dpp.Windowed = FALSE;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 3;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
}
else
{
D3DDISPLAYMODE mode;
if (FAILED(_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode)))
throw Error("get adapter display mode failed");
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
}
if( FAILED( _d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &_device ) ) )
{
if( FAILED( _d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &_device ) ) )
{
HRESULT result = _d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &_device );
if (result!=D3D_OK)
{
switch (result)
{
case D3DERR_INVALIDCALL: throw Error("failed to create device - invalid call");
case D3DERR_NOTAVAILABLE: throw Error("failed to create device - not available");
case D3DERR_OUTOFVIDEOMEMORY: throw Error("failed to create device - out of video memory");
}
throw Error("failed to create device");
}
}
}
// create font
assert(_device);
D3DXCreateFont(_device,(HFONT)GetStockObject(SYSTEM_FONT),&_font);
if (!_font) throw Error("failed to create font");
// initialize states
if (_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR) != D3D_OK) throw Error("set texture magfilter failed");
if (_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR) != D3D_OK) throw Error("set texture minfilter failed");
if (_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR) != D3D_OK) throw Error("set texture mipfilter failed");
if (_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW) != D3D_OK)
throw Error("set cull mode failed");
if (_device->SetRenderState(D3DRS_ZENABLE, TRUE) != D3D_OK) throw Error("depth buffer enable failed");
if (_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE) != D3D_OK) throw Error("depth buffer write enable failed");
if (_device->SetFVF(D3DFVF_VERTEX) != D3D_OK)
throw Error("set vertex shader failed");
if (_device->SetRenderState(D3DRS_LIGHTING, TRUE) != D3D_OK)
throw Error("enable lighting failed");
if (_device->SetRenderState(D3DRS_AMBIENT, 0xFFFFFFFF) != D3D_OK)
throw Error("enable ambient lighting failed");
if (_device->SetRenderState(D3DRS_SPECULARENABLE, TRUE) != D3D_OK)
throw Error("enable specular lighting failed");
_device->SetRenderState(D3DRS_NORMALIZENORMALS, FALSE);
// clear back buffers
clear(Color(0,0,0), 1.0f, 0);
update();
clear(Color(0,0,0), 1.0f, 0);
update();
clear(Color(0,0,0), 1.0f, 0);
update();
// setup win32 key translation table
for (int i=0; i<256; i++) _translate[i] = i;
_translate[219] = System::Key::OPENBRACKET;
_translate[221] = System::Key::CLOSEBRACKET;
_translate[220] = System::Key::BACKSLASH;
_translate[13] = System::Key::ENTER;
_translate[187] = System::Key::EQUALS;
_translate[189] = System::Key::SEPARATOR;
_translate[186] = System::Key::SEMICOLON;
_translate[191] = System::Key::SLASH;
_translate[190] = System::Key::PERIOD;
_translate[188] = System::Key::COMMA;
_translate[45] = System::Key::INSERT;
#undef DELETE
_translate[46] = System::Key::DELETE;
// initialize emitters
_lineEmitter.initialize(_device, 1024);
_quadEmitter.initialize(_device, 1024);
}
virtual void close()
{
_lineEmitter.release();
_quadEmitter.release();
if (_window) DestroyWindow(_window);
if (_font) _font->Release();
if (_device) _device->Release();
defaults();
}
virtual bool valid() const
{
return _d3d && _device && _window && _font;
}
virtual void begin()
{
assert(_device);
if (_device->BeginScene()!=D3D_OK)
throw Error("begin scene failed");
}
virtual void end()
{
assert(_font);
assert(_device);
_timer.time();
double delta = _timer.delta();
double fps = 1.0 / delta;
_fps += (fps - _fps) * 0.05;
if (_stats)
{
char str[64];
sprintf(str,"%.2f fps", _fps);
_font->Begin();
RECT r; r.top=10;r.left=10;r.bottom=40;r.right=100;
_font->DrawText(str,-1,&r,DT_LEFT|DT_TOP,0xFFFFFFFF);
_font->End();
}
if (_device->EndScene()!=D3D_OK)
throw Error("end scene failed");
}
virtual void clear(const Color &color, float depth, unsigned int stencil)
{
assert(_device);
if (_device->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL , color.packed(), depth, stencil) != D3D_OK) throw Error("clear failed");
}
virtual void update()
{
assert(_device);
SystemDisplay::update();
MSG message;
while (true)
{
if (_active)
{
if (!PeekMessage(&message,_window,0,0,PM_REMOVE)) break;
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
if (!GetMessage(&message,_window,0,0)) break;
TranslateMessage(&message);
DispatchMessage(&message);
}
}
if (_device->Present( NULL, NULL, NULL, NULL ) != D3D_OK) throw Error("present failed");
Sleep(0);
}
virtual int numberOfLights() const
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?