Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

RAWR Dorking around with DirectX and C++


AeroEBrown
 Share

Recommended Posts

I am actually looking for some comments on this, as I am not very great with C++ yet.

```

// ------------------------------------------------------------------

// ---- ----

// ---- Basic Loading of Required Dependencies ----

// ---- ----

// ------------------------------------------------------------------

// Include the basic headers we need, the Windows API headers, and the DirectX 9 headers.

#include

#include

#include

#include

#include

#include

#include

#include

// Include the DirectX 9 libraries.

#pragma comment (lib, "d3d9.lib")

#pragma comment (lib, "d3dx9.lib")

// ------------------------------------------------------------------

// ---- ----

// ---- Constants, Structs, Globals, and Prototypes ----

// ---- ----

// ------------------------------------------------------------------

// Define Constants

const int kScreenWidth = 1024;

const int kScreenHeight = 768;

const bool kFullscreen = false;

const int kTileCount = 2;

const int kSpriteCount = 1;

const int kDistanceToNextMovement = 32;

const int kMeasureFrameCount = 60;

// Global Properties/Variables

LPDIRECT3D9 gDirect3D;

LPDIRECT3DDEVICE9 gDirect3DDevice;

ID3DXSprite * gDirect3DXSprite;

ID3DXFont * gDirectXFont;

LPDIRECT3DTEXTURE9 * gTiles, * gSprites;

D3DXVECTOR3 gPlayerPosition = D3DXVECTOR3(0, 0, 0), gPlayerPositionDisplay = D3DXVECTOR3(0, 0, 0);

byte gPlayerDirection = 0; // 0 = Down, 1 = Left, 2 = Right, 3 = Up

bool * gBrokenTiles, * gBrokenSprites, gIsPlayerRunning = false, gIsDebugMode = false, gPauseGame = false;

int gCurrentTileAnimation = 0, gCurrentFrame = 0;

float gTimePerFrame = 0, frameSum = 0, gFrameTimes[kMeasureFrameCount];

clock_t gFrameBeginTime, gFrameEndTime;

RECT gTextRect = {0, 0, kScreenWidth, kScreenHeight},

gPlayerAnimationSources [1][16] = {{{0, 0, 32, 48},{32, 0, 64, 48},{64, 0, 96, 48},{96, 0, 128, 48},

{0, 48, 32, 96},{32, 48, 64, 96},{64, 48, 96, 96},{96, 48, 128, 96},

{0, 96, 32, 144},{32, 96, 64, 144},{64, 96, 96, 144},{96, 96, 128, 144},

{0, 144, 32, 192},{32, 144, 64, 192},{64, 144, 96, 192},{96, 144, 128, 192}}};

// Function Prototypes

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

void InitializeDirect3D(HWND hWnd);

void InitializeGraphics(void);

void LoadContent(void);

void RenderFrame(void);

void CleanDirect3D(void);

void UpdateGameLogic(void);

// ------------------------------------------------------------------

// ---- ----

// ---- Basic Window Control and Draw Functions ----

// ---- ----

// ------------------------------------------------------------------

// Basic Entry point for Windows Programs.

int WINAPI WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

// Setup the Window Handle.

HWND hWnd;

// This will hold our Window's Information.

WNDCLASSEX wc;

// Set the Window Information to Null.

ZeroMemory(&wc, sizeof(WNDCLASSEX));

// Setup the properties we need.

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = CS_HREDRAW | CS_VREDRAW;

wc.lpfnWndProc = WindowProc;

wc.hInstance = hInstance;

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.lpszClassName = "MyWindowClass";

// Remove the background color from fullscreen.

if (!kFullscreen)

wc.hbrBackground = (HBRUSH)COLOR_WINDOW;

// Tell Windows we have a window.

RegisterClassEx(&wc);

// Now let's create the window.

hWnd = CreateWindowEx(NULL,

"MyWindowClass", // name of the window class

"DirectX 3D version 9, with Sprites", // title of the window

WS_EX_TOPMOST | WS_POPUP, // window style, WS_EX_TOPMOST | WS_POPUP, WS_OVERLAPPEDWINDOW

0, // x-position of the window

0, // y-position of the window

kScreenWidth, // width of the window

kScreenHeight, // height of the window

NULL, // we have no parent window, NULL

NULL, // we aren't using menus, NULL

hInstance, // application handle

NULL); // used with multiple windows, NULL

// Display our Window to the world!

ShowWindow(hWnd, nCmdShow);

// Setup DirectX 3D.

InitializeDirect3D(hWnd);

// Hold our Window's Messages.

MSG msg;

// Enter the infinite message loop

while(TRUE)

{

// Setup FPS start time.

gFrameBeginTime = clock();

// Check to see if any messages are waiting in the queue

while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

// Translate the message and dispatch it to WindowProc()

TranslateMessage(&msg);

DispatchMessage(&msg);

}

// If the message is WM_QUIT, exit the while loop

if(msg.message == WM_QUIT)

break;

// If the game isn't paused...

if (!gPauseGame)

{

// Update game logic.

UpdateGameLogic();

// Render our Graphics.

RenderFrame();

}

// Setup FPS end time.

gFrameEndTime = clock();

// Add to the current frame.

if (gCurrentFrame >= kMeasureFrameCount)

gCurrentFrame = 0;

else

++gCurrentFrame;

// Give us the time for this frame.

gTimePerFrame = ((gFrameEndTime - gFrameBeginTime) * 10);

// Update the frametime.

gFrameTimes[gCurrentFrame] = gTimePerFrame;

}

// Loop's over. Clean our Direct3D.

CleanDirect3D();

// Return something, usually WM_QUIT.

return msg.wParam;

}

// This function will handle messages.

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

// Find what message it was.

switch(message)

{

// It was a standard Character.

case WM_CHAR:

{

// Let's get the full parameters on the character.

switch ((char)(wchar_t)wParam)

{

case 'w':

{

// Is the y within 4 pixels from the bottom?

if (gPlayerPosition.y - gPlayerPositionDisplay.y >= -kDistanceToNextMovement && gPlayerPosition.x == gPlayerPositionDisplay.x)

{

// Yes. They may move up.

gPlayerPosition.y = gPlayerPosition.y - 32;

gPlayerDirection = 3;

}

} break;

case 'a':

{

// Is the x within 4 pixels from the bottom?

if (gPlayerPosition.x - gPlayerPositionDisplay.x >= -kDistanceToNextMovement && gPlayerPosition.y == gPlayerPositionDisplay.y)

{

// Yes. They may move left.

gPlayerPosition.x = gPlayerPosition.x - 32;

gPlayerDirection = 1;

}

} break;

case 's':

{

// Is the y within 4 pixels from the top?

if (gPlayerPosition.y - gPlayerPositionDisplay.y <= kDistanceToNextMovement && gPlayerPosition.x == gPlayerPositionDisplay.x)

{

// Yes. They may move down.

gPlayerPosition.y = gPlayerPosition.y + 32;

gPlayerDirection = 0;

}

} break;

case 'd':

{

// Is the x within 4 pixels from the top?

if (gPlayerPosition.x - gPlayerPositionDisplay.x <= kDistanceToNextMovement && gPlayerPosition.y == gPlayerPositionDisplay.y)

{

// Yes. They may move right.

gPlayerPosition.x = gPlayerPosition.x + 32;

gPlayerDirection = 2;

}

} break;

case 'z':

{

gPauseGame = !gPauseGame;

} break;

case 27: // Escape Key

{

PostQuitMessage(0);

} break;

}

} break;

// Standard Keypress not handled by a Character.

case WM_KEYDOWN:

{

// We need the full parameters.

switch (wParam)

{

case VK_SHIFT: // Shift Key

{

gIsPlayerRunning = !gIsPlayerRunning;

} break;

case VK_F1:

{

gIsDebugMode = !gIsDebugMode;

} break;

}

} break;

// This means we are shutting down.

case WM_DESTROY:

{

// Kill our Application.

PostQuitMessage(0);

return 0;

} break;

}

// Handle any messages the switch statement didn't

return DefWindowProc (hWnd, message, wParam, lParam);

}

// ------------------------------------------------------------------

// ---- ----

// ---- DirectX Control and Draw Functions ----

// ---- ----

// ------------------------------------------------------------------

// This function initializes the DirectX interfaces.

void InitializeDirect3D(HWND hWnd)

{

// Create our DirectX 3D 9 interface.

gDirect3D = Direct3DCreate9(D3D_SDK_VERSION);

// Create the Presentation Parameters.

D3DPRESENT_PARAMETERS d3dpp;

// Clear the Presentation Parameters to null.

ZeroMemory(&d3dpp, sizeof(d3dpp));

// Setup the Presentation Parameters we need. Discard old frames, send the window handle.

d3dpp.Windowed = !kFullscreen;

d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;// D3DSWAPEFFECT_DISCARD;

d3dpp.hDeviceWindow = hWnd;

d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; // 64-Bit Color: D3DFMT_A16B16G16R16, 32-Bit Color With Transparency: D3DFMT_A8R8G8B8, 32-Bit Color Short Alpha: D3DFMT_A2R10G10B10, 32-Bit Color No Alpha: D3DFMT_X8R8G8B8

d3dpp.BackBufferWidth = kScreenWidth;

d3dpp.BackBufferHeight = kScreenHeight;

d3dpp.BackBufferCount = 3;

//d3dpp.FullScreen_RefreshRateInHz = 75;

//d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

// Create the DirectX 3D 9 Device with our Presentation Parameters.

gDirect3D->CreateDevice(D3DADAPTER_DEFAULT,

D3DDEVTYPE_HAL,

hWnd,

D3DCREATE_HARDWARE_VERTEXPROCESSING,

&d3dpp,

&gDirect3DDevice);

// Initialize our Graphics.

InitializeGraphics();

}

// This function initializes the DirectX graphics.

void InitializeGraphics(void)

{

// Create the sprite object.

D3DXCreateSprite(gDirect3DDevice, &gDirect3DXSprite);

// Create the Font Object.

D3DXCreateFont(gDirect3DDevice,

24,

0,

FW_BOLD,

1,

false,

DEFAULT_CHARSET,

OUT_DEFAULT_PRECIS,

DEFAULT_QUALITY,

DEFAULT_PITCH | FF_DONTCARE,

"Courier New",

&gDirectXFont);

// Load our content.

LoadContent();

}

// This function loads the content into the sprite textures.

void LoadContent(void)

{

// Setup the Tiles Variables.

gTiles = new LPDIRECT3DTEXTURE9 [kTileCount];

gBrokenTiles = new bool [kTileCount];

// Setup the Sprites Variables.

gSprites = new LPDIRECT3DTEXTURE9 [kSpriteCount];

gBrokenSprites = new bool [kSpriteCount];

// Loop through all the tiles

for (int i = 0; i < kTileCount; i++)

{

// Setup and create the string.

char fileName [32];

sprintf(fileName, "%d.bmp", i);

// Create the texture.

int result = D3DXCreateTextureFromFileEx(

gDirect3DDevice, // Our DirectX Device

fileName, // Our texture image!

D3DX_DEFAULT_NONPOW2, // width

D3DX_DEFAULT_NONPOW2, // height

D3DX_FROM_FILE, // MIP levels

0, // usage

D3DFMT_DXT1, // texture format

D3DPOOL_MANAGED, // mem pool

D3DX_DEFAULT, // filter

D3DX_DEFAULT, // MIP filter

0xFF000000, // transparent color key

NULL, // image info struct

NULL, // palette

&gTiles[i]); // the returned texture

// If the resource didn't load correctly, set the gBrokenTiles to true.

if (result == D3D_OK)

gBrokenTiles[i] = false;

else

gBrokenTiles[i] = true;

}

// Loop through all the sprites

for (int i = 0; i < kSpriteCount; i++)

{

// Setup and create the string.

char fileName [32];

sprintf(fileName, "%d.png", i);

// Create the texture.

int result = D3DXCreateTextureFromFileEx(

gDirect3DDevice, // Our DirectX Device

fileName, // Our texture image!

D3DX_DEFAULT_NONPOW2, // width

D3DX_DEFAULT_NONPOW2, // height

D3DX_FROM_FILE, // MIP levels

0, // usage

D3DFMT_DXT1, // texture format

D3DPOOL_MANAGED, // mem pool

D3DX_DEFAULT, // filter

D3DX_DEFAULT, // MIP filter

0xFFFF00FF, // transparent color key

NULL, // image info struct

NULL, // palette

&gSprites[i]); // the returned texture

// If the resource didn't load correctly, set the gBrokenSprites to true.

if (result == D3D_OK)

gBrokenSprites[i] = false;

else

gBrokenSprites[i] = true;

}

}

// This function will render a frame. This does not have the code to UPDATE GAME LOGIC.

void RenderFrame(void)

{

// Clear the window.

gDirect3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

// Initialize the Scene.

gDirect3DDevice->BeginScene();

// Begin the sprite batch with alpha blending, draw the sprite, close the batch.

gDirect3DXSprite->Begin(D3DXSPRITE_ALPHABLEND);

// Let's loop through the rows and columns and display our tiles.

for (int r = 0; r < kScreenHeight / 32; r++)

{

for (int c = 0; c < kScreenWidth / 32; c++)

{

D3DXVECTOR3 thisPos = D3DXVECTOR3(c * 32, r * 32, 0);

gDirect3DXSprite->Draw(gTiles[0], NULL, NULL, &thisPos, 0xFFFFFFFF); // Grass

gDirect3DXSprite->Draw(gTiles[1], NULL, NULL, &thisPos, 0xFFFFFFFF); // Fisheh

}

}

// Are they going left or right? Or Up or down? Setup the tile for them.

gCurrentTileAnimation = ((4 * gPlayerDirection) + (abs((int)(gPlayerDirection == 1 || gPlayerDirection == 2 ? gPlayerPositionDisplay.x : gPlayerPositionDisplay.y)) / 4 % 4));

// Draw the player.

gDirect3DXSprite->Draw(gSprites[0], &gPlayerAnimationSources[0][gCurrentTileAnimation], NULL, &gPlayerPositionDisplay, 0xFFFFFFFF);

// Draw the player's silhouette.

if (gIsDebugMode)

gDirect3DXSprite->Draw(gSprites[0], &gPlayerAnimationSources[0][gCurrentTileAnimation], NULL, &gPlayerPosition, 0x7FFF0000);

// End our sprite batch.

gDirect3DXSprite->End();

// If we are in Debug Mode, do some stuff.

if (gIsDebugMode)

{

// Reset the sum.

frameSum = 0;

// Loop through the frames and add them to the sum.

for (int i = 0; i < kMeasureFrameCount; ++i)

frameSum += gFrameTimes[i];

// Setup and create the string we wish to draw.

std::stringstream ss;

ss << (gIsPlayerRunning ? "True" : "False") << ", " << (gIsDebugMode ? "True" : "False") << "\r\n"

<< gPlayerPosition.x << ":" << gPlayerPosition.y << "\r\n"

<< gPlayerPositionDisplay.x << ":" << gPlayerPositionDisplay.y << " " << (gPlayerDirection == 0 ? "0" : (gPlayerDirection == 1 ? "1" : (gPlayerDirection == 2 ? "2" : "3"))) << "\r\n"

<< gCurrentTileAnimation << "\r\n"

<< gTimePerFrame << ":" << gTimePerFrame / CLOCKS_PER_SEC << ", " << gFrameBeginTime << ":" << gFrameEndTime << "\r\n"

<< 10 / ((frameSum / CLOCKS_PER_SEC) / kMeasureFrameCount) << " " << gCurrentFrame << " " << 10 / (gTimePerFrame / CLOCKS_PER_SEC);

std::string s = ss.str();

// Draw our text to the screen. (This draws whether the player is running.)

gDirectXFont->DrawTextA(NULL,

s.c_str(),

strlen(s.c_str()),

&gTextRect,

DT_LEFT | DT_TOP,

0xFF000000);

}

// End the Scene.

gDirect3DDevice->EndScene();

// Show the user.

gDirect3DDevice->Present(NULL, NULL, NULL, NULL);

}

// This function cleans up the variables we had. The DirectX ones and the COM/C++ ones.

void CleanDirect3D(void)

{

// Loop through and release all our tiles.

for (int i = 0; i < kTileCount; i++)

{

// If the tile isn't broken, release it.

if (!gBrokenTiles[i])

gTiles[i]->Release();

}

// Loop through and release all our sprites.

for (int i = 0; i < kSpriteCount; i++)

{

// If the sprite isn't broken, release it.

if (!gBrokenSprites[i])

gSprites[i]->Release();

}

gDirectXFont->Release(); // Close and Release our Font

gDirect3DXSprite->Release(); // Close and Release our Sprite

gDirect3DDevice->Release(); // Close and Release our Device

gDirect3D->Release(); // Finally, Close and Release Direct3D

}

// ------------------------------------------------------------------

// ---- ----

// ---- Game Logic Functions ----

// ---- ----

// ------------------------------------------------------------------

void UpdateGameLogic(void)

{

// Setup the factor. If they are running it is 2\. Otherwise 1.

int factor = gIsPlayerRunning ? 2 : 1;

// Update their X position based on whether they are ahead of or behind the real position.

if (gPlayerPosition.x > gPlayerPositionDisplay.x)

gPlayerPositionDisplay.x += factor;

else if (gPlayerPosition.x < gPlayerPositionDisplay.x)

gPlayerPositionDisplay.x -= factor;

// Update their Y position based on whether they are ahead of or behind the real position.

if (gPlayerPosition.y > gPlayerPositionDisplay.y)

gPlayerPositionDisplay.y += factor;

else if (gPlayerPosition.y < gPlayerPositionDisplay.y)

gPlayerPositionDisplay.y -= factor;

// Is the X within 1 pixel? If so, make it the same.

if (gPlayerPosition.x - gPlayerPositionDisplay.x <= 1 && gPlayerPosition.x - gPlayerPositionDisplay.x >= -1)

gPlayerPositionDisplay.x = gPlayerPosition.x;

// Is the Y within 1 pixel? If so, make it the same.

if (gPlayerPosition.y - gPlayerPositionDisplay.y <= 1 && gPlayerPosition.y - gPlayerPositionDisplay.y >= -1)

gPlayerPositionDisplay.y = gPlayerPosition.y;

}

Yes, it's long. I have attached a compiled Windows Binary as well, so you can see what it does. (Also has all resources, although, if I remember right, it isn't the most up-to-date version of the source.)

Thanks,

Aeroplane[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]

```
Link to comment
Share on other sites

Use [GetWindowLong](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633584%28v=vs.85%29.aspx)([Ptr](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633585%28v=vs.85%29.aspx)) and [SetWindowLong](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx)([Ptr](http://msdn.microsoft.com/en-us/library/windows/desktop/ms644898%28v=vs.85%29.aspx)) to associate data with your window handle, allowing you access to that data within your event handler. The excessive use of global variables is usually seen as a [bad coding practice](http://c2.com/cgi/wiki?GlobalVariablesAreBad), and rightfully so.

Context switches are _expensive_, especially when textures are involved. Therefore they should be avoided as much as is possible. Use [IDirect3D9_GetDeviceCaps](http://msdn.microsoft.com/en-us/library/windows/desktop/bb174320%28v=vs.85%29.aspx) to query the maximum texture size that is supported (D3DCAPS9.MaxTextureWidth and D3DCAPS9.MaxTextureHeight), and to query whether NPOT-textures are supported (albeit less interesting; D3DCAPS9.TextureCaps). Then create a texture of that size using [IDirect3DDevice9_CreateTexture](http://msdn.microsoft.com/en-us/library/windows/desktop/bb174363%28v=vs.85%29.aspx), and use [IDirect3DTexture9_LockRect](http://msdn.microsoft.com/en-us/library/windows/desktop/bb205913%28v=vs.85%29.aspx) to lock the texture, whereupon you can update (parts of) it by copying over the pixels directly (be aware of concepts such as pitch, pixel formats and so further, it is a lot more complicated than you might think it is), whereupon you have to unlock it using [IDirect3DTexture9_UnlockRect](http://msdn.microsoft.com/en-us/library/windows/desktop/bb205914%28v=vs.85%29.aspx). That way you can fill up your textures with tiles, and other images, until there is no space left, whereupon you can apply the same process for a new texture. This ensures you will have the least amount of textures, reducing the amount of context switches drastically.

However, the process itself is quite difficult to implement, and I am not aware of any libraries that do the blitting and the entire management of such textures for you. What I am aware of is that the alternative provided by OpenGL is a lot easier to work with. People who have worked with OpenGL before may be familiar with [glTexSubImage2D](http://www.opengl.org/sdk/docs/man/xhtml/glTexSubImage2D.xml).

Other than that, you should improve your organisation: split up logic into functions, name them properly, and group functions related to the same idea, task, etc. within the same file. Files shouldn't be longer than two to three hundred lines of code (with code generation being the major exception).

Yours faithfully

S.J.R. van Schaik.
Link to comment
Share on other sites

> Now write a shader that will accomplish the same tasks. A lot of modern rendering is done through shaders,it'd be good to get the hang of it sooner ![:P](http://www.touchofdeathforums.com/community/public/style_emoticons/<#EMO_DIR#>/tongue.png)

Yes, vertex and fragment shader programming are preferred over the fixed function pipeline, because they make great use of parallelism, and because they offer both a huge amount of flexibility and performance, but I really discourage jumping straight into the subject, unless you are already experienced with both linear algebra and graphics programming itself, since that makes it easier to actually comprehend shader programming to begin with.

Yours faithfully

S.J.R. van Schaik.
Link to comment
Share on other sites

  • 2 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...