Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

DirectX Vertex Buffer Wrapper: runtime error

Started by Chad Smith Mar 28, 2007 at 6:58 PM 1 replies 2.1k views
Original Post
Chad Smith
Chad Smith
Hey, I have been learning DirectX lately, so I have been writting a DirectX wrapper also. I have one going for the window. That was really simple. Anyway, I decided to go ahead and take my hand at trying to write a Vertex Buffer wrapper, so that way it will be a little bit easier for me to draw some simple shapes before I get into .X loading. Anyway...before I added the Vertex Buffer, my window worked just fine. Now that I did...it seems like it freezes or something. I am actually not really sure what is going on. All I know is that it's not even getting to the render loop. It won't even clear my screen like it used to. That reason alone has led me to believe that it is the Vertex Buffer. I will also include the window loading code, the demo I am using the wrapper in, and my vertex buffer class information. Let's begin. :) VertexBuffer.h

/*VertexBuffer.h
*this file is here for the class declaration of the VertexBuffer
*This will lie in the EGLGraphics namespace  TODO: Add the EGLGraphics Namespace!!!!
*help us get a vertex buffer up fast, and set an index buffer if we need it
*/

//inclusion guards
#ifndef VERTEXBUFFER_H
#define VERTEXBUFFER_H

//include the needed directX header files
#include <d3d9.h>
#include <d3dx9.h>

//start the vertex buffer class
class VertexBuffer
{
	//public mode
public:
	//constructor
	VertexBuffer();
	//destructor
	~VertexBuffer() {Release();}

	//create a vertex buffer
	bool CreateVertexBuffer(LPDIRECT3DDEVICE9 theDevice, UINT numVertices, DWORD FVF, UINT vertexSize, bool dynamic=false);
	//release the buffer
	void Release();
	//set the data
	bool SetData(UINT numVertices, void* vertices, DWORD flags=D3DLOCK_DISCARD);
	//render the vertex buffer
	void Render(LPDIRECT3DDEVICE9 theDevice, UINT numPrimitives, D3DPRIMITIVETYPE primitiveType);

	//private mode
private:
	//vertex buffer
	LPDIRECT3DVERTEXBUFFER9 VB;
	//number of verticies to use
	UINT numberVertices;
	//vertex size
	UINT vertexSize;
	//the vertex FVF
	DWORD FVF;
};

#endif

VertexBuffer.cpp (Where I think where the problem could lie...)

/*Vertexbuffer.cpp
*used for the class definition of the VertexBuffer
*/

//includes
//include the VertexBuffer.h 
#include "VertexBuffer.h"

//the default constructor
VertexBuffer::VertexBuffer()
{
	this->VB=NULL;
	this->numberVertices=0;
	this->FVF=0;
	this->vertexSize=0;
}

//create a vertex buffer
//return true if it works, and false if not
bool VertexBuffer::CreateVertexBuffer(LPDIRECT3DDEVICE9 theDevice, UINT numVertices, DWORD FVF, UINT vertexSize, bool dynamic)
{
	//release any other vertex buffer
	Release();
	this->numberVertices=numVertices;
	this->FVF=FVF;
	this->vertexSize=vertexSize;

	//check to make sure we do not have a dynamic buffer, as they can not be used in D3DPOOL_MANAGED
	D3DPOOL pool=dynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
	DWORD usage=dynamic ? D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC : D3DUSAGE_WRITEONLY;
	//check to makes ure the vertex buffer was created
	if(FAILED(theDevice->CreateVertexBuffer(this->numberVertices*this->vertexSize, usage, this->FVF, pool, &VB, NULL)))
	{
		//if we are in here, then the vertex buffer was not created, and we need to exit
		return false;
	}
	return true;
}

//clean up all the resources we created
void VertexBuffer::Release()
{
	VB->Release();
	this->numberVertices=0;
	this->FVF=0;
	this->vertexSize=0;
}

//now fill the vertex buffer with data
bool VertexBuffer::SetData(UINT numVertices, void *vertices, DWORD flags)
{
	//if there is no vertexbuffer, we need to go ahead and exit
	if(this->VB==NULL)
	{
		return false;
	}
	char* data;
	//lock the vertex buffer, so we can wright stuff to it
	if(FAILED(this->VB->Lock(0, 0, (void**)&data, flags)))
	{
		//if we are in here, then we could not lock the vertex buffer.  exit
		return false;
	}

	//now copy the vertices to the vertex buffer
	memcpy(data, vertices, numVertices*vertexSize);
	
	//unlock the vertex buffer
	if(FAILED(VB->Unlock()))
	{
		//if we are in here, we could not unlock the vertex buffer
		//so get out
		return false;
	}
	return true;
}

//render the buffer
void VertexBuffer::Render(LPDIRECT3DDEVICE9 theDevice, UINT numPrimitives, D3DPRIMITIVETYPE primitiveType)
{
	//if we have a null device, then get out of this function
	if(theDevice==NULL)
	{
		return;
	}
	//set the stream source for the vertex buffer
	theDevice->SetStreamSource(0, this->VB, 0, this->vertexSize);
	//the FVF to use
	theDevice->SetFVF(this->FVF);

	theDevice->DrawPrimitive(primitiveType, 0, numPrimitives);
}

EGLWindow.h

/*EGLWindow.h
*this file is uses for the window class for the EGL Library
*the window class will lie in the EGL namespace
*/

//inclusion guards
#ifndef EGLWINDOW_H_
#define EGLWINDOW_H_

//now include all of the usefull header files that we will need.  
//iostream
#include <iostream>
//windows
#include <windows.h>
//DirectX header files
#include <d3d9.h>
#include <d3dx9.h>
//SDL header file
#include <SDL/sdl.h>

//start the EGL namespace
namespace EGL
{
	//the EGL windows class
	class EGLWindow
	{
		//first is public mode
	public:
		//the constructor
		EGLWindow(int width, int height);
		//the destructor
		~EGLWindow();

		//init the window
		bool InitWindow();

		//getters
		//get the window width
		int GetWidth() {return eglWidth;}
		//get the windows height
		int GetHeight() {return eglHeight;}
		//get the windows Direct3D Device
		IDirect3DDevice9* GetDevice() {return d3dDevice;}


		//private mode
	private:
		//the very important variables that we will need
		//first a Direct3D9 object
		IDirect3D9* d3dObject;
		//the Direct3D9Device
		IDirect3DDevice9* d3dDevice;
		//the present parameters, for device properties
		D3DPRESENT_PARAMETERS presentParameters;
		//hold the windows width
		int eglWidth;
		//height
		int eglHeight;
	};
	//end class
	//end namespace for this header file
}

#endif

EGLWindow.cpp

/*EGLWindow.cpp
*used for the class and/or namespace definitions for the EGLWindow.h file
*/

//the includes
//I only need to include the EGLWindow.h file
#include "EGLWindow.h"

//use the std namespace
using namespace std;

//start the defintions now
//the constructor
EGL::EGLWindow::EGLWindow(int width, int height)
{
	//first we need to set all variables/pointers to something
	eglWidth=width;
	eglHeight=height;
	d3dObject=NULL;
	d3dDevice=NULL;
	//first, we need to Init SDL
	//init all the subsystems
	SDL_Init(SDL_INIT_EVERYTHING);
}

//the destructor
EGL::EGLWindow::~EGLWindow()
{
}

bool EGL::EGLWindow::InitWindow()
{
	//set the video info
	SDL_SetVideoMode(eglWidth, eglHeight, 32, NULL);

	//now we init the Direct3D stuff
	//the Direct3DObject
	d3dObject=Direct3DCreate9(D3D_SDK_VERSION);
	if(d3dObject==NULL)
	{
		MessageBox(GetActiveWindow(), L"Error-Could not create a Direct3D Object", L"Direct3D Error", MB_OK);
		return false;
	}
	cout<<"The object was created"<<endl;
	//set the device parameters
	//clear out the structer
	ZeroMemory(&presentParameters, sizeof(presentParameters));
	presentParameters.Windowed=true;
	presentParameters.SwapEffect=D3DSWAPEFFECT_DISCARD;
	presentParameters.EnableAutoDepthStencil=true;
	presentParameters.AutoDepthStencilFormat=D3DFMT_D24S8;
	presentParameters.hDeviceWindow=::GetActiveWindow();
	presentParameters.BackBufferWidth=eglWidth;
	presentParameters.BackBufferHeight=eglHeight;
	presentParameters.BackBufferFormat=D3DFMT_A8R8G8B8;
	presentParameters.MultiSampleType=D3DMULTISAMPLE_NONE;
	presentParameters.BackBufferCount=1;
	presentParameters.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
	//create the Direct3DDevice
	if(FAILED(d3dObject->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetActiveWindow(), D3DCREATE_SOFTWARE_VERTEXPROCESSING,
									  &presentParameters, &d3dDevice)))
	{
		MessageBox(GetActiveWindow(), L"Error-Could not create the Direct3D Device", L"Direct3D Error", MB_OK);
		return false;
	}
	cout<<"The device was created..."<<endl;
	//we are done with the direct3D object now
	d3dObject->Release();
	cout<<"Object Released..."<<endl;
	return true;
}

EGL.h (The main file for the EGL Library

/*EGL.h
*this is the main header file
*this is where general functions are defined
*for the EGL Namespace
*/

//inclusion guards
#ifndef EGL_H_
#define EGL_H_

//include DirectX stuff
#include <d3d9.h>
//include the eglwindow stuff
#include "EGLWindow.h"

//start the EGL namespace
namespace EGL
{
	//make a IDirect3DDevicee also be a EGLDevice
	typedef IDirect3DDevice9* EGLDevice;
	//a Direct3DDevice to use instead of the real one
	EGLDevice referenceDevice;

	//start a window for us automatically
	bool InitEGLWindow(int width, int height)
	{
		EGLWindow appWindow(800, 600);
		if(appWindow.InitWindow()==false)
		{
			return false;
		}
		//now set the reference device to a device
		referenceDevice=appWindow.GetDevice();
		std::cout<<appWindow.GetDevice()<<std::endl;
		std::cout<<referenceDevice<<std::endl;
		return true;
	}

	//clear the whole screen function
	void ClearScreen(IDirect3DDevice9* theDevice, D3DCOLOR theColor)
	{
		theDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, theColor, 1.0f, 0);
	}

	//begin rendering the whole screen function
	void BeginRender(IDirect3DDevice9* theDevice)
	{
		theDevice->BeginScene();
	}

	//end all the rendering stuff
	void EndRender(IDirect3DDevice9* theDevice)
	{
		theDevice->EndScene();
	}

	//present the details to the user
	void Present(IDirect3DDevice9* theDevice)
	{
		theDevice->Present(NULL, NULL, NULL, NULL);
	}

	//clear to a RGB color
	inline D3DCOLOR ClearRGBColor(int r, int g, int b)
	{
		return D3DCOLOR_XRGB(r,g, b);
	}

	//templated release function, to release certain stuff
	template<class T> void Release(T t)
	{
		if(t)
		{
			t->Release();
			t=0;
		}
	}
}


#endif


The Demo file

//this is the demo for the EGL library
//include iostream
#include <iostream>
//first include the EGL.h file, as that is the main file
#include "EGL.h"
//the vertex and index buffer information
#include "VertexBuffer.h"
#include "IndexBuffer.h"

//struct for the custom vertex
struct Vertex
{
	Vertex() {}
	Vertex(float _x, float _y, float _z)
	{
		x=_x; y=_y; z=_z;
	}
	float x, y, z;
};
//CONSTANT TO HOLD THE FVF FOR THE CUSTOM VERTEX
const DWORD FVF=D3DFVF_XYZ;

//start main
int main(int argc, char* argv[])
{
	//create a SDL_Event, so we can poll for events and handle input
	SDL_Event evnt;

	//CONSTANTS TO HOLD THE WINDOWS WIDTH AND HEIGHT AND ASPECT RATIO
	const int WIDTH=800;
	const int HEIGHT=600;
	const float ASPECTRATIO=(float)WIDTH/(float)HEIGHT;

	//init the window using the built in InitWindow from EGL's namespace
	EGL::InitEGLWindow(800, 600);
	if(EGL::referenceDevice==NULL)
	{
		std::cout<<"the device is null...we need out..."<<std::endl;
		return 1;
	}

	//create a triangle
	Vertex triangle[3];
	triangle[0]=Vertex(-2.0f, -2.0f, 5.0f);
	triangle[1]=Vertex(0.0f, 2.0f, 5.0f);
	triangle[2]=Vertex(-2.0f, 2.0f, 5.0f);


	//setup the Vertex and Index Buffers
	VertexBuffer vertexBuffer;
	vertexBuffer.CreateVertexBuffer(EGL::referenceDevice, 6, FVF, sizeof(Vertex));
	vertexBuffer.SetData(3, triangle);

	std::cout<<"Just created the index/vertex buffer(s)"<<std::endl;

	//now position and aim the camera
	//the position vector
	//move it further back, so we can see the whole scene
	D3DXVECTOR3 position(0.0f, 0.0f, -5.0f);
	//aim the camera at the orgin (0, 0, 0)
	D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
	//the y-axis is up
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
	//view matrix
	D3DXMATRIX view;
	//define where the camera should look at 
	D3DXMatrixLookAtLH(&view, &position, ⌖, &up);

	//set to transform to the view matrix now
	EGL::referenceDevice->SetTransform(D3DTS_VIEW, &view);

	//projection matrix
	D3DXMATRIX projection;
	D3DXMatrixPerspectiveFovLH(&projection, D3DXToRadian(90), ASPECTRATIO, 1.0f, 1000.0f);
	//projection transform
	EGL::referenceDevice->SetTransform(D3DTS_PROJECTION, &projection);
	EGL::referenceDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

	std::cout<<"window is now inited, and about to enter game loop"<<std::endl;
	//before we loop, make sure are device is not null
	if(EGL::referenceDevice==NULL)
	{
		std::cout<<"device is null...QUIT..."<<std::endl;
		return 1;
	}
	//now loop while we are not done
	while(1)
	{
		//while there is a event the check
		while(SDL_PollEvent(&evnt))
		{
			if(evnt.type==SDL_QUIT)
			{
				return 0;
			}
			break;
		}
		D3DXMATRIX rotationX, rotationY;
		//rotate 45 degrees along the x-axis
		static float x=0.0f;
		D3DXMatrixRotationX(&rotationX, x);
		x+=0.05f;
		//increatment the y-rotation angle
		static float y=0.0f;
		D3DXMatrixRotationY(&rotationY, y);
		y+=0.05f;
		if(y>=6.28f)
		{
			y=0.0f;
		}

		//combine rotations
		D3DXMATRIX combined=rotationX*rotationY;
		EGL::referenceDevice->SetTransform(D3DTS_WORLD, &combined);
		EGL::ClearScreen(EGL::referenceDevice, EGL::ClearRGBColor(0, 255, 0));
		EGL::BeginRender(EGL::referenceDevice);
		vertexBuffer.Render(EGL::referenceDevice, 12, D3DPT_TRIANGLELIST);
		EGL::EndRender(EGL::referenceDevice);
		EGL::Present(EGL::referenceDevice);
	}
	vertexBuffer.Release();
	//release the device with a homemade templated release function
	EGL::Release<EGL::EGLDevice>(EGL::referenceDevice);
	return 0;
}

I am far aware of some of the bad coding techniques being used, though some more helpful hints would ALWAYS be appreciated. Do any of y'all know what is wrong? Any help is AMAZING and of course appreciated. Oh yikes. Almost forgot the runtime error that Visual C++ Express Edition is throwing at me.

Unhandled exception at 0x0041341d in EGL.exe: 0xC0000005: Access violation reading location 0x00000000.
From what that is saying...it does seem like there is a NULL pointer somewhere. My first thought was the reference device I was using. But where I output both of the addresses of the devices (reference, and real one) to make sure they are the same, it dosen't output it as a NULL pointer, and both addressse are the same. The output my program throws out in the console window is:

Object Created
Device Created
Object Released
*address here
*address here (same as the first)
I tried debugging this...but I am not really sure/good on debugging this kind of stuff. I'm still really learning the debugging ways, but getting a little better. Again...any help is appreciated. Chad.
Xrystal
Xrystal
You might want to check all your assignments and releases. At first glance to me it looks like you are trying to release something that hasn't been assigned.

What I usually do with objects is to first assign them as NULL and then when I want to release them I test the NULL status and only release if it isn't NULL and then set it to NULL.

eg.
LPDIRECT3DDEVICE9 pDevice = NULL;....if (pDevice) pDevice->Release();pDevice = NULL;


Some tutorials or examples have the release code set up as a macro to automatically test and release as required with one line of code. You could do something similar with your own objects by using delete on an object when it has been newed.

eg.
CMyObject* pObject = NULL;....pObject = new CMyObject(...);....if (pObject) delete pObject;pObject = NULL;


I hope that helps you in some way. I'm sure someone else will have spotted something else that my quick glance didn't see.
Chad Smith
Chad Smith
thanks for the reply. I have been spending some time looking at the assignments and stuff lately. I'll post here if I figure anything out.


Chad.

EDIT: I tried debugging a couple more times and I finally recieved some usefull information.

The Problem:

VB->Release();

I was releasing it if it was null. And in the createvertexbuffer function, I was releasing it...and since it wasn't created yet, it was still NULL. Adding a if(VB!=NULL) {VB->Release();} to the release function fixed it. Thanks a lot dude!!! rate++;

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.