Sign in to follow this  
Dhaos

Sprites disappear after about 4-5 seconds (Fixed!)

Recommended Posts

In my studies of directx9 I decide to make a simple app that displays some sprites I made. It worked, except the sprites eventually disappear. The more sprites on screen the faster they disappear. Perhaps this is a memory issue? I've looked up various tutorials, spent hours on google and gamedev (among other tutorial sites) and am just lost. Any help is greatly appreciated.
[Source]
#define WIN32_LEAN_AND_MEAN
//HEADERS//////////////////////////////////////
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

//HEADERS_DX9//////////////////////////////////
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9tex.h>

//HEADERS_INTERNAL/////////////////////////////
#include "text.h"

#define WIN_TITLE	"Direct_X_Study"
#define WIN_W	640
#define WIN_H	480

#define WIND_MODE FALSE //windowed_mode
#define SAFE_RELE(x) if(x) {(x)->Release(); (x) = NULL;}//releases_memory

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

LPDIRECT3D9				g_pd3d9		= NULL;
LPDIRECT3DDEVICE9		g_pd3ddevi	= NULL;//d3d9 device
D3DDISPLAYMODE			g_dispmode;//display_mode
D3DPRESENT_PARAMETERS	g_d3dpp;

LPDIRECT3DVERTEXBUFFER9 g_pvert		= NULL;
LPDIRECT3DTEXTURE9		g_ptext01	= NULL;
LPDIRECT3DTEXTURE9		g_ptext02	= NULL;

LPD3DXSPRITE			g_pd3dsprite_01= NULL;
LPD3DXSPRITE			g_pd3dsprite_02= NULL;
LPD3DXSPRITE			g_pd3dsprite_03= NULL;
LPD3DXSPRITE			g_pd3dsprite_04= NULL;
LPD3DXSPRITE			g_pd3dsprite_05= NULL;

#define D3DFVF_PANELVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

HWND					g_hwnd;
int	test	=	0;
//FUNCTIONS////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
BOOL SetPP();//sets presentation parameters
void RendFram();//renders frames

struct PANELVERTEX
{
    FLOAT x, y, z;
    DWORD color;
    FLOAT u, v;
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
		//define
		WNDCLASSEX wcex;
		wcex.cbSize			= sizeof(WNDCLASSEX);
		wcex.style			= CS_HREDRAW|CS_VREDRAW;//CS_OWNDC
		wcex.lpfnWndProc	= WndProc;
		wcex.cbClsExtra		= 0;
		wcex.cbWndExtra		= 0;
		wcex.hInstance		= hInstance;
		wcex.hIcon			= NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CUNIT));
		wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);//setting NULL to hInstance is bad
		wcex.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
		wcex.lpszMenuName	= NULL;
		wcex.lpszClassName	= WIN_TITLE;
		wcex.hIconSm		= NULL;//LoadIcon(hInstance,MAKEINTRESOURCE(IDI_CUNIT));
		
		RegisterClassEx(&wcex);
		
		//g_hwnd = CreateWindow(WIN_TITLE,WIN_TITLE,WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,WIN_W,WIN_H,NULL,NULL,hInstance,0);//might be missing 1 parameter, a '0' 
		g_hwnd = CreateWindowEx(NULL,
								WIN_TITLE,
								WIN_TITLE,
								WS_POPUP|WS_VISIBLE,
								0,
								0,
								WIN_W,
								WIN_H,
								NULL,
								NULL,
								hInstance,
								NULL);
	
		ShowWindow(g_hwnd,nShowCmd);
		UpdateWindow(g_hwnd);
	
		SetPP();

		MSG msg;
		while(msg.message != WM_QUIT)
		{
			if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//check for messages///////////
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			else
			{
				RendFram();
			}
		}
		SAFE_RELE(g_pd3ddevi);
		SAFE_RELE(g_pd3d9);
		return msg.wParam;

}

BOOL SetPP()//set_presentation_parameters
{
		//initialize_dx9//////////////////////////////////////////////////////////////////////////
		g_pd3d9 = Direct3DCreate9(D3D_SDK_VERSION);
		if(!g_pd3d9)
		{
			MessageBox(0,"Direct3DCreate9() - Failed",0,0);
			return 0;
		}
		
		int adapmode = 0;
		int maxiadap = g_pd3d9->GetAdapterModeCount(D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8);
		bool badapmodefoun = false;//adaptor mode found
		
		for(adapmode = 0; adapmode < maxiadap; adapmode++)
		{
			if(FAILED(g_pd3d9->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, adapmode, &g_dispmode)))
			{
				MessageBox(g_hwnd,"enumadaptormodes failed","error",0);
			}
			if(g_dispmode.Width !=1024 || g_dispmode.Height != 768)
				continue;
			if(g_dispmode.Format != D3DFMT_X8R8G8B8)
				continue;
			if(g_dispmode.RefreshRate != 60)
				continue;
			badapmodefoun = true;
			break;
		}
		
		if (badapmodefoun = false)
		{
			MessageBox(g_hwnd, "adaptor mode not found", "adapmode",0);
		}
		
		if (FAILED(g_pd3d9->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, FALSE)))
		{
			MessageBox(g_hwnd, "check device type failed", "error", 0);
		}

		if (FAILED(g_pd3d9->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16)))
		{
			MessageBox(g_hwnd, "check device format, failed", "error", 0);
		}
		
		//g_pd3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &g_dispmode);//screws up fs mode
		
		//check for hardware t&l
		D3DCAPS9 d3dcaps;

		if (FAILED(g_pd3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dcaps)))
		{
			MessageBox(g_hwnd, "get device caps failed", "error", 0);
		}
		
		DWORD behaflag = 0;//behavior flags
		if(d3dcaps.VertexProcessingCaps != 0)
			behaflag |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
		else
			behaflag |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

		memset(&g_d3dpp, 0, sizeof(g_d3dpp));
		g_d3dpp.Windowed				= FALSE;
		g_d3dpp.EnableAutoDepthStencil	= TRUE;
		g_d3dpp.AutoDepthStencilFormat	= D3DFMT_D16;
		g_d3dpp.SwapEffect				= D3DSWAPEFFECT_DISCARD;
		g_d3dpp.BackBufferWidth			= 1024;
		g_d3dpp.BackBufferHeight		= 768;
		g_d3dpp.BackBufferFormat		= D3DFMT_X8R8G8B8;

		//create_d3d_device////////////////////////
		if(FAILED(g_pd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd, behaflag, &g_d3dpp, &g_pd3ddevi)))
		{
			MessageBox(0,"CreateDevice() - Failed","error",0);
			SAFE_RELE(g_pd3d9);
			return 0;
		}
		return TRUE;
}

void RendFram() //renders current frame
{
	//test+=1;
	g_pd3ddevi->Clear(	0,NULL,
						D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
						D3DCOLOR_COLORVALUE(0.325f, 0.3f, 0.3f, 0.0f), 1.0f, 0);
	g_pd3ddevi->BeginScene();
	//render data place holder
	D3DXMATRIX Ortho2D;	
	D3DXMATRIX object_01;//identity 1
	D3DXMATRIX object_02;//identity 2

	D3DXMATRIX panel_pos_01;
	D3DXMATRIX panel_pos_02;
	D3DXMATRIX sprite_01;
	D3DXMATRIX sprite_02;
	D3DXMATRIX sprite_03;
	D3DXMATRIX sprite_04;

	D3DXMatrixOrthoLH(&Ortho2D, 1024, 768, 0.0f, 1.0f);
	D3DXMatrixIdentity(&object_01);

	g_pd3ddevi->SetTransform(D3DTS_PROJECTION, &Ortho2D);
	g_pd3ddevi->SetTransform(D3DTS_WORLD, &object_01);
	g_pd3ddevi->SetTransform(D3DTS_VIEW, &object_01);

	D3DXMatrixTranslation(&panel_pos_01, -80.0f, -20.0f, 0.0f);
	g_pd3ddevi->SetTransform(D3DTS_WORLD, &panel_pos_01);

//------------------------------------------------------------------------------------------------
	g_pd3ddevi->SetRenderState(D3DRS_ALPHABLENDENABLE,  TRUE);

	g_pd3ddevi->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
	g_pd3ddevi->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_DESTALPHA);
	g_pd3ddevi->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
//------------------------------------------------------------------------------------------------
	D3DXCreateTextureFromFileEx(g_pd3ddevi, "sprite_bird_front.png", 0, 0, 0, 0,
								D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT,
								D3DX_DEFAULT ,0xFF00ff00, NULL, NULL, &g_ptext02);
		

	if(FAILED(D3DXCreateSprite(g_pd3ddevi,&g_pd3dsprite_01)))
	{
		MessageBox(0,"D3DXCreateSprite() - Failed","error",0);
		//return 0;
	}

	g_pd3ddevi->SetTexture(0, g_ptext02);
	g_pd3dsprite_01->Begin(D3DXSPRITE_ALPHABLEND);

	D3DXMatrixTranslation(&sprite_01,100.0f,150.0f, 0.0f);
	g_pd3ddevi->SetTransform(D3DTS_WORLD, &sprite_01);
	RECT rect_sprite;
	rect_sprite.top		= 0;
	rect_sprite.left	= 0;
	rect_sprite.bottom	= 64;
	rect_sprite.right	= 64;
	
	g_pd3dsprite_01->Draw(g_ptext02, &rect_sprite,NULL,NULL,0xFFFFFFFF);
	g_pd3dsprite_01->End();

//------------------------------------------------------------------------------------------------
	if(FAILED(D3DXCreateSprite(g_pd3ddevi,&g_pd3dsprite_02)))
	{
		MessageBox(0,"D3DXCreateSprite() - Failed","error",0);
		//return 0;
	}
	g_pd3ddevi->SetTexture(0, g_ptext02);

	g_pd3dsprite_02->Begin(D3DXSPRITE_ALPHABLEND);
	D3DXMatrixTranslation(&sprite_02,200.0f,150.0f, 0.0f);
	g_pd3ddevi->SetTransform(D3DTS_WORLD, &sprite_02);
	rect_sprite.top		= 0;
	rect_sprite.left	= 0;
	rect_sprite.bottom	= 64;
	rect_sprite.right	= 64;
	
	g_pd3dsprite_02->Draw(g_ptext02, &rect_sprite,NULL,NULL,0xFFFFFFFF);
	g_pd3dsprite_02->End();

//------------------------------------------------------------------------------------------------
	D3DXCreateTextureFromFileEx(g_pd3ddevi, "sprite_lizard_front.png", 0, 0, 0, 0,
								D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_DEFAULT,
								D3DX_DEFAULT ,0xFF00ff00, NULL, NULL, &g_ptext01);
		
	if(FAILED(D3DXCreateSprite(g_pd3ddevi,&g_pd3dsprite_03)))
	{
		MessageBox(0,"D3DXCreateSprite() - Failed","error",0);
		//return 0;
	}

	g_pd3ddevi->SetTexture(0, g_ptext01);

	g_pd3dsprite_03->Begin(D3DXSPRITE_ALPHABLEND);
	D3DXMatrixTranslation(&sprite_03,500.0f,150.0f, 0.0f);
	g_pd3ddevi->SetTransform(D3DTS_WORLD, &sprite_03);
	rect_sprite;
	rect_sprite.top		= 0;
	rect_sprite.left	= 0;
	rect_sprite.bottom	= 64;
	rect_sprite.right	= 64;
	
	g_pd3dsprite_03->Draw(g_ptext01, &rect_sprite,NULL,NULL,0xFFFFFFFF);
	g_pd3dsprite_03->End();
	
	g_pd3ddevi->EndScene();
	g_pd3ddevi->Present(NULL, NULL, NULL, NULL);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	switch(msg)
	{
		case WM_DESTROY:
			PostQuitMessage(0);

		case WM_KEYDOWN:
			switch(wparam)
			{
				case VK_ESCAPE:
					PostQuitMessage(0);
					break;
			}
			return 0;
	}
	return DefWindowProc(hwnd, msg, wparam, lparam);
}



[Edited by - Dhaos on May 1, 2006 3:00:57 PM]

Share this post


Link to post
Share on other sites
Yes, I'd say this is a memory issue. Looking at the code here (only done 1 glance over so far), it appears as if you are having the load-from-disk and allocations occurring during the render loop. This will load it from the disk EVERY cycle of the game, memory will deplete very very quickly at this rate.

My suggestion is to break out the image loading code into a routine before the message pump "while(msg.message != WM_QUIT)". This would make more logical sense (unless there is some strange reason you need it loaded from disk every cycle, if that's the case I suggest a cleanup at the end of the render loop).

Edit: looked more deep at it now. Yes, I would remove all the sprite creation code into it's own function that is run once (all the D3DXCreateTextureFromFile, D3DXCreateSpite, etc).

Share this post


Link to post
Share on other sites
Necreia *thank you*. It works now. Figured it was a simple thing like that >_<. My understanding of memory allocation is still pretty weak it seems.

Btw by 'cleanup' do you mean the release function? Or are there other ways to clean up/restore memory? I'm pretty fuzzy on the subject =(

Share this post


Link to post
Share on other sites
Quote:
Original post by Dhaos
Necreia *thank you*. It works now. Figured it was a simple thing like that >_<. My understanding of memory allocation is still pretty weak it seems.

Btw by 'cleanup' do you mean the release function? Or are there other ways to clean up/restore memory? I'm pretty fuzzy on the subject =(


You're welcome.

If you load it into memory, and wish to reload it again (for whatever reason), you have to destroy it (that's what I meant by cleanup). That would be the ->Release() funtion on the sprites. If you like, I can cook up a little wrapper for you for this (for example sake).

Share this post


Link to post
Share on other sites
At the bottom of this is what I threw together. Sorry but I'm not able to test it atm, so there may be syntax errors and such. Also, I tried to place it into what you already had... so it may take a little prodding to get it to work.

Basically, create a source and a header file for the sprite files... and include it in your main file. From there this should work (it makes and displays 2 sprite files).

Sprite Header

class CSprite
{
public:
CSprite();
~CSprite();

// variables
public:
D3DXVECTOR2 m_RotCenter; // center position
D3DXVECTOR2 m_Translation; // translation factor
D3DXVECTOR2 m_Scaling; // scaling factor
float m_Rotation; // angle of rotation

D3DCOLOR m_ModulateColor; // the color to modulate with the sprite

protected:
LPD3DXSPRITE m_pSprite; // ID3DXSprite
LPDIRECT3DTEXTURE9 m_pTexture; // sprites texture

// funtions
public:
HRESULT Load(char* PathName); // loads the file from disk
HRESULT Render(int x, int y); // renders at a location
};








Sprite Body

// get the device from the other file
extern LPDIRECT3DDEVICE9 g_pd3ddevi;

// Default constructor
CSprite::CSprite()
{
m_pSprite = 0; // null sprite pointer
m_pTexture = 0; // null texture pointer

// zero out rotation center
m_RotCenter.x = 0.0f;
m_RotCenter.y = 0.0f;

// zero out translation point
m_Translation.x = 0.0f;
m_Translation.y = 0.0f;

// set default scaling value
m_Scaling.x = 1.0f;
m_Scaling.y = 1.0f;

// assign white as modulation color
m_ModulateColor = D3DCOLOR_XRGB(255,255,255);

// set rotation amount to 0
m_Rotation = 0.0f;
}

// Destructor
CSprite::~CSprite()
{
// release the sprite if it exists
if(m_pSprite)
m_pSprite->Release();

// release the texture if it exists
if(m_pTexture)
m_pTexture->Release();
}

// Initialize the sprite with an image from disk
HRESULT CSprite::Load(char *PathName)
{
HRESULT r = 0; // error holding value

// load the texture from disk into memory
r = D3DXCreateTextureFromFile(g_pd3ddevi,PathName,&m_pTexture);
if(FAILED(r))
{
MessageBox(0,"Could not load texture into memory","error",0);
return E_FAIL;
}

// create a new ID3DXSprite Object
r = D3DXCreateSprite(g_pd3ddevi, &m_pSprite);
if(FAILED(r))
{
MessageBox(0,"Could not create the new ID3DXSprite Object","error",0);
return E_FAIL;
}

return S_OK; // return success
}

// Render the sprite at a location
HRESULT CSprite::Render(int x,int y)
{
// return if not valid
if((m_pSprite == NULL) || (m_pTexture == NULL))
return E_FAIL;

HRESULT r = 0; // error holding value

// translate the sprite based on values passed
m_Translation.x = (float)x;
m_Translation.y = (float)y;

m_pSprite->Begin(); // tell sprite it is about to be rendered

// draw the sprite
r = m_pSprite->Draw(m_pTexture,NULL,&m_Scaling,&m_RotCenter,m_Rotation,&m_Translation,
m_ModulateColor);
if(FAILED(r))
{
MessageBox(0,"Could not render the sprite","error",0);
}

// end drawing with this sprite
m_pSprite->End();

return S_OK; // return success
}








Body Code


#define WIN32_LEAN_AND_MEAN
//HEADERS//////////////////////////////////////
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

//HEADERS_DX9//////////////////////////////////
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9tex.h>

//HEADERS_INTERNAL/////////////////////////////
#include "text.h"

#define WIN_TITLE "Direct_X_Study"
#define WIN_W 640
#define WIN_H 480

#define WIND_MODE FALSE //windowed_mode
#define SAFE_RELE(x) if(x) {(x)->Release(); (x) = NULL;}//releases_memory

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

LPDIRECT3D9 g_pd3d9 = NULL;
LPDIRECT3DDEVICE9 g_pd3ddevi = NULL;//d3d9 device
D3DDISPLAYMODE g_dispmode;//display_mode
D3DPRESENT_PARAMETERS g_d3dpp;
CSprite g_Sprite1;
CSprite g_Sprite2;

LPDIRECT3DVERTEXBUFFER9 g_pvert = NULL;

#define D3DFVF_PANELVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

HWND g_hwnd;
int test = 0;
//FUNCTIONS////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
BOOL SetPP();//sets presentation parameters
void Load();
void RendFram();//renders frames

struct PANELVERTEX
{
FLOAT x, y, z;
DWORD color;
FLOAT u, v;
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
//define
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW|CS_VREDRAW;//CS_OWNDC
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;//LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CUNIT));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);//setting NULL to hInstance is bad
wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = WIN_TITLE;
wcex.hIconSm = NULL;//LoadIcon(hInstance,MAKEINTRESOURCE(IDI_CUNIT));

RegisterClassEx(&wcex);

//g_hwnd = CreateWindow(WIN_TITLE,WIN_TITLE,WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,WIN_W,WIN_H,NULL,NULL,hInstance,0);//might be missing 1 parameter, a '0'
g_hwnd = CreateWindowEx(NULL,
WIN_TITLE,
WIN_TITLE,
WS_POPUP|WS_VISIBLE,
0,
0,
WIN_W,
WIN_H,
NULL,
NULL,
hInstance,
NULL);

ShowWindow(g_hwnd,nShowCmd);
UpdateWindow(g_hwnd);

SetPP();

MSG msg;
LoadSprites() // load the sprites from disk
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//check for messages///////////
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
RendFram();
}
}
SAFE_RELE(g_pd3ddevi);
SAFE_RELE(g_pd3d9);
return msg.wParam;

}

BOOL SetPP()//set_presentation_parameters
{
//initialize_dx9//////////////////////////////////////////////////////////////////////////
g_pd3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if(!g_pd3d9)
{
MessageBox(0,"Direct3DCreate9() - Failed",0,0);
return 0;
}

int adapmode = 0;
int maxiadap = g_pd3d9->GetAdapterModeCount(D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8);
bool badapmodefoun = false;//adaptor mode found

for(adapmode = 0; adapmode < maxiadap; adapmode++)
{
if(FAILED(g_pd3d9->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, adapmode, &g_dispmode)))
{
MessageBox(g_hwnd,"enumadaptormodes failed","error",0);
}
if(g_dispmode.Width !=1024 || g_dispmode.Height != 768)
continue;
if(g_dispmode.Format != D3DFMT_X8R8G8B8)
continue;
if(g_dispmode.RefreshRate != 60)
continue;
badapmodefoun = true;
break;
}

if (badapmodefoun = false)
{
MessageBox(g_hwnd, "adaptor mode not found", "adapmode",0);
}

if (FAILED(g_pd3d9->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, FALSE)))
{
MessageBox(g_hwnd, "check device type failed", "error", 0);
}

if (FAILED(g_pd3d9->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16)))
{
MessageBox(g_hwnd, "check device format, failed", "error", 0);
}

//g_pd3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &g_dispmode);//screws up fs mode

//check for hardware t&l
D3DCAPS9 d3dcaps;

if (FAILED(g_pd3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dcaps)))
{
MessageBox(g_hwnd, "get device caps failed", "error", 0);
}

DWORD behaflag = 0;//behavior flags
if(d3dcaps.VertexProcessingCaps != 0)
behaflag |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
behaflag |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

memset(&g_d3dpp, 0, sizeof(g_d3dpp));
g_d3dpp.Windowed = FALSE;
g_d3dpp.EnableAutoDepthStencil = TRUE;
g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_d3dpp.BackBufferWidth = 1024;
g_d3dpp.BackBufferHeight = 768;
g_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;

//create_d3d_device////////////////////////
if(FAILED(g_pd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd, behaflag, &g_d3dpp, &g_pd3ddevi)))
{
MessageBox(0,"CreateDevice() - Failed","error",0);
SAFE_RELE(g_pd3d9);
return 0;
}
return TRUE;
}

void Load()
{
// set the render settings
g_pd3ddevi->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
g_pd3ddevi->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
g_pd3ddevi->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_DESTALPHA);
g_pd3ddevi->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);

// load the sprites into memory
g_Sprite1.Load("sprite_bird_front.png");
g_Sprite2.Load("sprite_lizard_front.png");
}

void RendFram() //renders current frame
{
//test+=1;
g_pd3ddevi->Clear( 0,NULL,
D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_COLORVALUE(0.325f, 0.3f, 0.3f, 0.0f), 1.0f, 0);
g_pd3ddevi->BeginScene();

// render the sprites
g_Sprite1->Render(100, 150);
g_Sprite2->Render(200, 150);

g_pd3ddevi->EndScene();
g_pd3ddevi->Present(NULL, NULL, NULL, NULL);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);

case WM_KEYDOWN:
switch(wparam)
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}






Again, sorry if it doesn't work right out of the box, but I don't have DX SDK installed on this machine.

Edit: fixed a typo in the source.

Share this post


Link to post
Share on other sites
Woah, thats alot more than I expected. *looks at super organized code* I will be studying that for awhile... again thank you, that was truly helpful.

I do have a rather odd question, I understand how private/protected types works, but in the various books I read, it never explains why they are useful exactly. I know they restrict what can access those member-types, but I could never figure out why you need to restrict them. In very large programs do they help the program to run faster because the data is restricted or is it something else.

Thanks for spending time to answer my questions.

Share this post


Link to post
Share on other sites
Private, protected, and public are for encapsulation of data. For instance, in the business world when you receive input from an outside source the first thing you want to do is vet that input against a set of validation parameters. You want to know later in the program that when you're dealing with this data that is solid and falls within the expected parameters.

As a game example consider a car class. Each car class has a different top speed; the maximum speed is set at instantiation of the car class based on which car model is chosen. In your currentSpeed event you can check and ensure that your speed does not actually exceed the maximum speed of the vehicle before assigning it to the private backing variable. Your accelerate function doesn't have to worry about the maximum speed of the car; it can continue trying to accelerate, but the car's engine - your class - isn't letting it go any faster because it knows better.

The currentSpeed variable of the car class would be private. You might provide get_CurrentSpeed() and set_CurrentSpeed(int). You control access to the actual speed of the car; the get_ and set_ functions are interfaces with which outside entities can interact with your class. The internals of your class use the speed normally as well; they know that the range of values that it can be is limited to appropriate values for the vehicle.

You can also use these as trigger points. In an RTS game you might have a trigger for the player accumulating so much gold; this trigger could be fired from within the accessor. (Although there's innumerable better places to put it. :)) Again, that variable can't change without the class knowing about it - it provides you with the ultimate in control.


Share this post


Link to post
Share on other sites
Hmm... I think I understand what you're saying, it's like a security measure to prevent data from getting modified inappropriately, but in the little bit of coding I have done (directx7.0 stuff) I never ran into a situation where I had to use private/protected members. I suppose what's confusing me is that what *would* be trying to access data inappropriately? Since you (the coder) is telling your program exactly what its doing...shouldn't you know already what the limits of functions are? (pardon if I'm missing the point, this topic has been bugging me since I started studying coding)

Share this post


Link to post
Share on other sites
To follow up what Talonius said, and in reference to the sprite class you see. Every member variable could be 'private' (most restrictive) for this class... and for a finished version they should be.

Having classes that 'expose' the elements (like m_Scaling) instead of exposing the members themselves increases readability and helps control scope.

Example:

// to make a sprite 2x the size, this would work within this example:

// right now this works
someSprite.m_Scaling.f = 2.0f
someSprite.m_Scaling.x = 2.0f

// if there was a function exposed to do it for us, and make the m_Scaling private, then this could be written
someSprite.ScaleSprite(2.0f, 2.0f);






I just made the example as simple as I could right away, but a good rule of thumb is only expose code exactly as much as you have to, and only within the scope that you have to.

To answer your last question... here is why it's done:
If you have less places you can be editing your code outside where it should be, there are less places for bugs to appear. If you can only ever modify / access a variable (say X) in 1 spot... due to scope and access level, then you only ever have to check that 1 spot if you suspect that it's being modified when it shouldn't-- on a very large project, you'll damn near praise it (I know I have).

Also, one could put limits on it. Look at the example above, what if you only ever wanted scale to be less than 2.0? Well... with accessor (function that exposes the private or protected data) you could force it to never go beyond that, with the old method you can't have that control.

Share this post


Link to post
Share on other sites
Alright, I think I see it now. Seems private/protected is pretty much a way to really organize code, in the simliest sense. Thanks for all the help, I learned alot today ^_^.

Share this post


Link to post
Share on other sites
Some cleanup, to make use of RAII, the initializer list, etc.


// A wrapper for D3DXVECTOR2 to make them easier to initialize.
struct vec2 : public D3DXVECTOR2 {
vec2(float x, float y) {
// I don't think this can be done via the initializer list, unfortunately.
this->x = x;
this->y = y;
}
};

class Sprite {
// A helper cleanup function.
// You'll also find this useful if you end up implementing a copy constructor
// and or assignment operator. For now I've assumed that Sprite objects should
// not be copied at all. To make the compiler enforce this, declare those
// functions in the private section and don't implement them, thus:
Sprite(const Sprite&);
Sprite& operator=(const Sprite&);
// Oh yeah, that cleanup function :)
void cleanup() {
if(m_pSprite) { m_pSprite->Release(); }
if(m_pTexture) { m_pTexture->Release(); }
}

protected:
LPD3DXSPRITE m_pSprite; // ID3DXSprite
LPDIRECT3DTEXTURE9 m_pTexture; // sprites texture

public:
// I typically define constructors and destructors inline. You don't have to.
// Note that to avoid having the Sprite class dependant on ("coupled to") the
// main module, I've provided the device as a parameter. You'll be grateful
// for this later if you ever need a second LPDIRECT3DDEVICE9.

Sprite(const char* pathname, LPDIRECT3DDEVICE9 dev) : m_pSprite(0), m_pTexture(0), m_RotCenter(0.0f, 0.0f), m_Translation(0.0f, 0.0f), m_Scaling(1.0f, 1.0f), m_ModulateColor(D3DCOLOR_XRGB(255,255,255)), m_Rotation(0.0f) {
// We shouldn't create the object if we can't get a valid texture and sprite.
if (FAILED(D3DXCreateTextureFromFile(dev, pathname, &m_pTexture)) ||
!m_pTexture) {
throw std::exception("Could not load texture into memory");
// TODO: Make own exception type for this.
}
if(FAILED(D3DXCreateSprite(g_pd3ddevi, &m_pSprite)) || !m_pSprite) {
// Note: need to clean up the texture!
cleanup();
throw std::exception("Could not create the new ID3DXSprite Object");
// Same TODO here.
}
}

~Sprite() { cleanup(); }

vec2 m_RotCenter; // center position
vec2 m_Translation; // translation factor
vec2 m_Scaling; // scaling factor
float m_Rotation; // angle of rotation
D3DCOLOR m_ModulateColor; // the color to modulate with the sprite

bool Render(int x, int y); // renders at a location
bool Render();
};

// Render the sprite at a location.
// Don't need to check validity of pointers; the constructor made sure of them.
bool Sprite::Render(int x, int y) {
vec2 tmp = m_Translation;
m_Translation = vec2(x, y);
boolean result = Render();
m_Translation = tmp; // restore the old translation.
return result;
}

// Render the sprite at its stored location.
bool Sprite::Render() {
m_pSprite->Begin();
bool success = !FAILED(m_pSprite->Draw(m_pTexture, NULL, &m_Scaling,
&m_RotCenter, m_Rotation,
&m_Translation, m_ModulateColor));
// Clean up unconditionally
m_pSprite->End();
return success;
}

// There's too much body code for me to clean up, but example usages then go like:

vector<Sprite> tryCreatingAllSprites(const vector<string>& names) {
vector<Sprite> result;
for (vector<string>::iterator it = names.begin();
it != names.end(); ++it) {
try {
result.push_back(Sprite(*it, g_pd3ddevi));
} catch (std::exception& e) {
MessageBox(0, e.what(), "error", 0);
}
}
// The 'results' now contains Sprite objects corresponding only to those
// files which were successfully loaded.
return result;
}

// Or, for working with a single Sprite, and assuming the creation succeeds...
Sprite x("Sprite bird front.png", g_pd3ddevi);
x.Render(); // at 0,0, because we didn't set it yet
x.m_Translation = vec2(40, 40);
x.Render(); // at 40, 40
x.Render(123, 456); // at 123, 456
x.Render(); // at 40, 40 again!

Share this post


Link to post
Share on other sites

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

Sign in to follow this