Simple directdraw question

Started by
8 comments, last by flucknugget 21 years, 11 months ago
If a Blt() returns an DDERR_INVALIDOBJECT error (DirectDraw received a pointer that was an invalid DirectDraw object), what exactly did I do wrong? DirectDraw initializes without any errors, and it goes into graphics mode and stuff. My DirectDraw stuff is all in a class, including the backbuffer surface, and I retreive it from the class so I can blit to it, but that shouldn''t change anything I don''t think. You don''t pass a DirectDraw object to Blt(), so does that mean it must be an initialization problem? - f l u c k y p o o - the geek inside
- f l u c k y p o o
Advertisement
It''s probably an init prob, yeah. Are you sure that you are checking all the return values against FAILED() macro? And have you checked that the pointer is not NULL? You have to make sure that your source/dest surfaces exist.

____________________________________________________________
Direct3D vs. OpenGL
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Yeah, I did that. I was having lots of trouble trying to figure this out, so I went ahead and wrote an error logging class. At each step of initialization I checked it with the FAILED macro, and if it did I logged the error, and if it didn''t I logged the success. It says everything went successfully. Then before I blit to the backbuffer, when I retreive it from my DirectDraw wrapper class that I''m making, it still says it''s not NULL. My log file looked like this.

DirectDraw interface object created successfully.
DirectDraw cooperative level set successfully.
Display mode set successfully.
Primary surface created successfully.
Backbuffer created successfully.
The backbuffer is alright.
Trying to Blt a surface...
DDERR_INVALIDOBJECT: DirectDraw received a pointer that was an invalid DirectDraw object.
The backbuffer is alright.
Trying to Blt a surface...
DDERR_INVALIDOBJECT: DirectDraw received a pointer that was an invalid DirectDraw object.
etc...


- f l u c k y p o o
- the geek inside
- f l u c k y p o o
What are you blitting, source and destination ?
How about posting the line of code.

,Jay

  HRESULT hr;// get the backbufferLPDIRECTDRAWSURFACE7 lpDDSBack = m_Graphics->GetBack();if(lpDDSBack == NULL)	m_ErrorLog->Write("The backbuffer is NULL.");else	m_ErrorLog->Write("The backbuffer is alright.");// blit the squareRECT DestRect, SourceRect;SetRect(&DestRect, 0, 0, 200, 200);SetRect(&SourceRect, 0, 0, 100, 100);if(FAILED(hr = lpDDSBack->Blt(&DestRect, m_lpDDSTest, NULL, DDBLT_WAIT | DDBLT_KEYSRC, NULL))){	m_ErrorLog->Write("Trying to Blt a surface...");	m_ErrorLog->DDError(hr);}  


m_Graphics is an instance of my CGraphics class. CGraphics::GetBack() returns the backbuffer. m_lpDDSTest is a surface that I created earlier that''s cleared to white.


- f l u c k y p o o
- the geek inside
- f l u c k y p o o

  /* It is assumed that lpDDS is a valid pointer to    an IDirectDrawSurface7 interface. */ HRESULT ddrval;DDPIXELFORMAT ddpf; ddpf.dwSize = sizeof(ddpf);if (SUCCEEDED(lpDSS->GetPixelFormat(&ddpf)){    DDBLTFX ddbltfx;      ddbltfx.dwSize = sizeof(ddbltfx);     ddbltfx.dwFillColor = ddpf.dwBBitMask; // Pure blue     ddrval = lpDDS->Blt(         NULL,        // Destination is entire surface        NULL,        // No source surface        NULL,        // No source rectangle        DDBLT_COLORFILL, &ddbltfx);      switch(ddrval)     {         case DDERR_WASSTILLDRAWING:             .             .             .         case DDERR_SURFACELOST:             .             .             .         case DD_OK:             .             .             .         default:     } }  


I grabbed this code from MSDN, it colourfills a surface with blue. If this fails to work on your code then there is something wrong with the backbuffer, if it works then the test surface is wrong.

Are you sure that GetBack returns a pointer to the backbuffer and shouln''t

LPDIRECTDRAWSURFACE7 lpDDSBack = m_Graphics->GetBack();.
be
LPDIRECTDRAWSURFACE7 *lpDDSBack = m_Graphics->GetBack();

(I could be wrong about this, but I would think that you''d want to return a pointer to the backbuffer rather than the value of the backbuffer, then dereference it at the blt line)

Also test for DD_OK.

,Jay

Ok, thanks, that worked. So it must be my surface class that''s messed up. Well at least that narrows it down a bit. I''ll go and try and fix that now.

quote:Original post by Jason Zelos
Are you sure that GetBack returns a pointer to the backbuffer and shouln''t

LPDIRECTDRAWSURFACE7 lpDDSBack = m_Graphics->GetBack();.
be
LPDIRECTDRAWSURFACE7 *lpDDSBack = m_Graphics->GetBack();

(I could be wrong about this, but I would think that you''d want to return a pointer to the backbuffer rather than the value of the backbuffer, then dereference it at the blt line)

Also test for DD_OK.

,Jay


An LPDIRECTDRAWSURFACE7 isn''t the value of the surface, a DirectDrawSurface7 is, LPDIRECTDRAWSURFACE is a pointer to a DirectDrawSurface7. So you can set LPDIRECTDRAWSURFACE7''s equal to eachother and it''ll just be changing the surface that they''re pointing to, so there''s no need for returning a pointer. But yeah, thanks.


- f l u c k y p o o
- the geek inside
- f l u c k y p o o
Ok, I''m having trouble with my surface class, and I don''t see anything wrong with it. Of course, I just started learning DirectDraw, so it might be kinda hard to catch bugs. I made a class called CSurface used to help me do stuff with LPDIRECTDRAWSURFACE7s, like allocate and destroy them and load them from a file and clear them and draw text to them and stuff. The surface I was trying to blit before was created with this code.

CSurface Surface(*m_ErrorLog);
Surface.SetSurface(m_lpDDSTest);
Surface.Create(m_lpDD, 100, 100);
Surface.Clear(m_lpDD, Surface.MakeColor(255, 255, 255));

The CSurface class has a private LPDIRECTDRAWSURFACE7 called m_lpDDS, and when you call the constructor it sets it to NULL. That constructor passes a CErrorLog class I made along, which enables error logging to help me debug it. The SetSurface function sets m_lpDDS to the surface you pass it. Here''s my create function.


  void CSurface::Create(LPDIRECTDRAW7 lpDD, int Width, int Height){	Destroy();	// create a surface description	DDSURFACEDESC2 ddsd;	memset(&ddsd, 0, sizeof(DDSURFACEDESC2));	ddsd.dwSize			= sizeof(DDSURFACEDESC2);	ddsd.dwFlags		= DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;	ddsd.ddsCaps.dwCaps	= DDSCAPS_OFFSCREENPLAIN;	ddsd.dwWidth		= Width;	ddsd.dwHeight		= Height;		HRESULT hr;	if(FAILED(hr = lpDD->CreateSurface(&ddsd, &m_lpDDS, NULL)))	{		if(m_ErrorLogging)		{			m_ErrorLog->Write("Failed creating the surface because:");			m_ErrorLog->DDError(hr);		}	}	else	{		if(m_ErrorLogging)		{			m_ErrorLog->Write("Surface created successfully.");		}	}}  


As far as I can tell, this should work fine. It doesn''t return a bad HRESULT or anything, and it doesn''t crash or anything like that. Destroy just released the surface if it''s NULL, to make sure it doesn''t try allocating over itself. Now here''s my clear function.


  void CSurface::Clear(LPDIRECTDRAW7 lpDD, DWORD Color){	// create a bltfx structure	DDBLTFX ddbltfx;	memset(&ddbltfx,0,sizeof(DDBLTFX));	ddbltfx.dwSize = sizeof(DDBLTFX);	ddbltfx.dwFillColor = Color;	// clear the surface	HRESULT hr;	if(FAILED(hr = m_lpDDS->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT | DDBLT_ASYNC, &ddbltfx)))	{		if(m_ErrorLogging)		{			m_ErrorLog->Write("Failed clearing the surface because:");			m_ErrorLog->DDError(hr);		}	}	else	{		if(m_ErrorLogging)		{			m_ErrorLog->Write("Surface cleared successfully.");		}	}}  


In order to make the color that you pass it, I made a function in CSurface that creates a color based on the pixel format of the surface in memory.


  DWORD CSurface::MakeColor(int Red, int Green, int Blue){	DDPIXELFORMAT ddpf;	memset(&ddpf, 0, sizeof(DDPIXELFORMAT));	m_lpDDS->GetPixelFormat(&ddpf);		// multiply color components by max ddpixel value (the mask)	Red		*= ddpf.dwRBitMask;	Green	*= ddpf.dwGBitMask;	Blue	*= ddpf.dwBBitMask;	// divide by max colorref(255)	Red	/= 255;	Green	/= 255;	Blue	/= 255;	// logical and with mask, to avoid fractions	Red	&= ddpf.dwRBitMask;	Green	&= ddpf.dwGBitMask;	Blue	&= ddpf.dwBBitMask;	// merge together, and return the result	return(Red | Green | Blue);}  


I pretty much got this code from Isometric Game Programming with DirectX 7, and changed it around a little bit. I''m not totally sure how the whole memory manipulation stuff works to set certain bits to create a color, but a function close enough to this works in their examples, so I''m assuming it should be fine.

Oh yeah, and the error log. I made a class called CErrorLog that has two member functions other than the constructor and destructor, Write and DDError. Write just prints whatever string you pass it to a file. I made a big switch statement with all the directdraw errors in it, so DDError lets you pass it an HRESULT and it''ll print the error returned and it''s description to a file.

Do you see any reason why Blt might consider that a surface created and cleared in this manner to be invalid?


- f l u c k y p o o
- the geek inside
- f l u c k y p o o
Where do you define the surface, I cannot see it here.
void CSurface::Create(LPDIRECTDRAW7 lpDD, int Width, int Height)   

Should there be a return LPDIRECTDRAWSURFACE7 rather than a void.

Other bits
How about replacing the makecolor function with an actual number, that will eliminate one possibility, or comment out the clear function.

Something I thought of, If surfaces are lost you have to reload them into memory, usualy when ALT-TABing or in window'd mode, could this be the problem (It only applies to non-primary/backbuffer surfaces).

Sorry about the pointer rubbish, I wasn't sure about it .


,Jay

Edit: Ok, I just realised you answered the first point already, but what does SetSurface do ? (code)


[edited by - Jason Zelos on May 3, 2002 3:13:18 PM]

[edited by - Jason Zelos on May 3, 2002 3:17:53 PM]
I think I''ve figured it out, When you blit you use ''m_lpDDSTest'', but even if thats the name of your class it wont work, you need to pass the LPDIRECTDRAWSURFACE7 class varible thats inside your class (thats what I thought you were doing thus the pointer rubbish).

,Jay

This topic is closed to new replies.

Advertisement