Sign in to follow this  
DragonGeo2

What am I doing wrong!?

Recommended Posts

To clear up any confusion: I'm using DirectX 9 - The December 2005 SDK release. Non-managed. Fixed-function pipelining. Microsoft Visual Studio 2003 C++. The problem that (I think) I am having is within the class I have written to handle all my map models and units that I'm using for a top-down 3-d strategy game. The probem I am experiencing is that when I run my program, the screen renders and I am able to see the LPDIRECT3DTEXT9 text that I have set up to draw during the renderloop, and the screen updates itself normally and shows the FPS count and everything, but the actual game-world is not rendered. The problem may be in the class itself, or in some memory management problems with me and pointers and the new operator (which I'm not quite used to doing in C++, I'm a java guy, really - but you can't do good 3-d in Java so.....). I'll post code of my class and renderloop as well as other misc. code. Any and all help is appreciated (not in the form of flames, they're only half-appreciated if they're half-helpful). Declarations (note that the Direct3d objects and device objects ARE initalized later on, but not shown here):
#include<d3d9.h>
#include<d3dx9.h>
#include <mmsystem.h> // Needed for the time
#include"CCamera.h"
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
#include <fstream>
using namespace std;
#include <cstdlib>
#include <time.h>

// Our vertex stucture define.
#define D3DFVF_D3DVertex (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

HWND hwnd;                                         // Handle to the window.

// Direct3D objects.
LPDIRECT3D9 Direct3D_Object = NULL;
LPDIRECT3DDEVICE9 D3D_Device = NULL;

struct Vertex
{
   FLOAT x, y, z;
   DWORD color;
   FLOAT tu, tv;
}; // Declarations, includes, and whatnot



Here's the class' source - it's probably the problem:
class GameObject
{
	protected: 
		Vertex* Vertices;
		LPDIRECT3DVERTEXBUFFER9* VB;
		bool VBCreated;
		LPDIRECT3DTEXTURE9* Texture;
		int Health;
		int UnitType;
		unsigned int SizeX;
		unsigned int SizeY;
		float PosX;
		float PosY;
		bool AliveStatus;
	public:
		GameObject::GameObject() // Constructor 1
		{
			SetVertBuffer(NULL);
			SetTexture(NULL);
			SetHealth(0);
			UnitType = 0;
			SizeX = 0;
			SizeY = 0;
			SetPosition(0,0);
			VB = new LPDIRECT3DVERTEXBUFFER9;
			Vertices = new Vertex;
			Texture = new LPDIRECT3DTEXTURE9;
			VBCreated = false;
		}
		GameObject::GameObject(LPDIRECT3DTEXTURE9* Tex)
		{
			SetVertBuffer(NULL);
			SetTexture(Tex);
			SetHealth(0);
			UnitType = 0;
			SizeX = 0;
			SizeY = 0;
			SetPosition(0,0);
			VB = new LPDIRECT3DVERTEXBUFFER9;
			Vertices = new Vertex;
			Texture = new LPDIRECT3DTEXTURE9;
			VBCreated = false;
		}
		GameObject::GameObject(float XPos, float YPos)
		{
			SetVertBuffer(NULL);
			SetTexture(NULL);
			SetHealth(0);
			UnitType = 0;
			SizeX = 0;
			SizeY = 0;
			SetPosition(XPos, YPos);
			VB = new LPDIRECT3DVERTEXBUFFER9;
			Vertices = new Vertex;
			Texture = new LPDIRECT3DTEXTURE9;
			VBCreated = false;
		}
		GameObject::GameObject(float XPos, float YPos, LPDIRECT3DTEXTURE9* Tex)
		{
			SetVertBuffer(NULL);
			SetTexture(Tex);
			SetHealth(0);
			UnitType = 0;
			SizeX = 0;
			SizeY = 0;
			SetPosition(XPos, YPos);
			VB = new LPDIRECT3DVERTEXBUFFER9;
			Vertices = new Vertex;
			Texture = new LPDIRECT3DTEXTURE9;
			VBCreated = false;
		}
		int GameObject::GetHealth()
		{
			return Health;
		}
		bool GameObject::SetHealth(int HP)
		{
			Health = HP;
			return GetAliveStatus();
		}
		bool GameObject::GetAliveStatus()
		{
			return AliveStatus;
		}
		void GameObject::SetAliveStatus(bool Alive)
		{
			AliveStatus = Alive;
		}
		int GetUnitType()
		{
			return UnitType;
		}
		LPDIRECT3DTEXTURE9* GameObject::GetTexture()
		{
			return Texture;
		}
		LPDIRECT3DVERTEXBUFFER9* GameObject::GetVertBuffer()
		{
			return VB;
		}
		float GameObject::GetPositionX()
		{
			return PosX;
		}
		float GameObject::GetPositionY()
		{
			return PosY;
		}
		int GameObject::GetSizeX()
		{
			return SizeX;
		}
		int GameObject::GetSizeY()
		{
			return SizeY;
		}
		bool GameObject::SetPosition(float x, float y)
		{
			return ((SetPositionX(x)) && (SetPositionY(y)));
		}
		bool GameObject::SetPositionX(float x)
		{
			PosX = x;
			return GetAliveStatus();
		}
		bool GameObject::SetPositionY(float y)
		{
			PosY = y;
			return GetAliveStatus();
		}
		bool GameObject::SetSizeX(int x)
		{
			SizeX = x;
			return GetAliveStatus();
		}
		bool GameObject::SetSizeY(int y)
		{
			SizeY = y;
			return GetAliveStatus();
		}
		bool GameObject::SetSize(int x, int y)
		{
			return (SetSizeX(x) && SetSizeY(y));
		}
		bool GameObject::SetTexture(LPDIRECT3DTEXTURE9* Tex)
		{
			Texture = Tex;
			return GetAliveStatus();
		}
		bool GameObject::SetVertBuffer(LPDIRECT3DVERTEXBUFFER9* VertBuffer)
		{
			VB = VertBuffer;
			return GetAliveStatus();
		}
		void GameObject::Destroy()
		{
			SetAliveStatus(false);
			SetVertBuffer(NULL);
			SetTexture(NULL);
			SetHealth(0);
			UnitType = 0;
			SizeX = 0;
			SizeY = 0;
			SetPosition(0,0);
		}
		void GameObject::Create(float PositionX, float PositionY, int Health)
		{
			SetPosition(PositionX, PositionY);
			if (Health > 0)
			{
				SetHealth(Health);	
				SetAliveStatus(true);
			}
			else
			{
				SetHealth(Health);
				SetAliveStatus(false);
			}
		}
		bool GameObject::DrawMe(LPDIRECT3DDEVICE9 Dev)
		{
			if (VBCreated == false)
			{
				if(MakeVB(Dev))
				{
					VBCreated = true;
				}
				else
				{
					MessageBox(hwnd, "Could not create vertex buffer!", NULL, NULL);
				}
			}
			else
			{
			}
			if (VBCreated == true)
			{
				if (GetTexture() == NULL)
				{
					Dev->SetTexture(0,NULL);
					//MessageBox(hwnd, "Texture not found", NULL, NULL);
				}
				else
				{
					Dev->SetTexture(0,*GetTexture());
					//MessageBox(hwnd, "Texture found", NULL, NULL);
				}
				Dev->SetStreamSource(0, *GetVertBuffer(), 0, sizeof(Vertex));
				Dev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
				return true;
			}
			else
			{
				return false;
			}
		}

		bool GameObject::MakeVB(LPDIRECT3DDEVICE9 Dev)
		{
   Vertex Verts[4];
   
   // Topright Vert
   Verts[0].x = float(GetPositionX() + (0.5 * GetSizeX()));
   Verts[0].z = float(GetPositionY() - (0.5 * GetSizeY()));
   Verts[0].tu = 0.0f;
   Verts[0].tv = 1.0f;
   Verts[0].y = 0.0f;
   Verts[0].color = 0xffffffff;

   // Topleft Vert
   Verts[1].x = float(GetPositionX() - (0.5 * GetSizeX()));
   Verts[1].z = float(GetPositionY() - (0.5 * GetSizeY()));
   Verts[1].tu = 0.0f;
   Verts[1].tv = 0.0f; 
   Verts[1].y = 0.0f;
   Verts[1].color = 0xffffffff;

   // Bottomright Vert
   Verts[2].x = float(GetPositionX() + (0.5 * GetSizeX()));
   Verts[2].z = float(GetPositionY() + (0.5 * GetSizeY()));
   Verts[2].tu = 1.0f;
   Verts[2].tv = 1.0f;
   Verts[2].y = 0.0f;
   Verts[2].color = 0xffffffff;

   // Bottomleft Vert
   Verts[3].x = float(GetPositionX() - (0.5 * GetSizeX()));
   Verts[3].z = float(GetPositionY() + (0.5 * GetSizeY()));
   Verts[3].tu = 1.0f;
   Verts[3].tv = 0.0f;
   Verts[3].y = 0.0f;
   Verts[3].color = 0xffffffff;

	if(FAILED(Dev->CreateVertexBuffer(sizeof(Verts),0, D3DFVF_D3DVertex,D3DPOOL_DEFAULT, GetVertBuffer(), NULL)))
         return false;

	if (FAILED((*GetVertBuffer())->Lock(0,sizeof(Verts), (void**)Vertices, 0)))
	{
		return false;
	}

	memcpy(Vertices, Verts, sizeof(Verts));

	if (FAILED((*GetVertBuffer())->Unlock()))
		return false;
	return true;
	}
};



Here's the initialization of GameObject class' objects:
GameObject* GOArray[10];

   for (int x = 0; x < 10; x++)
   {
		GOArray[x] = new GameObject();
		LPDIRECT3DTEXTURE9* TempTex = new LPDIRECT3DTEXTURE9;
		if (FAILED(D3DXCreateTextureFromFile(D3D_Device, "C:\\Documents and Settings\\DragonGeo2\\My Documents\\Visual Studio Projects\\NSRM\\Debug\\Gifcloud2.tga", TempTex)))
			MessageBox(hwnd, "Could not load Texture!", NULL, NULL);
		GOArray[x]->SetTexture(TempTex);
		GOArray->Create(float(x*5), float(5), 1);
		Number_GOs += 1; // global variable
   }



Here is my renderloop (I cut off the boring ending part where the text is drawn and the scene is ended and presented):
   // Tell Direct 3D we are now going to start drawing.
   D3D_Device->BeginScene();

      // Set the view matrix (camera position).
      SetCamera();

	   // This will bind the vertex data in the buffer to the Direct3D device.
	  D3D_Device->SetFVF(D3DFVF_D3DVertex);
	  
	for (int x = 0; x < Number_GOs; x++)
	{
		GOArray[x]->DrawMe(D3D_Device);
	}



Edit: I even added source code complete with a compiled EXE for people to download and see that it doesn't work. But WHY!? [url]http://rapidshare.de/files/22410308/NSRM.rar.html[/url] [Edited by - DragonGeo2 on June 7, 2006 6:52:09 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I checked a DirectX example, and as far as I know, you are not drawing the polygons inside-out (as was my first presumption about your error) such that you can't see them when the camera is not on the other side of them (plus you don't have polygon backface clipping enabled). So that can't be the problem. Anyone else have any ideas?

Share this post


Link to post
Share on other sites
Your 'provide full source' initiative is really nice, becuase it simplifies debugging.

However, when I compile and run I get an "Could not load texture" error.

Would it be possible to provide a completely full version?

Share this post


Link to post
Share on other sites
Quote:
Original post by Enselic
Your 'provide full source' initiative is really nice, becuase it simplifies debugging.

However, when I compile and run I get an "Could not load texture" error.

Would it be possible to provide a completely full version?


Well in order to fix that, you need to go to the section of code (I think it was in the class' MakeVB function) that says:
Quote:
MessageBox(hwnd, "Could not load texture", NULL, NULL);
and right before it, there should be an "IF ( FAILED ( ) )" test to see if D3DXCreateTextureFromFile() worked correctly. You then need to modify The CreateTextureFromFile parameters to contain the path to a texture that you actually have available on your machine - try something like:
Quote:
C:\\Windows\\Prairie Wind.bmp
. That should work.

Share this post


Link to post
Share on other sites
Damnit, I give up, I've tried to debug this one but I must admit failure.

I managed to get a texture to load, but despite poking around with the camera, the vertex formats etc I am unable to get it to show anyting. Truth to be told it have been a while since I used C++/Direct3D, so the solution might still be trivial.

While debugging however, I noticed some flaws in the code which I thought I'd share anyway.
  • When you call D3DXMatrixPerspectiveFovLH() you use degrees instead of radians for the field of view parameters (you should pass 3.14f / 2 instead of 45.0f). You also pass a faulty aspect ratio since 1280/1024 is calculated with integer division, so you get the wrong ratio. Pass 1280.0f/1024 instead for instance

  • When you create the game object (before the main loop) you use new-allocations, but as far as I can tell you don't delete them, i.e. you have a memory leak there. I also find
        LPDIRECT3DTEXTURE9* TempTex = new LPDIRECT3DTEXTURE9;
    a bit strange? I mean why do you dynamically allocate the pointer instead of just creating it the "normal" way
        LPDIRECT3DTEXTURE9 TempTex;
    and then pass its adress (&TempTex) to the D3DXCreateTextureFromFile function?

  • In your GameObject::Create() method you can replace
        if (Health > 0)
    {
    SetHealth(Health);
    SetAliveStatus(true);
    }
    else
    {
    SetHealth(Health);
    SetAliveStatus(false);
    }
    with
        SetHealth(Health);	
    SetAliveStatus(Health > 0);

  • One quite fatal bug is that you forget to set the size of you game objects so that the vertex buffer you try to use all have its vertices in the same point (since GetSizeY() and GetSizeX() returns 0)

  • It is also somewhat confusing that use use the game objects Y cordinate and assign that to the vertices z components (as in Verts[0].z = float(GetPositionY() - (0.5 * GetSizeY()));) though that is not a serious mistake.

  • You probably want #define D3DFVF_D3DVertex (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
    to be #define D3DFVF_D3DVertex (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX0) since the index is zero based.
    I'm stupid

That's some of the issues I noted, but I was unable to put my finger on why the rendering fails. [sad]

[Edited by - Enselic on June 14, 2006 1:36:56 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Enselic
Damnit, I give up, I've tried to debug this one but I must admit failure.

I managed to get a texture to load, but despite poking around with the camera, the vertex formats etc I am unable to get it to show anyting. Truth to be told it have been a while since I used C++/Direct3D, so the solution might still be trivial.

While debugging however, I noticed some flaws in the code which I thought I'd share anyway.
.
.
.
That's some of the issues I noted, but I was unable to put my finger on why the rendering fails. [sad]


You, my friend, are quite the thourough debugger - thanks for finding all of the shortcomings with my program and for all of your help. Here are some bugfixes I've implemented to solve the problem of the non-rendering program (with no avail thus-far):

Quote:
When you call D3DXMatrixPerspectiveFovLH() you use degrees instead of radians for the field of view parameters (you should pass 3.14f / 2 instead of 45.0f). You also pass a faulty aspect ratio since 1280/1024 is calculated with integer division, so you get the wrong ratio. Pass 1280.0f/1024 instead for instance.
Thanks! I always thought that my aspect ratio looked a bit too "square" for my monitor, I guess that's what happens when your aspect ratio is 1! Fixed.

Quote:
When you create the game object (before the main loop) you use new-allocations, but as far as I can tell you don't delete them, i.e. you have a memory leak there.
Fixed! I now appended a code section in the Cleanup function to delete all of the GameObject objects.

Quote:
I also find

LPDIRECT3DTEXTURE9* TempTex = new LPDIRECT3DTEXTURE9;

a bit strange? I mean why do you dynamically allocate the pointer instead of just creating it the "normal" way

LPDIRECT3DTEXTURE9 TempTex;

and then pass its adress (&TempTex) to the D3DXCreateTextureFromFile function?
I'm not really sure why I did that - must have been up too late coding :)

Quote:
In your GameObject::Create() method you can replace

if (Health > 0)

{

SetHealth(Health);

SetAliveStatus(true);

}

else

{

SetHealth(Health);

SetAliveStatus(false);

}

with

SetHealth(Health);

SetAliveStatus(Health > 0);
Fixed for efficiency!

Quote:
One quite fatal bug is that you forget to set the size of you game objects so that the vertex buffer you try to use all have its vertices in the same point (since GetSizeY() and GetSizeX() returns 0)
I would have thought that this was the root of the rendering problem, but I see that it isn't after I fixed this problem by adding a size parameter to the Create() function.

Quote:
It is also somewhat confusing that use use the game objects Y cordinate and assign that to the vertices z components (as in Verts[0].z = float(GetPositionY() - (0.5 * GetSizeY()));) though that is not a serious mistake.
Well I kind of did this one on purpose as the camera uses a Y-up coordinate system and is always overhead of the objects on screen (it's a strategy game), so I figured that most 3-d strategy games are derivations of their 2-d counterparts, and simplified it to X and Y use only (then converting to Z for rendering purposes).

Quote:
You probably want #define D3DFVF_D3DVertex (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
to be #define D3DFVF_D3DVertex (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX0) since the index is zero based.
Thanks - much appreciated.

Quote:
That's some of the issues I noted, but I was unable to put my finger on why the rendering fails.
Poop...

Anyone else want to have a crack at it?

Share this post


Link to post
Share on other sites
1) Don't use absolute directories!!! Use relative. Just create a folder called images in the root directory of which your solution is in. Then load the texture via "images\texturename.png"

2) My computer doesn't support the MAG filter D3D_Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); Check for that support.

3) You don't need to set z-enable to true, that is its default value.

4) You've got a D3D memory leak. Your loading a texture and not unloading it, a debug font abd not undloading it. The vertex buffer your also not unloading.

5) GetSize() is still returning 0, it seems as though you didn't upload your fixes so im still working on your old source code.

6) optimization, make sure you create your vertex buffer with the write-only flag.

7) Don't set the fill mode render state every frame. Set it once and only once when it changes.

I'll look at it more tommorow if you update your code.

- dave

Share this post


Link to post
Share on other sites
Quote:
Original post by ph33r
1) Don't use absolute directories!!! Use relative. Just create a folder called images in the root directory of which your solution is in. Then load the texture via "images\texturename.png"

2) My computer doesn't support the MAG filter D3D_Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); Check for that support.

3) You don't need to set z-enable to true, that is its default value.

4) You've got a D3D memory leak. Your loading a texture and not unloading it, a debug font abd not undloading it. The vertex buffer your also not unloading.

5) GetSize() is still returning 0, it seems as though you didn't upload your fixes so im still working on your old source code.

6) optimization, make sure you create your vertex buffer with the write-only flag.

7) Don't set the fill mode render state every frame. Set it once and only once when it changes.

I'll look at it more tommorow if you update your code.

- dave

Fixed all of your bugs, Dave, and guess what?

It's STILL not drawing anything on screen! Can ANYBODY FIGURE THIS OUT!?

Edit: I reupdated the source, see below - I also reorganized it such that different code sections are in different locations (probably shouldn't have ended those files with .h because they're really .cpp files):
http://rapidshare.de/files/22837249/NSRM.zip.html

Share this post


Link to post
Share on other sites
Testing for anisotropic is broken. Use "&", not "|=". Fallback to linear is better than POINT.

Projection matrix "45.0f" should be "D3DX_PI/4". ie: Radians, not degrees.

GameObjects are only created when D3D init fails.

You aren't copying the texture pointer, but a pointer to where the init code had the texture pointer on the stack. By the time you attempt to SetTexture, that part of the stack is long gone. Change all "LPDIRECT3DTEXTURE9 *"s to plain "LPDIRECT3DTEXTURE9". Note LP means it's a pointer already.

Same with the vertex buffer, except for CreateVertexBuffer, which actually wants a pointer to where your LPDIRECT3DVERTEXBUFFER9 is. Change that to just "&VB".

Don't new the VBs or Textures. D3D makes the new objects for you. Don't new the Vertices pointer. D3D fills in a valid pointer when you lock().

Don't delete any of these pointers either. When you're done with the texture or vertex buffer, call the Release function on them. The vertices pointer is invalid once you've called Unlock().

Lock should use (void **)&Vertices

It will now attempt to render, at which point D3D now says:
Stream 0 stride and vertex size, computed from the current vertex declaration or FVF, are different, which might not work with pre-DX8 drivers

Your FVF says TEX0, which means no UVs. You want TEX1. Note, this is a count, not a mask. For example, don't use TEX1|TEX2 to mean you want 2 texture coords, simply say TEX2. In your case, you 1 set of UVs, so say TEX1.

Your game objects are destroyed after D3D, but contain D3D objects (textures and VBs). This makes D3D sad. Move their destruction before killing D3D.

Your tests for wireframe and point mode aren't right. (= should be ==).

With all this changed, it's still not rendering...

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