I'm sure there is a simple answer to this one somewhere. I currently have a program which correctly renders a .png image as a texture over a rectangle of vertices. This all works fine and displays correctly.
My question is how do I go about rendering a second texture onscreen using a separate image? The easiest/optimal way (I know they are probably different!) The second image I want to add will serve as the background image. I have tried duplicating the CUSTOMVERTEX structure, vertex buffer, separate vertex data, translation matrix, texture stage setting etc.. for the second texture I want to use, but I can only successfully render one on the screen, something is getting overwritten. Unfortunately I am still learning texturing and am missing the right approach. Is a completely separate vertex setup even required?
The code below reflects my working code so far, displaying an image as a texture overlayed on a rectangle of vertices. What should I add to setup & render a separate texture for my background?
//////////////////////////////////////////////////////
// I N V A D E R S
//////////////////////////////////////////////////////
#include <Windows.h> // Windows library (for window functions, menus, dialog boxes, etc)
#include <d3dx9.h> // Direct 3D library (for all Direct 3D functions).
//-----START-----DEFINE GLOBAL ELEMENTS----------//
LPDIRECT3D9 D3D_Object = NULL; // Name of the Direct3D Obeject. Used to create the D3DDevice
LPDIRECT3DDEVICE9 D3D_Device = NULL; // Name of the rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL; // Buffer to hold vertices for the rectangle
LPDIRECT3DTEXTURE9 D3D_Tex_Background = NULL; // The texture for the background
LPDIRECT3DTEXTURE9 D3D_Tex_Invader = NULL; // The texture for the invader
float g_InvaderX = -50, g_InvaderY = 0, g_InvaderZ = 0; // starting cooordinates of object
// A structure for our custom vertex type, containing the vertex & texture coordinates
struct CUSTOMVERTEX
{
D3DXVECTOR3 position; // Vertex coordinates
FLOAT u, v; // Texture coordinates
};
// The structure of a vertex in our vertex buffer...
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1) // it will contain xyz coordinates & a texture
//////////////////////////////////////////////////////
// Setup Direct3D
//////////////////////////////////////////////////////
HRESULT SetupD3D(HWND hWnd)
{
// Create the D3D object.
if (NULL == (D3D_Object = Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL;
// Set up the structure used to create the D3D Device
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE; // application will be windowed
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // back to front buffer behavior - DISCARD = random data used for error checking
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // back buffer format - UNKNOWN = use current display resolution to retain consistency
d3dpp.EnableAutoDepthStencil = TRUE; // D3D device to create and manage depth and stencil buffer automatically
d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // format of the surfaces which hold the depth & stencil buffers - D16 = 16Bit colours
// Create the D3D Device - on successful completion return a pointer to the created device D3D_Device
if (FAILED(D3D_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &D3D_Device)))
{
return E_FAIL; // return error if D3D Device creation has failed
}
return S_OK;
}
//////////////////////////////////////////////////////
// DIRECT3D CLEANUP
//
// Release (delete) all the resources used by this program.
// Only release things if they are valid (i.e. have a valid pointer).
// If not, the program will crash at this point.
//////////////////////////////////////////////////////
void CleanUp()
{
// Delete the textures
if (D3D_Tex_Background != NULL) D3D_Tex_Background -> Release();
if (D3D_Tex_Invader != NULL) D3D_Tex_Invader -> Release();
// Release other D3D Device resources
if (g_pVertexBuffer != NULL) g_pVertexBuffer -> Release();
if (D3D_Device != NULL) D3D_Device -> Release();
if (D3D_Object != NULL) D3D_Object -> Release();
}
//////////////////////////////////////////////////////
// Setup the camera
//////////////////////////////////////////////////////
void SetupMatrices()
{
// Setup View Matrix
D3DXVECTOR3 vCamera(5.0f, 5.0f, -100.0f);
D3DXVECTOR3 vLookat(5.0f, 5.0f, 0.0f);
D3DXVECTOR3 vUpVector(0.0f, 1.0f, 0.0f);
D3DXMATRIX matrixView;
D3DXMatrixLookAtLH(&matrixView, &vCamera, &vLookat, &vUpVector);
D3D_Device -> SetTransform(D3DTS_VIEW, &matrixView);
// Setup Projection Matrix
// This transforms 2D geometry into a 3D space
D3DXMATRIX matrixProjection;
D3DXMatrixPerspectiveFovLH(&matrixProjection, D3DX_PI/4, 1.0f, 1.0f, 800.0f);
D3D_Device -> SetTransform(D3DTS_PROJECTION, &matrixProjection);
}
//////////////////////////////////////////////////////
// SETUP GEOMETRY -
// Define a square using the required verticies
//////////////////////////////////////////////////////
HRESULT SetupGeometry()
{
// Calculate the number of vertices required for the desired graphic
int Vertices = 2 * 3; // Six vertices required for the 2 triangles which make up the square.
// Calculate the size in bytes of the buffer which will hold the vertex information
// based on the number of verticies required and the elements contained within the CUSTOMVERTEX structure
int BufferSize = Vertices * sizeof(CUSTOMVERTEX);
// Create the vertex buffer which will store the vertex data to render
// (buffer size, special instructions, vertex buffer format, target memory location for buffer,pointer to vertex buffer, future use only)
if (FAILED(D3D_Device -> CreateVertexBuffer(BufferSize, 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVertexBuffer, NULL)))
{
return E_FAIL; // if the vertex buffer could not be created.
}
//////////////////////////////////////////////////////
// Fill vertex buffer with required vertex & texture info
//////////////////////////////////////////////////////
CUSTOMVERTEX *pVertices; // Create a pointer to the first vertex in the buffer.
if (FAILED(g_pVertexBuffer -> Lock(0, 0, (void**)&pVertices, 0))) // lock the buffer to prevent interference, allow access using the
{ // &pVerticies pointer
return E_FAIL; // if the pointer to the vertex buffer could not be established.
}
// Fill the vertex buffers with data concerning both vertex and texture locations
// Triangle 1
// Vertex 0
pVertices[0].position.x = 0; // Vertex coordinates
pVertices[0].position.y = 0;
pVertices[0].position.z = 0;
pVertices[0].u = 0; // texture coordinates
pVertices[0].v = 1;
// Vertex 1
pVertices[1].position.x = 0;
pVertices[1].position.y = 10;
pVertices[1].position.z = 0;
pVertices[1].u = 0;
pVertices[1].v = 0;
// Vertex 2
pVertices[2].position.x = 10;
pVertices[2].position.y = 0;
pVertices[2].position.z = 0;
pVertices[2].u = 1;
pVertices[2].v = 1;
// Triangle 2
// Vertex 3
pVertices[3].position.x = 10;
pVertices[3].position.y = 0;
pVertices[3].position.z = 0;
pVertices[3].u = 1;
pVertices[3].v = 1;
// Vertex 4
pVertices[4].position.x = 0;
pVertices[4].position.y = 10;
pVertices[4].position.z = 0;
pVertices[4].u = 0;
pVertices[4].v = 0;
// Vertex 5
pVertices[5].position.x = 10;
pVertices[5].position.y = 10;
pVertices[5].position.z = 0;
pVertices[5].u = 1;
pVertices[5].v = 0;
// Unlock the vertex buffer...
g_pVertexBuffer -> Unlock();
return S_OK;
}
//////////////////////////////////////////////////////
// Load the textures for the invaders and background
//////////////////////////////////////////////////////
void LoadTextures()
{
//D3DXCreateTextureFromFile(D3D_Device, // Direct3D Device name
// "background.jpg", // Source file in program folder
// &D3D_Tex_Background); // address of target texture object
D3DXCreateTextureFromFile(D3D_Device,
"invader300x300.png",
&D3D_Tex_Invader);
}
//////////////////////////////////////////////////////
// Render
//////////////////////////////////////////////////////
void Render()
{
// Clearing the current frame & Z buffers
// (rectangles to clear, rectangle coords, clear current buffer & Z buffer, RGB background colour of screen, initial z buffer value, initial
// stencil buffer value)
D3D_Device -> Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
// Once current frame has been cleared, begin drawing new frame
// lock is created at this point to prevent anything else drawing on the frame
if (SUCCEEDED(D3D_Device -> BeginScene()))
{
// Construct a translation matrix to move the Invader
D3DXMATRIX TranslateMatrix;
D3DXMatrixTranslation(&TranslateMatrix, g_InvaderX, g_InvaderY, g_InvaderZ);
D3D_Device -> SetTransform(D3DTS_WORLD, &TranslateMatrix);
// Render the contents of the vertex buffer.
D3D_Device -> SetStreamSource(0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX));
D3D_Device -> SetFVF(D3DFVF_CUSTOMVERTEX);
D3D_Device -> DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
// Select the invader texture, and initialise the texture stage state...
D3D_Device -> SetTexture(0, // the texture stage being set
D3D_Tex_Invader); // the object associated with the texture image
D3D_Device -> SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
D3D_Device -> SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
// Update the invader's x co-ordinate.
//if (g_RectX <=14.5)
g_InvaderX += 0.5f;
// Drawing of the scene has finished
D3D_Device -> EndScene();
}
// Present the back frame buffer contents to the screen (front frame buffer swaped with back fram buffer)
D3D_Device -> Present(NULL, NULL, NULL, NULL);
}
//////////////////////////////////////////////////////
// Windows Message Handling
//////////////////////////////////////////////////////
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
//////////////////////////////////////////////////////
// Create the application window
//////////////////////////////////////////////////////
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,
"Invaders", NULL};
RegisterClassEx(&wc);
// Create the application window
HWND hWnd = CreateWindow( "Invaders", // Window class's name
"I N V A D E R S", // Title bar text
WS_OVERLAPPEDWINDOW, // The window style
100, // window horizontal position
500, // window vertical position
800, // window width
800, // window height
GetDesktopWindow(), // the parent window's module
NULL, // the window's menu handle
wc.hInstance, // the instance handle
NULL);
// Initialize Direct3D
if (SUCCEEDED(SetupD3D(hWnd)))
{
// Create the scene geometry
if (SUCCEEDED(SetupGeometry()))
{
// Load the required texture(s) from files into memeory
LoadTextures();
// Display the window onscreen
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// Initialse the Viewpoint / Camera based on defined settings
SetupMatrices();
// Enter message loop to handle any messages MS Windows sends to the application
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();
}
}
}
CleanUp(); // release resources used ( delete all dynamically allocated objects)
UnregisterClass("Server", wc.hInstance);
return 0;
} // end WinMain
It seems that you need more basic understanding of programming with directx. Try to do some tutorials like this or this, they are quiet useful.
To your specific question: It seems that you want to make a 2D-Game with images that are drawn onto the screen. Therefore it's easier to use the D3DFVF_XYZRHW
(doc), because so you can render untransformed vertices with 2D-Coordinates. To render the background first draw a fullscreen sized quad with you image applied. After that you render your ships in front of that. If your ship isn't drawed, mabye the Z-Buffering determined that your background is in front of it and clipped it away. For 2D-Games either you deactivate ZBuffering or set the depth in the vertices.