Sign in to follow this  
kingpinzs

How do I get 2 class's to talk to each other with Direct3D objects?

Recommended Posts

I am atempting to make 2 c++ class's and I need data from one into another. I have class A
class Draw
{
private:
	LPDIRECT3D9 d3d;
	LPDIRECT3DDEVICE9 d3ddev;
	LPDIRECT3DSURFACE9 backbuffer;
	LPD3DXSPRITE spriteobj;
public:
	Draw(HWND hwnd,int width,int height,bool fullscreen)
	{
		d3d = NULL;
		d3ddev = NULL;
		backbuffer = NULL;
		spriteobj = NULL;
		Direct3D_Init(hwnd,width,height,fullscreen);
	}

	bool Direct3D_Init(HWND,int,int,bool);
	void Direct3D_Shutdown();
	LPDIRECT3DSURFACE9 LoadSurface(string filename);
    void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);
    LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));

};

that needs to send data to class B
class Font
{

private:
	//font variables
LPD3DXFONT font;
LPDIRECT3DDEVICE9 *d3ddev;
LPD3DXSPRITE *spriteobj;

public:

	Font(string name, int size)
	{
		MakeFont(name,size);
	}
	//font functions
    LPD3DXFONT MakeFont(string name, int size);
    void FontPrint( int x, int y, string text, D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));
	void getInfo(LPDIRECT3DDEVICE9 *d3ddev, LPD3DXSPRITE *spriteobj);
};

the data I need is the LPDIRECT3DDEVICE9 and LPD3DXSPRITE passed from a to b and also should I call a pointer or by reference? I am not sure I need to change it or just need the info of it Here are the class functions that need the data
LPD3DXFONT Font::MakeFont(string name, int size)
{
    LPD3DXFONT font = NULL;

    D3DXFONT_DESC desc = {
        size,                   //height
        0,                      //width
        0,                      //weight
        0,                      //miplevels
        false,                  //italic
        DEFAULT_CHARSET,        //charset
        OUT_TT_PRECIS,          //output precision
        CLIP_DEFAULT_PRECIS,    //quality
        DEFAULT_PITCH,          //pitch and family
        ""                      //font name
    };

    strcpy(desc.FaceName, name.c_str());

    D3DXCreateFontIndirect(d3ddev, &desc, &font);

    return font;
}

void Font::FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color)
{
    //figure out the text boundary
    RECT rect = { x, y, 0, 0 };
    font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color); 

    //print the text
    font->DrawText(spriteobj, text.c_str(), text.length(), &rect, DT_LEFT, color); 
}

Share this post


Link to post
Share on other sites
I would either make a CreateFont() function in the Draw class (Which will create a new Font and set the sprite pointer), or make the Draw class a singleton or globally accessible. The former is much more preferable...

Share this post


Link to post
Share on other sites
Since your project will use the DX Font stuff, why not make your DirectX rendering class do *all* work which require the d3d device, and your font class only generate data for it?

Write a font drawing function that accepts coordinates, a string, and maybe a style.
Then have your font class generate that data.

That way you have all the functionality your Font class wants, and on top of it all, you can then use the new drawing function for any object that wants font output.

That way you don't have to implement it for every object that needs one.

Share this post


Link to post
Share on other sites
Yes, thats also a solution, but not a good one. For a small and tiny game it may works good, but whats when you have a class for drawing the HUD? How should this draw text then? And putting the HUD-class onto the general Draw-Class is also a bad idea. That would make becoming it too big and unreadable. The common solution would look like this:

(Typed right of my head)

class Font
{
public:
//Do initialization here
HRESULT InitFont(LPDIRECT3DDEVICE9 Device,Foo foo foo....);

//Render here
HRESULT RenderFont(D3DXVECTOR2 Position, blah blah);

//Needed variables
LPD3DXFONT font;
LPDIRECT3DDEVICE9* d3ddev;
LPD3DXSPRITE* spriteobj;

};



and to use it, you would have to do this:


//Class-decleration:
Font HudFont;
...

//Somewhere else
void MyGame::InitGame()
{
HudFont.InitFont(d3ddev,blah blah);
}

void MyGame::RenderGame()
{
SomeObject->RenderMe(&HudFont); //Render some object which needs access to the font
}


Share this post


Link to post
Share on other sites
thanks for all the help.

What is the syntax to send the data from draw to font class or do I need to get the data.

What I am trying to say is do I use the font class to get the data or do I use the drawclass to push the data?

Share this post


Link to post
Share on other sites
Just look at my examples. I show both ways there:

-How to use your Font-Class inside another class (&Font <= Pointer)
-How to pass the device to the font class

When you are inside some class and you need it, the function which could use it, could look like this:


void SomeClass::RenderMe(Font* HudFont, .....)
{
HudFont->DoSomething();
}



So, where is the problem?

Oh, and a tipp: I've set up a general struct which holds pointer to some very important things in my engine. Its easier to use such a thing than pass hundreds of parameters to a function. Every object gets the pointer to that struct and is able to access the things it holds. Anyways, you don't need such a struct. Not, when you don't have a large Actor-system or many classes which need many DX things.

Put some parameters in you function and it should be nice :)

Share this post


Link to post
Share on other sites
I have tryed a few things now and nothing works.

in the font class I am trying to have the pointer point to the device that the draw function returns

same goes with the sprite function

This is how I am trying to do it

draw class

LPDIRECT3DDEVICE9 get_device()
{return d3ddev;}

LPD3DXSPRITE get_sprObj()
{ return spriteobj;}



font class


Font()
{
*d3ddev = dd3.get_device();
*spriteobj = dd3.get_sprObj();
}


Share this post


Link to post
Share on other sites
Yes, this is right. But one thing:


LPDIRECT3DDEVICE9 *d3ddev;
LPD3DXSPRITE *spriteobj;

....

Font()
{
*d3ddev = dd3.get_device();
*spriteobj = dd3.get_sprObj();
}



Why *? The LPDIRECT3DDEVICE9 is already a pointer. Everything LP... with an uppercased name is a pointer. You don't need a pointer to a pointer here.

Share this post


Link to post
Share on other sites
This part of the code is giving me issues now


void Font::FontPrint( int x, int y, string text, D3DCOLOR color)
{
//figure out the text boundary
RECT rect = { x, y, 0, 0 };
font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color);

//print the text
font->DrawText(spriteobj, text.c_str(), text.length(), &rect, DT_LEFT, color);
}



I call the above from here


void Game_Run(HWND window)
{
if(NewGame.Start())
{

normal.FontPrint(100,300,"Endgame");

NewGame.End();
}
}



its saying that the
font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color);

has

Unhandled exception at 0x000e2935 in class_Test.exe: 0xC0000005: Access violation reading location 0x00000000.

I am not sure what this means?

I started everything properly I believe but it still not getting the data passed like it should

Share this post


Link to post
Share on other sites
Quote:
Original post by kingpinzs
looks like the device info sent to font is all null according to the debugger.

Why would that be?
Use the debugger and find out?

Also, in this line:
*d3ddev = dd3.get_device();
d3ddev is a pointer to an LPDIRECT3DDEVICE9? Why make it a pointer? Why not just a LPDIRECT3DDEVICE9?
Also, if you're passing around COM interfaces like that, it's a good idea to AddRef() and Release(), or - better - use a smart pointer.

Share this post


Link to post
Share on other sites
Quote:

Also, if you're passing around COM interfaces like that, it's a good idea to AddRef() and Release()


Thats something I don't understand. Isn't is easier when I create all my DirectX-COM interfaces in the according classes (Like font, Mesh, etc) and don't do AddRef() when giving a pointer to it away? When the (For example) Mesh class gets destroyed it could call Release() on all objects it created. And I wouldn't have to matter about what happens when the pointer I gave away gets out of the scope. Even DXUT doesn't does AddRef(). So please tell me why we all should do it? Maybe there are critical things I don't know...

Share this post


Link to post
Share on other sites
Quote:
Original post by mind in a box
Thats something I don't understand. Isn't is easier when I create all my DirectX-COM interfaces in the according classes (Like font, Mesh, etc) and don't do AddRef() when giving a pointer to it away? When the (For example) Mesh class gets destroyed it could call Release() on all objects it created. And I wouldn't have to matter about what happens when the pointer I gave away gets out of the scope. Even DXUT doesn't does AddRef(). So please tell me why we all should do it? Maybe there are critical things I don't know...
So long as you are 100% sure that your device won't be Release()d when there's other objects like your mesh class still using it, it's fine.
If you're not 100% sure though, then you could end up in a situation where you Release() your device, then try to do something to a mesh which makes a call to the device - which has already been released, and you get an access violation (If you're lucky - if you're unlucky it'll work fine on your machine and then crash on some users machine where you can't debug it).

EDIT: Really, DXUT doesn't use AddRef()? That surprises me...

Share this post


Link to post
Share on other sites
Use the debugger and find out?

The debugger says that when I call the draw class it gets created but when I have the font class get the debvice and spriteobj it does not get passed.
Other then that I am not sure how to use the debugger to find out why. I stped through the program and it just failes as soon as i call to display the font on the screen

Also, in this line:
*d3ddev = dd3.get_device();
d3ddev is a pointer to an LPDIRECT3DDEVICE9? Why make it a pointer? Why not just a LPDIRECT3DDEVICE9?

I wasnt sure how to point to a pointer with out making it a pointer but now i see that I did make it a pointer
so its LPDIRECT3DDEVICE9 d3ddev; now

Also, if you're passing around COM interfaces like that, it's a good idea to AddRef() and Release(), or - better - use a smart pointer.

No idea what a smart pointer is.


also


void Font::FontPrint(int x, int y, string text, D3DCOLOR color)
{
//figure out the text boundary
RECT rect = { x, y, 0, 0 };
"It failes right here ->" font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color);

//print the text
font->DrawText(spriteobj, text.c_str(), text.length(), &rect, DT_LEFT, color);
}





Share this post


Link to post
Share on other sites
Quote:
Original post by kingpinzs
The debugger says that when I call the draw class it gets created but when I have the font class get the debvice and spriteobj it does not get passed.
Other then that I am not sure how to use the debugger to find out why. I stped through the program and it just failes as soon as i call to display the font on the screen
Well, it'll fail because your pointer is NULL. What do you mean by "the font class get the debvice and spriteobj it does not get passed"? You'll need to step through your code and check that the "device pointer sent to the font" is valid (not null) everywhere you think it should be.

Quote:
Original post by kingpinzs
No idea what a smart pointer is.
Smart Pointer

Share this post


Link to post
Share on other sites
Because LPDIRECT3DDEVICE9 is a typdef:

typdef LPDIRECT3DDEVICE9 IDirect3DDevice9*
(Not sure about the names, but that how it is)

@EvilSteve:

I read this in the DXUT documentation:

Quote:

DXUTGetD3D10Device

Get a pointer to the ID3D10Device interface that represents the current device.

Syntax

ID3D10Device * DXUTGetD3D10Device()


Return Value
Pointer to the ID3D10Device that represents the current Direct3D 10 device. NULL is returned if no Direct3D 10 device has been created.

Remarks
Only one device can be active in DXUT at a time so either this function or DXUTGetD3D9Device will return NULL.

This function exposes access to a global ID3D10Device object. The reference count on this device interface is not incremented, so a calling function should not release the ID3D10Device interface pointer returned by this function.

Requirements
Header: Declared in DXUT.h.



You can find that on any DXUTGet*() function.

PS: Good, that I am pretty sure that my device doesn't get released when my engine is running :)

Share this post


Link to post
Share on other sites
Quote:
Original post by mind in a box
@EvilSteve:

I read this in the DXUT documentation:

[snip]

You can find that on any DXUTGet*() function.

PS: Good, that I am pretty sure that my device doesn't get released when my engine is running :)
Ah - I expect that's because DXUT is for setting up the basic device framework, and it's easier to not increment the reference count. If you were using the device for anything much more involved, I'd say you should be calling AddRef() yourself.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
What do you mean by "the font class get the debvice and spriteobj it does not get passed"? You'll need to step through your code and check that the "device pointer sent to the font" is valid (not null) everywhere you think it should be.



I thought it was getting created but I geuss not


Draw NewGame(window,SCREENW,SCREENH,false); "<- device is created"
"between the NewGame and normal device is nulled out have no idea why."
Font normal;

bool Game_Init(HWND window)
{

normal.Font_Init("Arial",24);

return true;
}


void Game_Run(HWND window)
{
if(NewGame.Start())
{

normal.FontPrint(100,300,"Endgame");

NewGame.End();
}
}

void Game_End()
{

}






class Draw
{
private:

LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;
LPDIRECT3DSURFACE9 backbuffer;
LPD3DXSPRITE spriteobj;
public:
Draw()
{
d3d = NULL;
d3ddev = NULL;
backbuffer = NULL;
spriteobj = NULL;

}

Draw(HWND hwnd,int width,int height,bool fullscreen)
{

Direct3D_Init(hwnd,width,height,fullscreen);

}

bool Direct3D_Init(HWND,int,int,bool);

LPDIRECT3DDEVICE9 get_device()
{return d3ddev;}
LPD3DXSPRITE get_sprObj()
{ return spriteobj;}

bool Start(){
if(d3ddev->BeginScene())
return true;
else
return false;
}

void End(){
spriteobj->End();

d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
void Start_Sprite(){
spriteobj->Begin(D3DXSPRITE_ALPHABLEND);
}

void Direct3D_Shutdown();
LPDIRECT3DSURFACE9 LoadSurface(string filename);
void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);
LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));


};

#endif





bool Draw::Direct3D_Init(HWND window, int width, int height, bool fullscreen)
{
//initialize Direct3D
d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d) return false;

//set Direct3D presentation parameters
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.hDeviceWindow = window;
d3dpp.Windowed = (!fullscreen);
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.EnableAutoDepthStencil = 1;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;

//create Direct3D device
d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
if (!d3ddev) return false;


//get a pointer to the back buffer surface
d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

//create sprite object
D3DXCreateSprite(d3ddev, &spriteobj);

return 1;
}


Share this post


Link to post
Share on other sites
So after a few days I have figured out why the device was being nulled out

first I created the device then in the font class I called the device again
which the called the constructor again and that nulled out the device

What I need to do is inherit the device from draw to font.

But I am not sure how to do this yet

Any ideas?

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