Trying to draw a simple textured quad, problems

Started by
8 comments, last by footlead 20 years, 6 months ago
I''m obviously a newbie to this, but I''ve been trying to get a textured quad to show up in DirectX 9 for the longest time.. and I don''t understand what I''m doing wrong. I have 2 classes that are supposed to do this, a Display class and a Sprite class. As of now, the display class holds a vertex buffer for 4 sprite vertices that ALL my sprite objects access (obviously there must do so one at a time). I don''t know if that actually makes things more efficient or not. Anyway here is the code (scattered across various functions in different classes): Defined sprite vertex:

typedef struct
{
  float x, y, z;    // 3-D coordinates

  DWORD diffuse;	// diffuse color component

  float u, v;       // Texture coordinates

} spriteVertex;

#define SPRITEFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
The setting up stuff:

	if (FAILED(_d3ddevice->CreateVertexBuffer( (sizeof (spriteVertex)) * 4, D3DUSAGE_WRITEONLY, 
												SPRITEFVF, D3DPOOL_MANAGED, &_spritevertexbuffer, 
												NULL)))
		return FALSE;
// set stream source

	if (FAILED (_d3ddevice->SetStreamSource(0, _spritevertexbuffer, 0, sizeof (spriteVertex))))
		return FALSE;
	if (FAILED (_d3ddevice->SetFVF(SPRITEFVF)))
		return FALSE;

	_d3ddevice->SetTextureStageState( 0, D3DTSS_COLORARG1,	D3DTA_TEXTURE );
	_d3ddevice->SetTextureStageState( 0, D3DTSS_COLORARG2,	D3DTA_DIFFUSE );
	_d3ddevice->SetTextureStageState( 0, D3DTSS_COLOROP,	D3DTOP_MODULATE );
	_d3ddevice->SetSamplerState( 0, D3DSAMP_MAGFILTER,	D3DTEXF_LINEAR);
	_d3ddevice->SetSamplerState( 0, D3DSAMP_MINFILTER,	D3DTEXF_LINEAR);

	_d3ddevice->SetRenderState (D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);

	if (SetProjection( 1.0f, 1000.0f) == FALSE)
		return FALSE;
	SetZBuffer (_zbuffer);

	if (SetAlphaTest (TRUE) == FALSE)
		return FALSE;
	// set up view matrix, temporarily to some default

	D3DXMATRIX view;
	D3DXVECTOR3 eye (0.0f, 0.0f, -1.0f), at(0.0f, 0.0f, 0.0f), up (0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&view, &eye, &at, &up);
	if (FAILED (_d3ddevice->SetTransform(D3DTS_VIEW, &view)))
	{
		return FALSE;
	}
	// end default set up

	if (FAILED (_d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0)))
		return FALSE;
	return (SUCCEEDED(_d3ddevice->BeginScene()));
My SetProjection function:

	D3DXMATRIX projection;
	float ratio = (float) _width / (float) _height;

	D3DXMatrixPerspectiveFovLH ( &projection , (float) (D3DX_PI / 4.0f), ratio, nearZ, farZ );
	return (SUCCEEDED (_d3ddevice->SetTransform(D3DTS_PROJECTION, &projection)));
my setalphatest function:

	if (test == _alphatest)  // <-- was already set that means

		return TRUE;
	if (FAILED (_d3ddevice->SetRenderState(D3DRS_ALPHATESTENABLE, test)))
	{
		return FALSE;
	}
	if (test == TRUE)
	{
		if (FAILED (_d3ddevice->SetRenderState(D3DRS_ALPHAREF, 0x08)))
		{
			return FALSE;
		}
		if (FAILED (_d3ddevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL)))
		{
			return FALSE;
		}
	}
	_alphatest = test;
	return TRUE;
the sprite is created this way:

	if (FAILED (D3DXCreateTextureFromFileEx	(display->GetDevice(), filename, 
											D3DX_DEFAULT, D3DX_DEFAULT, numMipMaps, 0,
											display->BPPtoFormat(bpp), D3DPOOL_MANAGED, 
											filter, filter, _transparent, &info, NULL, &_texture)))
		return FALSE;
	_width = width;
	_height = height;
	_totalwidth = info.Width;
	_totalheight = info.Height;
and the function for drawing the sprite goes like this:

	RECT spriteRect;
	spriteVertex * pointer;
	D3DXMATRIX translation, x_rotation, y_rotation, z_rotation, scale, world;

	spriteRect.left = (_frame % (_totalwidth / _width)) *  (_width + 1);
	spriteRect.right = spriteRect.left + _width;
	spriteRect.top = (int) (_frame / (_totalwidth / _width)) * (_height + 1);
	spriteRect.bottom = spriteRect.top + _height;

	spriteVertex vertices[4] = 
	{
		{ 0.0f, 0.0f, 0.0f, 0xffffffff, (float)spriteRect.left / (float)_totalwidth, (float)spriteRect.top / (float)_totalheight }, // x, y, z, color, u, v (texture coords)

		{ (float) _width, 0.0f, 0.0f, 0xffffffff, (float)spriteRect.right / (float)_totalwidth, (float)spriteRect.top / (float)_totalheight },
		{ (float) _width, (float) _height, 0.0f, 0xffffffff, (float)spriteRect.right / (float)_totalwidth, (float)spriteRect.bottom / (float)_totalheight },
		{ 0.0f, (float) _height, 0.0f, 0xffffffff, (float)spriteRect.left / (float)_totalwidth, (float)spriteRect.bottom / (float)_totalheight },
	};
	int i = 3;
	UINT size = sizeof(vertices);
	if (FAILED(_display->GetSpriteVertexBuffer()->Lock(0, 0, (void**)&pointer, 0)))
		return FALSE;
	memcpy(pointer, vertices, size);
	if (FAILED (_display->GetSpriteVertexBuffer()->Unlock()))
		return FALSE;
	if (_display->SetAlphaTest(TRUE) == FALSE)
		return FALSE;
	if (FAILED (_display->GetDevice()->SetTexture(0, _texture)))
		return FALSE;

// ** set world transform 

	D3DXMatrixTranslation(&translation, x, y, z);
	D3DXMatrixRotationX(&x_rotation, xAngle);
	D3DXMatrixRotationY(&y_rotation, yAngle);
	D3DXMatrixRotationZ(&z_rotation, 0.0f);
	D3DXMatrixScaling(&scale, 1.0f, 1.0f, 1.0f);

	D3DXMatrixIdentity(&world);
	D3DXMatrixMultiply(&world, &world, &scale);
	D3DXMatrixMultiply(&world, &world, &x_rotation);
	D3DXMatrixMultiply(&world, &world, &y_rotation);
	D3DXMatrixMultiply(&world, &world, &z_rotation);
	D3DXMatrixMultiply(&world, &world, &translation);

	if (FAILED (_display->GetDevice()->SetTransform(D3DTS_WORLD, &world)))
		return FALSE;
// ** done set world transform **


	if (FAILED (_display->GetDevice()->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2)))
	{
		return FALSE;
	}
	if (_display->SetAlphaTest(FALSE) == FALSE)
		return FALSE;
Finally:

	if (SetAlphaTest(FALSE) == FALSE)
		return FALSE;
	if (FAILED (_d3ddevice->EndScene()))
		return FALSE;
	return (SUCCEEDED (_d3ddevice->Present(NULL, NULL, NULL, NULL)));
So the flow of the test program creates a display object, a test sprite object w/ an arbitrary texture, then calls setup, sprite drawing, then wrapup. It seems like it should work (the sprite quad is world transformed to the origin, and the camera is positioned at -1.0f on the z axis, looking at the origin), but nothing shows, just a black screen. Can anybody help me out?
Advertisement
Have you made sure you have lights disabled, or that you''ve added some lights to the scene?
Now I put in this line:

if(FAILED(_d3ddevice->SetRenderState(D3DRS_LIGHTING, FALSE)))
return FALSE;

to disable lighting, but it still doesn''t work. =(
I got part of it to show, finally, but I still have very strange problems.
I tried scaling down the quad by a factor of 100, and I was finally able to see a part of sprite. This was when the Eye vector for the viewing matrix was at 0.0f, 0.0f, -5.0f. The strange thing is, however, if I try to change the eye vector it screws up. For example, I tried to "zoom out" by changing the eye vector to a value of 0.0f, 0.0f, -5.5f. The sprite disappears entirely. Then I tried to "zoom in" by changing it to 0.0f, 0.0f, -4.0f. It zooms in as expected, but now, no matter what I do, if i try to zoom back out to even the original z-value of -5.0f, the sprite disappears! Now, it seems like I can only see it at a value of -4.0f, even on entirely new runnings of the program. This has to be more than a DirectX problem than some strange memory problem.
Ok, serious problems.. It seems my program will be partially "corrected" after I have run another D3D program (i.e. one of DrunkenHyena''s example programs) and for a short while I can change a couple parameters on mine. After that, though, it goes back to screwing up such that I can''t "back up" (zoom back on the z-axis) until after I have run another d3d example program again , and even then it has random glitches in the display. So obviously something is seriously wrong with what I''m doing. Any suggestions?
Everything ok with your SetZBuffer function ?
if you have a z buffer, you must clear the z buffer each frame:

_d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0)
You''re in luck. I think i found out your problem. You are trying to display stuff to the screen WITHOUT RASTERIZATION. Or in other words, you already know it''s position on the screen.

Change your vertex format so it ends up looking like this:

typedef struct
{
float x, y, z, rhw; // 3-D coordinates DWORD diffuse; // diffuse color component float u, v; // Texture coordinates
} spriteVertex;

and change the declaration to this
#define SPRITEFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)

also add another number in your filling of the vertex buffer so it looks like this:

Actually it''s too much to write (or copy). Simply put in the value 1.0f in the fourth parameter. If you need help, post your modified code and i will see what else is there. Make sure you don''t scale the vertices in the world matrix. Otherwise it will be to small to show up.

Since you are a newbie, i recommend that you visit these 3 sites:

www.ultimategameprogramming.com &
(i forget the other one, just search for drunken hyena that''s the name of the site)

This other one is more advanced (does deal with begginer stuff but half of it is advanced like pixel and vertex shaders, hlsl, and cg)
www.codesampler.com

Your welcome.
if (FAILED(_d3ddevice->CreateVertexBuffer( (sizeof (spriteVertex)) * 4,

shouldn''t this be * 6? Because doesn''t each face have to have 3 vertices? Sorry if I''m wrong, but that''s what I was told
It would have been * 6 if he were using D3DPT_TRIANGLELIST to render. Instead he has D3DPT_TRIANGLEFAN that requires 4 vertices to get a quad.

This topic is closed to new replies.

Advertisement