Sign in to follow this  
zyrolasting

BIG Issues. Game Troubles Piling. Seeking experienced help.

Recommended Posts

Oh god, I have problems. This is a little... Catastrophic. Scratch that, I am royally screwed and I'm too overwhelmed to think about it any more at the moment. There are three main issues and I need a good deal of help. I would REALLY appreciate help, but be warned, you'd really be reading a lot. If anything, just answer what you can. To help you out, I added comments in the code below like /***1***/ to mark key areas to pay attention to. This assuming Ctrl+F can check in these source boxes... Nutshell --- 1. Duplicating allocations eating system memory. Unsure how to structure remedy. 2. Mesh texture flickering, Mesh Share distorting slightly. 3. Attempted AABB/OBB setup has Game Objects never leave their initial positions. Detail --- I have constructed a large class to represent Objects in game. HEADER
/*********************/
//GAMEOBJECT Class
//Holds all generic info
//for a game object.
/*********************/
class GameObject
{
public:
	/*Object Types. When rendering these objects or accessing them, they are processed in the order these are enumerated.
	For example, once a FOR loop updates an array of these objects, SYSTEM objects are updated first.*/
	enum ObjectType
	{
		SYSTEM,
		SCENIC,
		LIFELESS,
		CHARACTER,
		NONPLAYABLE_CHARACTER
	};

	float x, y, z;

	LPTSTR name, modelname, id;
	D3DXVECTOR3 LastPos;
	ObjectType my_type;
	MODEL mesh;

	GameObject() {LastPos = D3DXVECTOR3(0.0f, 0.0f, 0.0f); active = false;}
	
/*Function: Create. General constructor. Unlike organized constructors, this must be called due to instances of this class allocated in array. Updating soon.*/
	void Create(ObjectType type, D3DXVECTOR3 pos, LPTSTR _modelname, LPTSTR _name, LPTSTR _id);
	void setActive (bool _active) {active = _active;}
	bool getActive() {return active;}
	void SetLastPosition(); /***4***/
	bool LoadStats(LPTSTR _statfile);

private:
	bool active;
};






For the Record, this MODEL class is closely related.
/**************************/
//Model Class.
//Holds info for a mesh. Requires Direct3D headers.
/**************************/

class MODEL
{
public:
    LPD3DXMESH Mesh;
    D3DMATERIAL9* Material;
    LPDIRECT3DTEXTURE9* Texture;
    DWORD numMaterials;
    D3DXVECTOR3 minBounds, maxBounds, WorldBounds[8], ObjectBounds[8];
    bool ready;

    ~MODEL()
    {
        delete [] Material;
        delete [] Texture;
    }
	void AABBtoWorldArray(D3DXMATRIX *T) /***2***/
	{
		ObjectBounds[0] = D3DXVECTOR3(minBounds.x, minBounds.y, minBounds.z);
		ObjectBounds[1] = D3DXVECTOR3(maxBounds.x, minBounds.y, minBounds.z);
		ObjectBounds[2] = D3DXVECTOR3(minBounds.x, maxBounds.y, minBounds.z);
		ObjectBounds[3] = D3DXVECTOR3(minBounds.x, minBounds.y, minBounds.z);
		ObjectBounds[4] = D3DXVECTOR3(minBounds.x, minBounds.y, maxBounds.z);
		ObjectBounds[5] = D3DXVECTOR3(maxBounds.x, minBounds.y, maxBounds.z);
		ObjectBounds[6] = D3DXVECTOR3(minBounds.x, maxBounds.y, maxBounds.z);
		ObjectBounds[7] = D3DXVECTOR3(maxBounds.x, maxBounds.y, maxBounds.z);

		D3DXMATRIX matWorld;
		for (int i = 0; i < 8; i++)
			D3DXVec3TransformCoord(&WorldBounds[i], &ObjectBounds[i], T);

	}
	void AABBfromOBB() /***3***/
	{
		minBounds.x = maxBounds.x = ObjectBounds[0].x;
		minBounds.y = maxBounds.y = ObjectBounds[0].y;
		minBounds.z = maxBounds.z = ObjectBounds[0].z;

		for (int i = 1; i < 8; i++)
		{
			if (ObjectBounds[i].x < minBounds.x) minBounds.x = ObjectBounds[i].x;
			if (ObjectBounds[i].x > maxBounds.x) maxBounds.x = ObjectBounds[i].x;
			if (ObjectBounds[i].y < minBounds.y) minBounds.y = ObjectBounds[i].y;
			if (ObjectBounds[i].y > maxBounds.y) maxBounds.y = ObjectBounds[i].y;
			if (ObjectBounds[i].z < minBounds.z) minBounds.z = ObjectBounds[i].z;
	        if (ObjectBounds[i].z > maxBounds.z) maxBounds.z = ObjectBounds[i].z;
		}
	}
};





DEFINITIONS
#include "global.h" //Do not be concerned with this.

//Build Object. If Sequenced (sequence != NULL) then mesh data will reference from first created element judged by ConstructMultipleObjects().
//This applies to this funtion being called for identical objects.
void GameObject::Create(ObjectType type, D3DXVECTOR3 pos, LPTSTR _modelname, LPTSTR _name, LPTSTR _id)
{
	my_type = type;
	x = pos.x; y = pos.y; z = pos.z; //Init position.

	name = _name; //Name of object
	modelname = _modelname; //This will store the file name to .X file used for this object.
	id = _id; //Holds a unique id for the object, in case more than one instance shares data.
	SetObjectModel(this); /***1***/
	SetLastPosition();
	active = true; //The game will perform tasks on this object if it's active.
}
bool GameObject::LoadStats(LPTSTR _statfile)
{
	//If the object is a character of any kind, include the location of the .zst file that contains stat info.
	//Set _statfile parameter to NULL if there is none.
	if (my_type == CHARACTER || my_type == NONPLAYABLE_CHARACTER && _statfile != NULL)
	{
		ifstream statfile(_statfile, ifstream::in);
		while (statfile.good())
		{
						statfile >> health[0] >> energy[0] >> speed >> power >> defense >> vitality >> tolerance;
		}
		statfile.close();
	}
}

void GameObject::SetLastPosition() /***4***/
{
	LastPos.x = x;
	LastPos.y = y;
	LastPos.z = z;
}
GameObject::ObjectType getType(GameObject* obj)
{
	return obj->my_type;
}






MODEL DEFINITIONS AND RELATED
[source lang="cpp]
bool LoadModel(MODEL* Model, LPCTSTR File)
{
    LPD3DXBUFFER bufMaterial;
    if (FAILED(D3DXLoadMeshFromX(File, D3DXMESH_SYSTEMMEM, d3ddev, NULL, &bufMaterial, NULL,
                      &Model->numMaterials, &Model->Mesh))) return false;

    D3DXMATERIAL* tempMaterials = (D3DXMATERIAL*)bufMaterial->GetBufferPointer();
    Model->Material = new D3DMATERIAL9[Model->numMaterials];

    Model->Texture = new LPDIRECT3DTEXTURE9[Model->numMaterials];

    for(DWORD index = 0; index < Model->numMaterials; index++)
    {
        Model->Material[index] = tempMaterials[index].MatD3D;
        Model->Material[index].Ambient = Model->Material[index].Diffuse;

        USES_CONVERSION;
        if(FAILED(D3DXCreateTextureFromFile(d3ddev,
                                            CA2W(tempMaterials[index].pTextureFilename),
                                            &Model->Texture[index])))

            Model->Texture[index] = NULL;
    }

    return true;
}

void SetObjectModel(GameObject* obj) /***1***/
{
	if (obj->modelname != NULL)
	{
		LoadModel(&(obj->mesh),obj->modelname);
		obj->mesh.ready = true;
	}
	if (GetModelBoundBox(&(obj->mesh)))
		obj->setActive(false); //Bounding Box in error state. Object forced to remain dormant.
}
bool GetModelBoundBox(MODEL* mesh)
{
	if (mesh->ready)
	{
		BYTE* pVertices = NULL;
		if (FAILED(mesh->Mesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pVertices)))
			return false;

		D3DXComputeBoundingBox((D3DXVECTOR3*)pVertices, mesh->Mesh->GetNumVertices(),
			D3DXGetFVFVertexSize(mesh->Mesh->GetFVF()), &(mesh->minBounds), &(mesh->maxBounds));

		mesh->Mesh->UnlockVertexBuffer();
		return true;
	}
	return false;
}






These objects are allocated at the beginning of the game, before entering the message loop. I allocate 100 objects in this example. Alright, now please observe these two functions.
void ConstructMultipleObjects(GameObject obj[], GameObject::ObjectType type, D3DXVECTOR3 pos, D3DXVECTOR3 pos_inc, LPTSTR _modelname, LPTSTR _name, LPTSTR _id, int num)
{
	int start = ObjectsInPlace;
	for (int i = 0; i < num; i++)
	{
		if (i) /*ISSUE 1! What difference should be in this condition? See below, outside source box*/
		{
			pos.x += pos_inc.x;
			pos.y += pos_inc.y;
			pos.y += pos_inc.z;
			obj[start+i].Create(type,pos,_modelname,_name,_id);
		}
		else
			obj[start+i].Create(type,pos,_modelname,_name,_id);
		ObjectsInPlace++;
	}
}

void ConstructOneObject(GameObject obj[], GameObject::ObjectType type, D3DXVECTOR3 pos, LPTSTR _modelname, LPTSTR _name, LPTSTR _id)
{
	obj[ObjectsInPlace].Create(type,pos,_modelname,_name,_id);
	ObjectsInPlace++;
}






Bit of background. The context of the two functions are not that different. A global variable called ObjectsInPlace defines the next available spot to create an object. Time to lead into issue 1. Looking at ConstructMultipleObjects, I am doing just that but am instructing each object to load a copy of the mesh. This is a problem. This is done by yet another (but thankfully small) function called SetObjectModel(). (LABEL 1) My issue is knowing how exactly in ConstructMultipleObjects() that I have every instance other than the first reference the first mesh. (Copy constructors came to mind, but I'm still knee deep in structure issues. Read on.) Issue 2 shouldn't be too hard to describe, but I have no idea how to solve it. Observe this image. ConstructMultipleObjects has a param called pos_inc which is a vector that defines a distance and direction to increment before placing the next instance. This will clear up some of the stuff below. Photobucket The Original mesh... Top left. Made in Maya. In the viewer and in game the textures are flickering out of control. It looked like I was growing a garden of black maggots, and hell, may as well have been. Also, on close observation of the "In Viewer" pic (Top Right), it looks as if the center has been bent down a wee bit. You can also kinda see it in the bottom right pic. In Game, it's horrific. I moved my view to the edge, and it looked as if the bottoms were waving like an ocean. This is meant to be flat on the bottom. Granted, I got lazy with UVs. But I at least attempted to map them downward on the circular shapes; The sides and bottom had the most reason to flicker. But the top also suffered. I have no labels for this issue. Third and final issue. AABB to OBB. LABEL 2 marks the function AABBtoWorldArray this should be the function to transform vectors to where the AABB goes before (or after?) the OBB is set. (LABEL 3) Prepare for another function... This is called in my rendered scenes.
void DrawModel(MODEL* Model, float x, float y, float z)
{
    D3DXMATRIX matTranslate;

    D3DXMatrixTranslation(&matTranslate, x, y, z);
    d3ddev->SetTransform(D3DTS_WORLD, &matTranslate);
	Model->AABBtoWorldArray(&matTranslate);
	Model->AABBfromOBB();

    for(DWORD index = 0; index < Model->numMaterials; index++)
    {
        d3ddev->SetMaterial(&Model->Material[index]);
        if(Model->Texture[index] != NULL)
            d3ddev->SetTexture(0, Model->Texture[index]);

        Model->Mesh->DrawSubset(index);
    }
    return;
}






It's called in my Render functions in a for loop stepping through the array of objects. Issue 3 is that I don't know how exactly the translations are being calculated. The method calls for a matrix, but DrawModel uses floar params for it's positioning. As you can see, I tried using that translation matrix in the function body. However, when the game starts, if I use say ConstructMultipleObjects to place things in a line, they all snap together. I know the related data. GameObject has a Vector called LastPos (LABEL 4, also on definition), which holds it's position in the last frame. It was intended to be used when there was a collision. I suspect when the game starts it initialized as 0.0 on each, so I called to update LastPos in the object creating functions. Didn't help. I swear to god, I'm about to explode. Please tell me where I royally messed up like you would to a guy that makes this kind of mess. Ugh. If you read this far, thanks for doing that, if anything!

Share this post


Link to post
Share on other sites
1. Make one array of meshes data, which will hold only one instance of every object, and then render calling the id of the mesh, pointer or any similar approach.

GameObject *g_ObjectGlobal[MAX_OBJ];

and SceneObject

class SceneObject
{
...
int m_iId; // holds offset on g_ObjectGlobal array
// so you can call g_ObjectGlobal[ m_iId ];
...
or
GameObject **m_ppToGameObject; // which will be pointer to
// one of g_ObjectGlobal objects
};

2. Possible you have problems with filtering or mip mapping check this

3. Hm, D3DXMatrixTranslation is before for loop, maybe you need to translate every subset?

Share this post


Link to post
Share on other sites
Also sooner or later, you will have performance problems. Drawing each mesh separately will took too much time, instead you need to rethink the approach, and call render functions only few times every frame. You can create one or few big vertex buffers which will be filled with all meshes that uses same texture, then render them in one call. Also you can create one BIG texture which will hold several textures in one place and then playing with UV coordinates you can put more data in VB, much more minimizing render calls.

So once you create vertex buffer with all data, then render it every frame

If you need to move some data that is stored in VB lock the buffer, make changes,
unlock and continue rendering.

Just some thoughts...

Share this post


Link to post
Share on other sites
Alright, thanks for replying. I do have a few questions.

1.
Quote:

GameObject *g_ObjectGlobal[MAX_OBJ];

and SceneObject

class SceneObject
{
...
int m_iId; // holds offset on g_ObjectGlobal array
// so you can call g_ObjectGlobal[ m_iId ];
...
or
GameObject **m_ppToGameObject; // which will be pointer to
// one of g_ObjectGlobal objects
};


EDIT: Wait. I just saw that "or" you put there. That being the case, your method doesn't look too different than mine. I'm still confused here, so can you clarify? Here's what I've been calling.

GameObject Objects[MAX_OBJ];

void Render(GameObject obj[])
{
StartRender();
for (int i = 0; i < MAX_OBJ; i++)
{
if (obj[i].getActive()) DrawModel(&(obj[i].mesh),obj[i].x,obj[i].y,obj[i].z);
}
EndRender();
return;
}



All meshes on inactive objects should be ignored from render, but I still am not sure what your method does to prevent duplicate meshes being loaded in.

OLD: So I would be holding an array of meshes in SceneObject... If I were to create a new object, I would store it's position into m_iId and for every object like it I render it using the **m_ppToGameObject->mesh? (Or whatever operator is appropriate there. Currently away from compiler.)

2.

if (i)
{
pos.x += pos_inc.x;
pos.y += pos_inc.y;
pos.y += pos_inc.z; // < -- Ugh.
}





I didn't really move them by a Z increment yet, but I did notice giving them more distance on Z fought off the flicker and limited it to the sides and bottom like before. There was a small bit of intersection, but the texture really did not like it. Your article links will still be very handy, but I had to fix that above line and distance them before I injured myself.

3. Wouldn't that still be before the for loop? What difference will this make, and where are you coming from on it?

Quote:

Also sooner or later, you will have performance problems. Drawing each mesh separately will took too much time, instead you need to rethink the approach, and call render functions only few times every frame. You can create one or few big vertex buffers which will be filled with all meshes that uses same texture, then render them in one call. Also you can create one BIG texture which will hold several textures in one place and then playing with UV coordinates you can put more data in VB, much more minimizing render calls.

So once you create vertex buffer with all data, then render it every frame

If you need to move some data that is stored in VB lock the buffer, make changes,
unlock and continue rendering.

Just some thoughts...


Advice noted, I do see what you mean when I think about my Maya modeler. My preview is handled far more quickly when I am concentrating on a single complex surface as opposed to the same object composed of several smaller objects.

But I have no knowledge of handling meshes in vertex buffers. Can you explain some more on how I accomplish it? You don't need to tell me much; I just need to understand how meshes relate to vertex buffers from .X files. I could probably take it from there.

[Edited by - zyrolasting on October 25, 2008 10:08:18 AM]

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