📄 renderer.cpp
字号:
break;
case D3DFMT_R8G8B8:
case D3DFMT_X8R8G8B8:
ourMode.bitsPerPixel = 24;
break;
case D3DFMT_R5G6B5:
//case D3DFMT_X1R5G5B5:
//case D3DFMT_A1R5G5B5:
//case D3DFMT_A4R4G4B4:
//case D3DFMT_X4R4G4B4:
ourMode.bitsPerPixel = 16;
break;
default:
// Unknown or unrecognized mode - skip it
continue;
}
// Count it, or add it to the list
if (pass == 0) {
// 1st pass - just count it
++videoModeCount;
} else {
// 2nd pass. Actually add it to the list.
// First, we check for duplicates
bool dup = false;
for (int i = 0 ; i < videoModeCount ; ++i) {
VideoMode *v = &videoModeList[i];
if (
(v->xRes == ourMode.xRes) &&
(v->yRes == ourMode.yRes) &&
(v->bitsPerPixel == ourMode.bitsPerPixel) &&
(v->refreshHz == ourMode.refreshHz)
) {
dup = true;
break;
}
}
// Add it, if not a dup
if (!dup) {
videoModeList[videoModeCount] = ourMode;
++videoModeCount;
}
}
// Keep enumerating video modes
}
// Any valid modes found?
if (videoModeCount == 0) {
// Nope - clean up and report failure.
pD3D->Release();
pD3D = NULL;
return 0;
}
// End of first pass?
if (pass == 0) {
// Yep. Allocate list. Notice that we are
// possibly allocating more memory than we
// will need, because there might be duplicates.
// We don't care about minor differences in
// pixel formats with the same bit depth
videoModeList = new VideoMode[videoModeCount];
// Reset count for next pass
videoModeCount = 0;
}
}
// Return number of modes
return videoModeCount;
}
//---------------------------------------------------------------------------
// Renderer::getVideoMode
//
// Returns a video mode, by index
const VideoMode &Renderer::getVideoMode(int index) {
// Make sure list is built
if (getVideoModeCount() < 1) {
ABORT("3D support not detected.");
}
assert(videoModeCount > 0);
assert(pD3D != NULL);
// Index should be in range
assert(index >= 0);
assert(index < videoModeCount);
// Return it
return videoModeList[index];
}
//---------------------------------------------------------------------------
// Renderer::init
//
// Startup the renderer in the specified screen mode. This must be called
// only once, at program startup. You MUST call this before any other
// 3D calls are made.
void Renderer::init(const VideoMode &mode) {
HRESULT result;
// Make sure Direct3D interface is created
getVideoModeCount();
// We should have a D3D object, but not a D3D object
assert(pD3D != NULL);
assert(pD3DDevice == NULL);
// Figure out actual pixel format to use for desired bit depth
int modeIndex = 0;
D3DDISPLAYMODE d3dMode;
for (;;) {
// Get the mode
result = pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT,modeIndex,&d3dMode);
++modeIndex;
// No more modes? Then we couldn't find an appropriate mode
if (FAILED(result)) {
ABORT("Can't find valid video mode for %dx%dx%dbpp", mode.xRes, mode.yRes, mode.bitsPerPixel);
}
// Will this mode do for what they want?
if (d3dMode.Width != mode.xRes) continue;
if (d3dMode.Height != mode.yRes) continue;
if (mode.bitsPerPixel == 16) {
if (d3dMode.Format == D3DFMT_R5G6B5) {
break;
}
} else if (mode.bitsPerPixel == 24) {
if (d3dMode.Format == D3DFMT_R8G8B8) {
break;
}
if (d3dMode.Format == D3DFMT_X8R8G8B8) {
break;
}
} else if (mode.bitsPerPixel == 32) {
if (d3dMode.Format == D3DFMT_A8R8G8B8) {
break;
}
} else {
// Huh? You are asking for an invalid bit depth
assert(false);
}
}
// Figure out Z buffer format. We'll start by assuming
// a 16-bit depth buffer
D3DFORMAT depthBufferFormat = D3DFMT_D16;
// If in higher bit depth, we'll shoot for the depth buffer
// with the most resolution possible
if (mode.bitsPerPixel > 16) {
// First, try a full 32-bit z-buffer.
// if that doesn't work, we'll try a 24-bit
// z-buffer
if (SUCCEEDED(pD3D->CheckDeviceFormat(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
d3dMode.Format,
D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE,
D3DFMT_D32
))) {
depthBufferFormat = D3DFMT_D32;
} else if (SUCCEEDED(pD3D->CheckDeviceFormat(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
d3dMode.Format,
D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE,
D3DFMT_D24S8
))) {
depthBufferFormat = D3DFMT_D24S8;
}
}
// Fill in the "present" parameters
D3DPRESENT_PARAMETERS presentParms;
presentParms.BackBufferWidth = mode.xRes;
presentParms.BackBufferHeight = mode.yRes;
presentParms.Windowed = 0;
presentParms.BackBufferFormat = d3dMode.Format;
presentParms.MultiSampleType = D3DMULTISAMPLE_NONE;
presentParms.EnableAutoDepthStencil = TRUE;
presentParms.AutoDepthStencilFormat = depthBufferFormat;
presentParms.Flags = 0;
presentParms.hDeviceWindow = gHwndApp;
presentParms.BackBufferCount = 2;
presentParms.SwapEffect = D3DSWAPEFFECT_FLIP;
if (mode.refreshHz == kRefreshRateDefault) {
presentParms.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
} else if (mode.refreshHz == kRefreshRateFastest) {
presentParms.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_UNLIMITED;
} else {
assert(mode.refreshHz > 0);
presentParms.FullScreen_RefreshRateInHz = mode.refreshHz;
}
presentParms.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
// Create hardware transform device, hopefully with vertex and
// pixel shader support.
result = pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
gHwndApp,
D3DCREATE_FPU_PRESERVE | D3DCREATE_HARDWARE_VERTEXPROCESSING,
&presentParms,
&pD3DDevice
);
if (!SUCCEEDED(result)) {
// Nope - try falling back on software vertex processing
result = pD3D->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
gHwndApp,
D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&presentParms,
&pD3DDevice
);
if (!SUCCEEDED(result)) {
ABORT("Can't set video mode to %dx%dx%dbpp", mode.xRes, mode.yRes, mode.bitsPerPixel);
}
}
// Remember resolution
screenX = mode.xRes;
screenY = mode.yRes;
// Set a full screen window initially
setFullScreenWindow();
// Clear out any garbage on the screen
for (int i = 0 ; i < 4 ; ++i) {
beginScene();
clear(kClearFrameBuffer | kClearDepthBuffer);
endScene();
flipPages();
}
// Set a default render state
setD3DRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
setD3DRenderState(D3DRS_ZWRITEENABLE, TRUE);
setD3DRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
setD3DRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
setD3DRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
setD3DRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
setD3DRenderState(D3DRS_AMBIENT, ambientLightColor);
setD3DRenderState(D3DRS_FOGENABLE, fogEnable);
setD3DRenderState(D3DRS_FOGCOLOR, fogColor);
setD3DRenderState(D3DRS_FOGSTART, *(DWORD*)(&fogNear));
setD3DRenderState(D3DRS_FOGEND, *(DWORD*)(&fogFar));
setD3DRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
// Set texture wrapping mode
result = pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
assert(SUCCEEDED(result));
result = pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
assert(SUCCEEDED(result));
// Setup the material with the properties that we want
memset(&d3dMaterial, 0, sizeof(d3dMaterial));
d3dMaterial.Diffuse.r = 1.0f;
d3dMaterial.Diffuse.g = 1.0f;
d3dMaterial.Diffuse.b = 1.0f;
d3dMaterial.Diffuse.a = 1.0f;
d3dMaterial.Ambient = d3dMaterial.Diffuse;
d3dMaterial.Specular = d3dMaterial.Diffuse;
d3dMaterial.Power = 50.0f; // arbitrary
// Force upload of the D3D material
constantARGB ^= 0xff000000; // force alpha portion to change
setOpacity(constantOpacity);
// Setup directional light
memset(&d3dDirectionalLight, 0, sizeof(d3dDirectionalLight));
d3dDirectionalLight.Type = D3DLIGHT_DIRECTIONAL;
d3dDirectionalLight.Diffuse.r = GET_R(directionalLightColor) / 255.0f;
d3dDirectionalLight.Diffuse.g = GET_G(directionalLightColor) / 255.0f;
d3dDirectionalLight.Diffuse.b = GET_B(directionalLightColor) / 255.0f;
d3dDirectionalLight.Diffuse.a = 0.0f;
d3dDirectionalLight.Specular = d3dDirectionalLight.Diffuse;
d3dDirectionalLight.Ambient.r = 0.0f;
d3dDirectionalLight.Ambient.g = 0.0f;
d3dDirectionalLight.Ambient.b = 0.0f;
d3dDirectionalLight.Ambient.a = 0.0f;
d3dDirectionalLight.Direction.x = directionalLightVector.x;
d3dDirectionalLight.Direction.y = directionalLightVector.y;
d3dDirectionalLight.Direction.z = directionalLightVector.z;
d3dDirectionalLight.Falloff = 1.0f;
d3dDirectionalLight.Theta = kPi;
d3dDirectionalLight.Phi = kPi;
setD3DDirectionalLight();
// Enable it
result = pD3DDevice->LightEnable(0, TRUE);
assert(SUCCEEDED(result));
// Prepare the texture cache
resetTextureCache();
}
//---------------------------------------------------------------------------
// Renderer::shutdown
//
// Called to shutdown the renderer. This MUST be called at program shutdown
// time, and no other renderer calls may be made after that
void Renderer::shutdown() {
// Free texture resources
freeAllTextures();
// Delete Direct3D device object
if (pD3DDevice != NULL) {
pD3DDevice->Release();
pD3DDevice = NULL;
}
// Delete Direct3D interface
if (pD3D != NULL) {
pD3D->Release();
pD3D = NULL;
}
// Delete list of video modes
delete [] videoModeList;
videoModeList = NULL;
videoModeCount = 0;
}
//---------------------------------------------------------------------------
// Renderer::flipPages
//
// Called when scene rendering is complete, to "present" the back buffer
void Renderer::flipPages() {
// Make sure we have a device
if (pD3DDevice != NULL) {
// Toggle it
HRESULT result = pD3DDevice->Present(NULL,NULL,NULL,NULL);
// We could lose the surface - we'll ignore this error
assert((result == D3DERR_DEVICELOST) || SUCCEEDED(result));
}
// Perform frame-time processing
idle();
}
//---------------------------------------------------------------------------
// Renderer::beginScene
//
// Called at the beginning of the scene. You must call this before any
// rendering primitives.
void Renderer::beginScene() {
// Make sure we have a device
if (pD3DDevice == NULL) {
assert(false);
} else {
// Do it
HRESULT result = pD3DDevice->BeginScene();
assert(SUCCEEDED(result));
}
}
//---------------------------------------------------------------------------
// Renderer::endScene
//
// Called at the end of the scene. You must call this after all
// primitives have been rendered.
void Renderer::endScene() {
// Make sure we have a device
if (pD3DDevice == NULL) {
assert(false);
} else {
// Do it
HRESULT result = pD3DDevice->EndScene();
assert(SUCCEEDED(result));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -