Simple vertex buffer problem :S

Started by
12 comments, last by cybbe 18 years, 8 months ago
Hi there, I'm very new to Direct3D and I'm about to tear my head apart. I've taken a little sample Direct3D app and modified it a bit to my liking. So I have a couple of X models loaded and a camera that I can move with DirectInput. Now I was about to do a gui (HUD) and I'm trying to do a simple vertexbuffer with 4 vertices in screen space and then draw a trianglestrip of two primitives. I want to do this in a new class called CGui. Here's the code: gui.h

#ifndef GUI_H
#define GUI_H

#include <d3d9.h>
#include <d3dx9.h>

#define D3DFVF_GUIFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)

struct GuiVertex
{
	float x, y, z, rhw;
	DWORD color;
	float tu, tv;
};

class CGui
{
	LPDIRECT3DDEVICE9 d3dDevice;
	LPDIRECT3DVERTEXBUFFER9 vb;
	LPDIRECT3DTEXTURE9 texture;

	GuiVertex *verts;
public:
	CGui();
	~CGui();

	HRESULT Init(LPDIRECT3DDEVICE9 device);
	HRESULT DeInit();

	HRESULT Render();
};

#endif

gui.cpp

#include <d3d9.h>
#include <d3dx9.h>
#include "constants.h"
#include "gui.h"

CGui::CGui()
{
	vb = NULL;
	verts = NULL;
	texture = NULL;
}

CGui::~CGui()
{
	SafeRelease(vb);
	SafeRelease(texture);
	SafeDeleteArray(verts);
}

HRESULT CGui::Init(LPDIRECT3DDEVICE9 device)
{
	void *tempVerts = NULL;
	d3dDevice = device; // Assign our CGui::d3dDevice so we can use it in other CGui functions.

	verts = new GuiVertex[4];
	// CW Order
	verts[0].x = 100.0f; verts[0].y = 100.0f; verts[0].z = 0.0f; verts[0].rhw = 1.0f; verts[0].color = D3DCOLOR_ARGB(255, 255, 0, 0); verts[0].tu = 0.0f; verts[0].tv = 0.0f;
	verts[1].x = 400.0f; verts[1].y = 100.0f; verts[1].z = 0.0f; verts[1].rhw = 1.0f; verts[1].color = D3DCOLOR_ARGB(255, 0, 255, 0); verts[1].tu = 1.0f; verts[1].tv = 0.0f;
	verts[2].x = 100.0f; verts[2].y = 400.0f; verts[2].z = 0.0f; verts[2].rhw = 1.0f; verts[2].color = D3DCOLOR_ARGB(255, 0, 0, 255); verts[2].tu = 0.0f; verts[2].tv = 1.0f;
	verts[3].x = 400.0f; verts[3].y = 400.0f; verts[3].z = 0.0f; verts[3].rhw = 1.0f; verts[3].color = D3DCOLOR_ARGB(255, 255, 255, 255); verts[3].tu = 1.0f; verts[3].tv = 1.0f;

	D3DXCreateTextureFromFile(d3dDevice, "data/textures/gui.dds", &texture);
	d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

	// D3DPOOL_DEFAULT makes the app hang? O.o
	d3dDevice->CreateVertexBuffer(4 * sizeof(GuiVertex), D3DUSAGE_WRITEONLY, D3DFVF_GUIFVF, D3DPOOL_MANAGED, &vb, NULL);
	vb->Lock(0, sizeof(verts), (void**)&tempVerts, 0);
	memcpy(tempVerts, verts, sizeof(verts));
	vb->Unlock();

	return S_OK;
}

HRESULT CGui::DeInit()
{
	SafeRelease(vb);
	SafeRelease(texture);
	SafeDeleteArray(verts);

	return S_OK;
}

HRESULT CGui::Render()
{
	d3dDevice->SetTexture(0, texture);
	d3dDevice->SetStreamSource(0, vb, 0, sizeof(GuiVertex));
	d3dDevice->SetFVF(D3DFVF_GUIFVF);

	// Just draw the first triangle (should be a TRIANGLESTRIP but for bug searching reasons...)
	d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

	return S_OK;
}

So as you see I send the d3dDevice pointer to CGui::init so that CGui:s other functions can use it (as render for example). Then I create my vertices, load a texture, create a vertexbuffer, lock the vertex buffer and copy the vertice data to the vertex buffer and finally unlock it. When I render it I render as a single triangle because I'm not sure that the trianglestrip would work correctly. I've also tried to cull both CCW and CW but that is not the problem.
Advertisement
Sorry, what is the problem, u have only asked it to render one primitive, i gather that is what it is doing right?

ace
Looks okay at first sight, but, what is the problem? What does and what doesn't your application currently do?

Illco
Heh, "oops" :)

The code does not render a thing. No matter how I try to turn it (CW or CCW), I have lighting turned off and I have translation to 0,0,0 - rotation to 0,0,0 and scaling to 1,1,1.

I don't really know what other code snippets I could show you but I have x models loaded and I have a font class showing off some fonts (2d and 3d).

I have also put break points in both CGui::Init and CGui::Render and the program _does_ go into these functions, but it doesn't render anything. I've also tried a d3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); to change the culling sides in the CGui::Render function. That way I've "checked" that the d3dDevice that is in the CGui::Render function actually is the right device.
not sure, but a couple of things i do thats different is that i explicitly declare the size of the data to be memcpy'd, like 4* sizeof( MYVERTEX ) rather than the size of the array. I would go through and just get it to render one triangle without loading any more than that into the vertex buffer etc.

ace
Well, I'm pretty sure this is it:
	d3dDevice->CreateVertexBuffer(4 * sizeof(GuiVertex), D3DUSAGE_WRITEONLY, D3DFVF_GUIFVF, D3DPOOL_MANAGED, &vb, NULL);	vb->Lock(0, sizeof(verts), (void**)&tempVerts, 0);	memcpy(tempVerts, verts, sizeof(verts));


You're locking "sizeof(verts)" but verts is a pointer (4 bytes). So, in reality, you're only locking 4 bytes. Try using "4 * sizeof(GuiVertex)" for your lock and memcpy calls.

Good luck :).

EDIT: ahhh, got beat to it :(.
Sirob Yes.» - status: Work-O-Rama.
Thanks for that one (it probably was wrong) but it didn't help :/ Still no triangle. But just to get one thing straight. This should do a screen space triangle right? I don't have to do anything more between drawing a 3d mesh (x model) and drawing this triangle. I'm an old opengl fan and there you switch to orthographic projection before drawing gui / HUD things.

As I've understood it there is no need for this in D3D, it just goes screen space if I define the FVF with x, y, z, rhw? And rhw should be 1.0f and z should be 0.0f? If so all that stuff should be correct... And x and y coordinates depend on the resolution, and it's not something I need to define myself? And since I use 1024 x 768 as window size my x and y coordinates that is between 100 and 400 should be within the window and big enough not to miss.
The vertices are right for it to be a screenspace triangle.

I honestly cant see whats wrong. The winding order is wrong, but that depends on whether you have culling on.

ace
Hi,

I haven't used the fixed function pipeline in ages but I would guess that your your X and Y coords should be in device coords which range from -1 to 1 (see "Viewports and Clipping" in the DirectX SDK Docs).

You can use an orthographic projection matrix if you want to deal with coords in another range (e.g. 0-1024 , 0-768). See the D3DX matrix methods in the SDK docs.

Hope this helps,

Mike.
I take it the world and view transforms are correct, as you derived this from another sample. Otherwise double check the view in so far that it looks at your triangle. Switch culling completely off and make the background non-black.

Then switch on the DX debug mode (via control panel) and watch closely what it says. Also check any return values. You will probably get new leads as to what the problem is. If not, you know the triangle gets rendered but not in your viewport facing you.

Illco

This topic is closed to new replies.

Advertisement