Sign in to follow this  

Pointers losing their type?

This topic is 4374 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Okay, let me clear a few things up before I give you any code. Number 1, I'm using 1 pointer to a single model on both draw attempts. (could be problem #1) Number 2, There ARE two things in the Scene_Objects vector. Number 3, Both objects return the same pointer to the same Model. Numebr 4, This works with only 1 Object in Scene_Objects.
void GLRenderer::DrawSceneObjects()
{
	for (int i = 0; i<Scene_Objects.size(); i++)
	{	
		Obj = Scene_Objects[i]->GetRenderInformation();
		GLRenderer::Draw(Obj);
		Obj = NULL;
		glTranslatef(0.0, 0.0, -30.0);
	}
}

I get a nasty error on this one, no compiler errors, just errors during runtime. Any clues? I can run the debugger sure, but I have no idea what to look for. [Edited by - Shamino on December 19, 2005 11:13:58 PM]

Share this post


Link to post
Share on other sites
You could start by describing the errors you get...

Then fire up the debugger and at least figure out what line it's terminating on.

Then examine the state of your variables, containers, etc at the time of the crash and figure out what it's trying to do that's causing it to crash, then figure out what would cause it to try and do such a thing. Basic debugging and troubleshooting skills, you need to apply.

Share this post


Link to post
Share on other sites
Okay, so the error is this, ran debugger, I'll ignore how rude you were.

Basically, the second go around, the program can't figure out what Obj's model information is, why are we losing this information our second go around?

Here is my Model Loading code, it works the first time, but the second time around, it breaks.... Should I set Obj to Null before I start this function each time?

void GLRenderer::Draw(MS3DModel * Obj)
{

GLboolean texEnabled = glIsEnabled( GL_TEXTURE_2D );

// Draw by group
for ( int i = 0; i < Obj->NumMeshes; i++ )
{

int materialIndex = Obj->Meshes[i].MaterialIndex;
if ( materialIndex >= 0 )
{
glMaterialfv( GL_FRONT, GL_AMBIENT, Obj->Materials[materialIndex].Ambient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, Obj->Materials[materialIndex].Diffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, Obj->Materials[materialIndex].Specular );
glMaterialfv( GL_FRONT, GL_EMISSION, Obj->Materials[materialIndex].Emissive );
glMaterialf( GL_FRONT, GL_SHININESS, Obj->Materials[materialIndex].Shininess );

if ( Obj->Materials[materialIndex].Texture > 0 )
{
glBindTexture( GL_TEXTURE_2D, Obj->Materials[materialIndex].Texture );
glEnable( GL_TEXTURE_2D );
}
else
glDisable( GL_TEXTURE_2D );
}
else
{
// Material properties?
glDisable( GL_TEXTURE_2D );
}

glBegin( GL_TRIANGLES );
{
for ( int j = 0; j < Obj->Meshes[i].NumTriangles; j++ )
{
int triangleIndex = Obj->Meshes[i].TriangleIndices[j];
const MS3DModel::Triangle * pTri = &(Obj->Triangles[triangleIndex]);

for ( int k = 0; k < 3; k++ )
{
int index = pTri->VertexIndices[k];

glNormal3fv( pTri->VertexNormals[k] );
glTexCoord2f( pTri->Textures1[k], pTri->Textures2[k] );
glVertex3fv( Obj->Vertices[index].Location );
}
}
}
glEnd();
}

if ( texEnabled )
glEnable( GL_TEXTURE_2D );
else
glDisable( GL_TEXTURE_2D );
}





Let me give you the exact messages the debugger gives me...


__vfptr CXX0030: Error: expression cannot be evaluated
NumVertices CXX0030: Error: expression cannot be evaluated
Vertices CXX0017: Error: symbol "" not found
NumTriangles CXX0030: Error: expression cannot be evaluated
Triangles CXX0017: Error: symbol "" not found
NumMeshes CXX0030: Error: expression cannot be evaluated
Meshes CXX0017: Error: symbol "" not found
NumMaterials CXX0030: Error: expression cannot be evaluated
Materials CXX0017: Error: symbol "" not found



That happens right when I call my Draw function the second time.

Share this post


Link to post
Share on other sites
To generally avoid problems like this, it is best to narrow the possibilities as much as possible. I would suggest you to qualify all suitable variables "const", in this case e.g.
void GLRenderer::Draw(const MS3DModel * Obj)
since the Draw routine isn't expected to alter the model. Also make all local variable inside the Draw method const where possible.

Next, it would be good to check routine parameters for correctness by assertions, in this case e.g.

void GLRenderer::Draw(MS3DModel * Obj)
{
// checking requirements
assert(Obj != 0);
...


Stuff like this has the advantage to point out mistakes that would have an effect here but are made elsewhere!

Unfortunately, the posted debugger output isn't helpful (at least to me). To use the debugger best in your case, you have to investigate the situation just _before_ the error happens. So, start the debugger, set a breakpoint at the line
GLboolean texEnabled = glIsEnabled( GL_TEXTURE_2D );
and run the program. When the debugger stops at the marked line the first time, you have the ability to look at the variable states "how they should be" during stepping through the routine. However, you could also simply "continue" that first stop if you know how the variables should look like. Then the debugger will stop the second time at the marked line. Compare the available variables by the values you expect. At any point a difference will occur.


What I'm curious about is that the DrawSceneObjects() routine uses a copy of Obj from the GetRenderInformation() method, and the Draw(MS3DModel*) uses a pointer to a MS3DModel. Since not visible from the given code snippets, I assume that there is a type compatibility like
typedef MS3Model* Obj
or something equivalent?


Quote:
Original post by Shamino
Should I set Obj to Null before I start this function each time?

No.

Share this post


Link to post
Share on other sites
"Expression cannot be evaluated" sounds more like something that would come up in the expression watch window than an actual error. This is straight C++ not Managed C++ right? I can't see anything in GLRenderer::Draw which writes to anything so I don't think it's in there. I suggest watching the contents of Obj all the way through both functions (try watching *(MS3DModel*)0xits_address).

Share this post


Link to post
Share on other sites
My Programming teacher suggested I investigate the "this" operator, apparently Obj loses access to its class the second time around, all those things that are unable to be determined are model information.

Here is a quote from my book that interests me.

Right now we can assume that Obj will become = to the same pointer, but not always, so we can't const it..

"Sometimes you need to find the class of an object. You may wonder how you could lose track of an object's class. However, imagine that you have an array of pointers to objects, and these pointers may point to objects of several different derived classes. How do you know what kind of object a pointer points to? We know we can use such a pointer to call a virtual function for the object, and the appropriate function will be called, depending on the type of object. The virtual function mechanism knows what kind of object the pointer points to, However, this information is not immediately available to the programmer."

Sounds like my problem, I think the problem is that Obj is losing its class.

How to remedy this?

Share this post


Link to post
Share on other sites
this is not an operator. In non-static member functions it's a pointer to the class the function was called on. Therefore in both DrawSceneObjects and Draw the this pointer will point to the GLRenderer object if those functions are not static (DrawSceneObjects appears to be non-static, as for Draw I can't tell).

I'm sorry to say this but going by the posted code I simply can't see how the Obj pointer can be the same both times Draw is called - that is, I think the Obj pointer is incorrect the second time, but that would be an error elsewhere in the code. If it is the same then it should work since the Draw function doesn't set anything except local variables.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shamino
Right now we can assume that Obj will become = to the same pointer, but not always, so we can't const it..

Hmm? Could you please post the line defining Obj? I assume Obj to be of a class derived from MS3Model, right?

Quote:
Original post by Shamino
"Sometimes you need to find the class of an object. You may wonder how you could lose track of an object's class. However, imagine that you have an array of pointers to objects, and these pointers may point to objects of several different derived classes. How do you know what kind of object a pointer points to? We know we can use such a pointer to call a virtual function for the object, and the appropriate function will be called, depending on the type of object. The virtual function mechanism knows what kind of object the pointer points to, However, this information is not immediately available to the programmer."

Sounds like my problem, I think the problem is that Obj is losing its class.

That is unlikely. SceneObjects is an array of pointers to a class (you haven't told us yet) that provides a method GetRenderInformation() returning something of the Obj's type. You copy the result to Obj in the DrawSceneObjects. If there would be really a problem in that, the compiler would complain and you wouldn't get an executable.

It is true that you as a programmer may not have an immediate possibility of checking for an object's type, but that isn't true for the compiler. A compiler will (hopefully) complain all type mismatches in advance.

I still suggest you to do an assertion on the local Obj inside Draw! As I already stated above (and also ZQJ has) it is likely that the problem isn't in the code snippets you have posted but elsewhere.

Share this post


Link to post
Share on other sites
First off, I put a check to see if Obj = 0, it still runs, therefore Obj is filled up both times, it is pointing to something, but its broken the second time around?

Nothing else in my code works with this functions, theres four things that work together to create images on my screen.

Draw, DrawSceneObjects, the vector of objects, and MS3DModel.

Obj is declared as MS3DModel * Obj; (switched this to const)
Ship1 (element 0 in the array) is declared as Ship * Ship1;
Ship2 (element 1 in the array) is declared as Ship * Ship2;

We fill up the vector manually in initgl (this is where we push_back Ship1/2 into the vector. We declare Ship1/2 as extern after the declaration of Ship.

Now we have a vector of two Ship objects, both of these have the GetRenderInformation() method, which returns a pointer to an MS3DModel;

we go to our DrawSceneObjects function, which loops through the vector activating each ship objects getrenderdata function, this returns an ms3dmodel pointer.

We set that pointer equal to Obj, we pass Obj to the Draw function, Obj is drawn according to what was returned by the getrenderdata method.

Same process happens again, until finally we begin to try to draw the second Obj, while this time it can't figure out any information specific to itself, it doesn't know how many vertices, how many anything, Obj can simply not access its own data.... Either that, or Obj wasn't set to getrenderdata's return type correctly, but it was the first time?

I'll give the MS3DModel class to you guys.

#ifndef MS3D_H
#define MS3D_H
#include <windows.h>
#include <gl\glaux.h>
#include <vector>

class MS3DModel
{
public:

MS3DModel();

virtual ~MS3DModel();

struct Vertex
{
char BoneID;
float Location[3];
};

int NumVertices;
Vertex *Vertices;

struct Triangle
{
float VertexNormals[3][3];
float Textures1[3], Textures2[3];
int VertexIndices[3];
};

int NumTriangles;
Triangle *Triangles;

struct Mesh
{
int MaterialIndex;
int NumTriangles;
int *TriangleIndices;
};

int NumMeshes;
Mesh *Meshes;

struct Material
{
float Ambient[4], Diffuse[4], Specular[4], Emissive[4];
float Shininess;
GLuint Texture;
char *TextureFilename;
};

int NumMaterials;
Material *Materials;

bool LoadModelData( const char *filename );
void ReloadTextures();
void DrawMS3DModels();
};

#endif





Could there possibly be something wrong with my Draw function?

I tried to make it Obj specific, whatever Obj equals is drawn..

Share this post


Link to post
Share on other sites
Did you try unrolling the for loop ?. Off the top of my head, there maybe there instances causing your errors:
  1. The Draw () method somehow modifies the Obj pointer, you may draw the first object two times (with slightly different positions if possible), just leave the 2nd object there. If there's something wrong with Draw () method, the 2nd draw won't succeed.
  2. The 2nd object pointer is corrupted, you may reverse the drawing operation (2 before 1) to make sure of it.
  3. There's nothing wrong with both the for loop and Draw (), the heap might be corrupted before executing the for loop.

Btw, the Obj pointer doesn't need to be set to NULL. I didn't carefully look at your Draw () method, that could possibly have something wrong also, I'm not sure.

Share this post


Link to post
Share on other sites
Figured it out, let me post this snippet of code...


Ship1->mModels.Model1 = new MS3DModel();

if ( Ship1->mModels.Model1->LoadModelData( "data/model2.ms3d" ) == false )// Loads The Model And Checks For Errors
{
MessageBox( NULL, "Couldn't load the model data\\model.ms3d", "Error", MB_OK | MB_ICONERROR );
return 0; // If Model Didn't Load Quit
}


Apparently I'm loading a model for a Ship1 object, which is the first object in my Scene_Objects vector. This was not my origional plan :\..

My plan was to load a generic model that anything that needed that resource could use, But I'm not quite sure how to go about that.

Share this post


Link to post
Share on other sites
So I understand that the second model wasn't set-up, but the assertion inside Draw hasn't detected a nil pointer. This leads me to suggest you to initialize pointers properly to 0. Don't let them have any random values, since tracking such problems is cumbersome.

Quote:
Orignal post by Shamino
My plan was to load a generic model that anything that needed that resource could use, But I'm not quite sure how to go about that.

If I understood you right, you want to have a resource manager, perhaps one especially storing models. Such a manager maps resource IDs (e.g. strings) to the objects of interest. Also the file system could be understood as such a resource manager, where the file name denotes the resource name and the resource type is very unspecific. In your case the map class from STL may be sufficient for storing, wrapped by a ModelManager class. Then the manager knows the kind of resource, and could also implement a file loader for the case that the resource isn't already loaded. The resource IDs should be (relative) file names then, so that the manager is able to complete the file path simply by prepending your model directory (or even better, it holds a lock of that directory).


BTW:
Quote:
Orignal post by Shamino
What was that about typedef haegarr?

Forget that typedef, it was nonsense.

Share this post


Link to post
Share on other sites
Thanks Haegarr, that really puts it into perspective...

So I create a list of resource ID's and simply attach them with the correct resources in a wrapper class for an STL map container. How do you decide which resource gets returned? Lots of if statements? A switch? Or like, is there a special way to do that with a map from STL? Can I simply loop through the map and check to see if two unique ID's match up, then return accordingly? That would require alot of if's, don't ya think, maybe not now but when I have lots of resources I need to manage?

Share this post


Link to post
Share on other sites
The whole point of using an STL map (std::map) is that it provides a direct lookup from the ID (key) to the thingie being stored (value). What actually happens is that it builds a binary search tree behind the scenes where each node contains a key and a value, and the sorting is done according to the key value (so they either have to be "naturally" comparable, or you provide a method for comparing them; with integer IDs there is no problem since those can be compared quite easily).

Normally one wants to store objects into STL containers rather than pointers to objects, but that doesn't work for polymorphism. So a bit more cleverness is required. Probably the easiest thing is to make use of something like boost::shared_ptr, so that in your case you could have something like


// This is a simple, "underengineered" approach, as opposed to creating a
// separate ModelManager class
class MS3DModel {
static std::map<int, boost::shared_ptr<MS3DModel> > items;
static int lastUsedId;
// other stuff
}

int MS3DModel::lastUsedId = 0;


And then you provide methods to create a Model and give it a unique ID (increment the lastUsedId, make a new Model, construct a shared_ptr using the raw pointer to that model, store it in the map using the id value (by its .insert() function), and return the ID value), access a Model by ID (just look it up in the map using its .find() function), etc.

Share this post


Link to post
Share on other sites
Should I use an STL container for each type of resource? Be it a sound resource, create a sound manager, for models, create a model manager, for textures, create a texture manager?

Instead of putting them all together in one? I would think if I were to try to deal with them all at once I'd get overwhelmed at the fact that I would have to allocate memory myself, there is an article here on Game Dev, code on the cob to be exact, but it is way to complex and doesn't use any STL containers.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shamino
Should I use an STL container for each type of resource? Be it a sound resource, create a sound manager, for models, create a model manager, for textures, create a texture manager?

Instead of putting them all together in one? I would think if I were to try to deal with them all at once I'd get overwhelmed at the fact that I would have to allocate memory myself, there is an article here on Game Dev, code on the cob to be exact, but it is way to complex and doesn't use any STL containers.

I don't think that there is "the golden way". I personally prefer to have several resource managers, but my framework handles really many kinds of extensions: plug-ins in general, file formats, compression schemes, interactive tools, scene node contexts, ... besides the "standard" resources like images, meshes, materials, and sounds. Also, most of that stuff must be accessible by a a-priori known ID to allow a binding lasting longer than the current run, so most IDs could not be generated at runtime.

Moreover, using several managers avoid the need of clients to type-cast the result returned by a manager, and I'm not a friend of type-casting.

You see, the answer to your question is somewhat depending on personal preference and, more important, the way you need to use the manager/s.

Share this post


Link to post
Share on other sites
Well currently I have a draw function that takes a pointer to a model and converts it to a generic pointer, then passes it to the drawMS3Dmodel draw function. I think this is a good way to do it since I don't have to do any conditional statements trying to figure out which model pointer we're gonna pass to the draw function, just simply set it = to Obj and pass Obj.

I think this will work well with any kind of resource manager system, it is just a matter of putting it in...

Currently my problem is getting STL maps to work, compiler seems to not like them, and I can't upgrade from Visual C++ 6 because my school wont allow me to download VS2005 on their computers, perhaps they'd make an exception, it is a senior project. They've alread supplied us with an ATI 1000 series video card, simply because we asked for a good video card.

Share this post


Link to post
Share on other sites

This topic is 4374 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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