I''m completely lost. I''ve been staring at this code for 10+ hours and now I regret not going to sleep because I still haven''t figured it out. Suffice to say, I''m pretty pissed at people that write tutorials and don''t explain everything or act as if everybody''s game is going to be in 1 giant source file.
Anyways, here''s the code. It compiles just fine but my texture isn''t showing up (splash.tga) and when I close the window I get an uninformative error.
CTexture.cpp
//-------------------------------------------------------Chronicles of Lorium--
// CTexture.cpp
// The CTexture class functions.
//-----------------------------------------------------------------------------
#include "CTexture.h"
#include "dx.h"
// Static member initialization
list <CTexture::LOADEDTEXTURE*> CTexture::loadedTextures;
// Load texture from file.
int CTexture::Init ( string sFilename ) {
D3DSURFACE_DESC surfaceDesc;
LOADEDTEXTURE* newTexture;
list<LOADEDTEXTURE*>::iterator itTextures;
// Make sure the texture is not already loaded.
if(bLoaded)
return FALSE;
// Convert filename to lowercase letters.
sFilename = strlwr( (char*)sFilename.c_str() );
// Check if texture is on the loaded list.
for( itTextures = loadedTextures.begin(); itTextures != loadedTextures.end(); itTextures++)
if ( (*itTextures)->sFilename == sFilename) {
// Get LOADEDTEXTURE object.
texture = *itTextures;
// Increment reference counter.
(*itTextures)->referenceCount++;
// Set loaded flag.
bLoaded = true;
// Successfully found texture
return TRUE;
}
// Texture was not in the list, make a new texture.
newTexture = new LOADEDTEXTURE;
// Load texture from file.
newTexture->texture = LoadTexture ( (char*)sFilename.c_str() );
// Make sure texture was loaded
if (!newTexture->texture)
return FALSE;
// Get texture dimensions
newTexture->texture->GetLevelDesc( 0, &surfaceDesc);
// Set new texture paramaters
newTexture->referenceCount = 1;
newTexture->sFilename = sFilename;
newTexture->width = surfaceDesc.Width;
newTexture->height = surfaceDesc.Height;
// Push new texture onto list
loadedTextures.push_back (newTexture);
// Setup current texture instance
texture = loadedTextures.back();
// Successfully loaded texture
return TRUE;
}
int CTexture::Close() {
// Make sure texture is loaded.
if(!bLoaded)
return FALSE;
// Decrement reference counter and nullify pointer.
texture->referenceCount--;
texture = NULL;
// Clear loaded flag.
bLoaded = FALSE;
// Successfull unloaded texture
return TRUE;
}
//Release all textures
int CTexture::CleanupTextures()
{
list<LOADEDTEXTURE*>::iterator it;
//Go through loaded texture list
for (it = loadedTextures.begin(); it != loadedTextures.end (); it++)
{
//Release texture
if ((*it)->texture)
(*it)->texture->Release();
(*it)->texture = NULL;
//Delete LOADEDTEXTURE object
delete (*it);
}
//Clear list
loadedTextures.clear ();
//Successfully released all textures
return TRUE;
}
//Draw texture.
void CTexture::Blit (int X, int Y, D3DCOLOR vertexColor, float rotate)
{
RECT rDest;
//Setup destination rectangle
rDest.left = X;
rDest.right = X + texture->width;
rDest.top = Y;
rDest.bottom = Y + texture->height;
//Draw texture
BlitD3D(texture->texture, &rDest, vertexColor, rotate);
}
d3dinit.cpp
//-------------------------------------------------------Chronicles of Lorium--
// d3dinit.cpp
// Initializes Direct3D, a rendering device, and a vertex buffer.
//-----------------------------------------------------------------------------
#include "dx.h"
#include "CTexture.h"
IDirect3D9* g_pD3D; // Direct3D interface.
IDirect3DDevice9* g_pd3dDevice; // Graphics adapter.
IDirect3DVertexBuffer9* g_pVB; // Buffer to hold vertices.
//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd ) {
// Create the Direct3D object which is needed to create the D3DDevice.
if( FAILED( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION) ) ) {
MessageBox( hWnd, "Could not create a Direct3D9 object.", "Direct3DCreate9", MB_OK);
return E_FAIL;
}
// Set up the structure used to create the D3DDevice. Most parameters are
// zeroed out. We set Windowed to TRUE, since we want to do D3D in a
// window, and then set the SwapEffect to "discard", which is the most
// efficient method of presenting the back buffer to the display. And
// we request a back buffer format that matches the current desktop display
// format.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Create the Direct3D device. Here we are using the default adapter (most
// systems only have one, unless they have multiple graphics hardware cards
// installed) and requesting the HAL (which is saying we want the hardware
// device rather than a software one). Software vertex processing is
// specified since we know it will work on all cards. On cards that support
// hardware vertex processing, though, we would see a big performance gain
// by specifying hardware vertex processing.
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) ) {
MessageBox( hWnd, "Could not create a Direct3D9 object.", "Direct3DCreate9", MB_OK);
return E_FAIL;
}
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.
//-----------------------------------------------------------------------------
HRESULT InitVB() {
// Set render states
if( FAILED( g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE) ) ) return E_FAIL;
if( FAILED( g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE) ) ) return E_FAIL;
if( FAILED( g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA) ) ) return E_FAIL;
if( FAILED( g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA) ) ) return E_FAIL;
if( FAILED( g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE) ) ) return E_FAIL;
// Set the vertex shader.
if( FAILED( g_pd3dDevice->SetVertexShader( NULL ) ) ) return E_FAIL;
if( FAILED( g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ) ) ) return E_FAIL;
// Create the vertex buffer.
if( FAILED( g_pd3dDevice->CreateVertexBuffer( sizeof(SQUAREVERTEX) * 4, NULL, D3DFVF_CUSTOMVERTEX,
D3DPOOL_MANAGED, &g_pVB, NULL ) ) )
return E_FAIL;
if( FAILED( g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(SQUAREVERTEX) ) ) )
return E_FAIL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID Cleanup()
{
CTexture::CleanupTextures();
g_pd3dDevice->SetStreamSource( 0, NULL, 0, 0 );
if( g_pVB != NULL )
g_pVB->Release();
if( g_pd3dDevice != NULL)
g_pd3dDevice->Release();
if( g_pD3D != NULL)
g_pD3D->Release();
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID Render()
{
if( NULL == g_pd3dDevice )
return;
// Clear the backbuffer to a blue color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 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).
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(SQUAREVERTEX) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, 1 );
// End the scene
g_pd3dDevice->EndScene();
}
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
//-----------------------------------------------------------------------------
// Name: *LoadTexture()
// Desc: Loads a texture from a file using D3DX. Supported formats include
// BMP, PPM, DDS, JPG, PNG, TGA, DIB. Returns a pointer to a texture.
//-----------------------------------------------------------------------------
IDirect3DTexture9 *LoadTexture( char *fileName ) {
IDirect3DTexture9 *d3dTexture;
D3DXIMAGE_INFO SrcInfo; // Optional
// Use a magenta colorkey.
D3DCOLOR colorkey = 0xFFFF00FF;
// Load image from file.
if ( FAILED( D3DXCreateTextureFromFileEx( g_pd3dDevice, fileName, 0, 0, 1, 0,
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT,
colorkey, &SrcInfo, NULL, &d3dTexture ) ) )
return NULL;
return d3dTexture;
}
//-----------------------------------------------------------------------------
// Name: BlitExD3D
// Desc: Draws a textured quad on the back buffer.
//-----------------------------------------------------------------------------
HRESULT BlitD3D( IDirect3DTexture9 *texture, RECT *rDest, D3DCOLOR vertexColor, float rotate ) {
SQUAREVERTEX* vertices;
// Lock the vertex buffer
g_pVB->Lock( 0, 0, (void**)&vertices, NULL);
// Setup vertices
// A -0.5f modifier is applied to vertex coordinates to match texture
// and screen coords. Some drivers may compensate for this
// automatically, but on others texture alignment errors are introduced
// More information on this can be found in the Direct3D 9 documentation
vertices[0].color = vertexColor;
vertices[0].x = (float) rDest->left - 0.5f;
vertices[0].y = (float) rDest->top - 0.5f;
vertices[0].z = 0.0f;
vertices[0].rhw = 1.0f;
vertices[0].u = 0.0f;
vertices[0].v = 0.0f;
vertices[1].color = vertexColor;
vertices[1].x = (float) rDest->right - 0.5f;
vertices[1].y = (float) rDest->top - 0.5f;
vertices[1].z = 0.0f;
vertices[1].rhw = 1.0f;
vertices[1].u = 1.0f;
vertices[1].v = 0.0f;
vertices[2].color = vertexColor;
vertices[2].x = (float) rDest->right - 0.5f;
vertices[2].y = (float) rDest->bottom - 0.5f;
vertices[2].z = 0.0f;
vertices[2].rhw = 1.0f;
vertices[2].u = 1.0f;
vertices[2].v = 1.0f;
vertices[3].color = vertexColor;
vertices[3].x = (float) rDest->left - 0.5f;
vertices[3].y = (float) rDest->bottom - 0.5f;
vertices[3].z = 0.0f;
vertices[3].rhw = 1.0f;
vertices[3].u = 0.0f;
vertices[3].v = 1.0f;
// Handle rotation.
if (rotate != 0) {
RECT rOrigin;
float centerX, centerY;
int index = 0;
// Find center of destination rectangle.
centerX = (float)(rDest->left + rDest->right) / 2;
centerY = (float)(rDest->top + rDest->bottom) / 2;
// Translate destination rect to be centered on the origin.
rOrigin.top = rDest->top - (int)(centerY);
rOrigin.bottom = rDest->bottom - (int)(centerY);
rOrigin.left = rDest->left - (int)(centerX);
rOrigin.right = rDest->right - (int)(centerX);
// Rotate vertices about the origin.
vertices[index].x = rOrigin.left * cosf(rotate) - rOrigin.top * sinf(rotate);
vertices[index].y = rOrigin.left * cosf(rotate) - rOrigin.top * sinf(rotate);
vertices[index + 1].x = rOrigin.right * cosf(rotate) - rOrigin.top * sinf(rotate);
vertices[index + 1].y = rOrigin.right * cosf(rotate) - rOrigin.top * sinf(rotate);
vertices[index + 2].x = rOrigin.right * cosf(rotate) - rOrigin.bottom * sinf(rotate);
vertices[index + 2].y = rOrigin.right * cosf(rotate) - rOrigin.bottom * sinf(rotate);
vertices[index + 3].x = rOrigin.left * cosf(rotate) - rOrigin.bottom * sinf(rotate);
vertices[index + 3].y = rOrigin.left * cosf(rotate) - rOrigin.bottom * sinf(rotate);
// Translate vertices to proper position
vertices[index].x += centerX;
vertices[index].y += centerY;
vertices[index + 1].x += centerX;
vertices[index + 1].y += centerY;
vertices[index + 2].x += centerX;
vertices[index + 2].y += centerY;
vertices[index + 3].x += centerX;
vertices[index + 3].y += centerY;
}
// Unlock the vertex buffer
if( FAILED( g_pVB->Unlock() ) )
return E_FAIL;
// Set texture
g_pd3dDevice->SetTexture( 0, texture );
// Draw image
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2);
return S_OK;
}
lsplash.cpp
//-------------------------------------------------------Chronicles of Lorium--
// lsplash.cpp
// Displays the lorium engine splash screen
//-----------------------------------------------------------------------------
#include <windows.h>
#include "dx.h"
#include "lorium.h"
#include "CTexture.h"
HRESULT LoriumSplash () {
if( NULL == g_pd3dDevice )
return E_FAIL;
CTexture txSplash;
txSplash.Init("splash.tga");
txSplash.Blit(512, 512, 0xffffffff, 0);
// Clear the backbuffer to a black color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
// Begin the scene.
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) {
// Set the stream source.
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(SQUAREVERTEX) );
// Let D3D know what vertex shader to use
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
// Render geometry.
g_pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, 1 );
// End the scene
g_pd3dDevice->EndScene();
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
return S_OK;
}
winmain.cpp
//-------------------------------------------------------Chronicles of Lorium--
// winmain.cpp
// The WinMain function (entry point) and the
// Windows message handler.
//-----------------------------------------------------------------------------
#include <windows.h>
#include "lorium.h"
#include "dx.h"
#include "CTexture.h"
#define WIN32_LEAN_AND_MEAN
HRESULT LoriumSplash ();
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window''s message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
switch( msg )
{
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
LoriumSplash();
ValidateRect( hWnd, NULL );
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,
"Lorium Engine", NULL };
RegisterClassEx( &wc );
// Create the Window
HWND hWnd = CreateWindow( "Lorium Engine", "Lorium Engine ver 0.1",
WS_OVERLAPPEDWINDOW, 100, 100, 800, 600,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
// Initialize Direct3D.
if( ( SUCCEEDED( InitD3D (hWnd) ) ) && ( SUCCEEDED( InitVB() ) ) ) {
// Show the window.
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// Enter the message loop.
MSG msg;
while(TRUE) {
// Handle messages.
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// GameMain will go here
// LoriumSplash will take a texture.
LoriumSplash();
}
}
UnregisterClass( "Lorium Engine", wc.hInstance );
return 0;
}
CTexture.h
//-------------------------------------------------------Chronicles of Lorium--
// CTexture.h
// The CTexture class Prototype.
//-----------------------------------------------------------------------------
#pragma once
#include <windows.h>
#include <assert.h>
#include <string>
#include <sstream>
#include <list>
#include <d3d9.h>
#include <d3dx9.h>
using namespace std;
class CTexture
{
public:
//Set default member values
CTexture()
{
bLoaded = FALSE;
texture = NULL;
}
//Load texture from file
int CTexture::Init (string sFilename);
//Unload a texture
int CTexture::Close();
//Draw texture with limited colour modulation
void CTexture::Blit (int X, int Y, D3DCOLOR vertexColour = 0xFFFFFFFF, float rotate = 0);
//Draw texture with full colour modulation
void CTexture::BlitEx (int X, int Y, D3DCOLOR* vertexColours, float rotate);
//Release all unreferenced textures
static int GarbageCollect();
//Release all unreferenced textures
static int CleanupTextures();
private:
//Loaded texture struct
struct LOADEDTEXTURE
{
int referenceCount; //Amount of CTexture instances containing this texture
IDirect3DTexture9* texture; //The texture
string sFilename; //The filename of the texture
int width; //Width of the texture
int height; //Height of the texture
};
//Linked list of all loaded textures
static list <LOADEDTEXTURE*> loadedTextures;
BOOL bLoaded; //Texture loaded flag
LOADEDTEXTURE* texture; //The texture
};
dx.h
//-------------------------------------------------------Chronicles of Lorium--
// dx.h
// Contains globals and function prototypes for DirectX.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Dependencies.
//-----------------------------------------------------------------------------
#include <d3d9.h>
#include <d3dx9.h>
extern IDirect3D9* g_pD3D; // Direct3D interface.
extern IDirect3DDevice9* g_pd3dDevice; // Graphics adapter.
extern IDirect3DVertexBuffer9* g_pVB; // Buffer to hold vertices.
//-----------------------------------------------------------------------------
// Function prototypes.
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd );
HRESULT InitVB();
IDirect3DTexture9 *LoadTexture( char *fileName );
HRESULT BlitD3D( IDirect3DTexture9 *texture, RECT *rDest, D3DCOLOR vertexColor, float rotate );
//-----------------------------------------------------------------------------
// Structures.
//-----------------------------------------------------------------------------
struct SQUAREVERTEX {
float x, y, z, rhw; // The transformed position for the vertex.
D3DCOLOR color; // The vertex color (32 bit AARRGGBB).
float u, v; // The texture coordinates of the vertex.
};
// Our custom FVF, which describes our custom vertex structure
const DWORD D3DFVF_CUSTOMVERTEX = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;
lorium.h
//-------------------------------------------------------Chronicles of Lorium--
// lorium.h
// Contains globals and function prototypes for the game.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Function prototypes.
//-----------------------------------------------------------------------------
void Cleanup();
void Render();