View Full Version : Help tracking down SIGBUS/SIGSEGV errors, please?
Jones
2006.07.19, 06:02 PM
I just finished writing up an MD2 model class for OpenGL, applying whatever I could learn from the multiple tutorials on the net, and some c++ class savvy I recently aquired. After going through all 130-some errors, and reducing it to zero-errors & zero warnings, I decided to test it out. Well, naturally it didn't work. No surprises there, *all* the code I write is killed by the system or another framework for some reason or another. Usually the dreaded SIGBUS, which I have groan (hehe, get it?) to loath with a heated passion. Unfortunatly, I also have an uncanny nack at be unable to track down the cause of this error. Anyway, SIGBUS:
Your code tried to read or write a memory location where no virtual memory is mapped.
Very similar is signal 11, SIGSEGV, "Segmentation Violation". In this case, there's virtual memory mapped to this address, but it's outside the range your application is allowed to read/write.
I'm guessing this is a direct result of the malloc stuff being used in the code. At first it was because I had forgotten to allocate memory to the header, but you don't need too... heh, no easy solutions for me.
So then I put in little cout tags to tell me what just happened. I stuck them throughout the open function. Nothing. So I stuck them in my main file, right before I declared a *static* MD2 (this time within a function) and right after. It told me it was about to declare an MD2, then told me it had done so, then got a SIGBUS error. So I tried *AGAIN* this time with the MD2 as non-static. Same results, but this time with a SIGSEGV (11) error. In both cases it got to the opening function then crashed, so it's in there. Not sure where though, perhaps you guys could help, please?
I stuck the code (Zipped xCode GLUT/OpenGL project) up for download. I had to remove the build folder though, because it was 27 wopping megs, for some reason (Even after a cleaning of all targets.). All GLUT projects do that (grow huge), it's actually quite annoying.
If you need to rebuild the project structure yourself, you can find a tutorial for GLUT projects (if you don't already know how) on OneSadCookie's tutorial page, here. (http://www.onesadcookie.com/Tutorials)
Download the source. (http://homepage.mac.com/gareth.cross/OpenGL.zip)
Thanks for any help you can offer! :)
Fenris
2006.07.19, 06:11 PM
What you want to do is to enable Guard Malloc under the Debug menu in XCode and then debug your app. It will run slow (expect two-three minutes to start the app) but it will break as soon as you make your memory error.
Jones
2006.07.19, 06:15 PM
What you want to do is to enable Guard Malloc under the Debug menu in XCode and then debug your app. It will run slow (expect two-three minutes to start the app) but it will break as soon as you make your memory error.
xCode can be used to actually debug stuff? Wow... that's new, my mind is boggling. :wacko:
Thanks for the tip, I'll try that right away.
NOTE for anybody who reads this thread: Yes, I know my class does not load skins, I left that out for more portability. I'll add some functions to give the user the paths they need.
**EDIT: Did as fenris suggested, and got some stuff returned. Here's some stuff from the console:
About to declare MD2...
Declared static MD2!
Program received signal: "EXC_BAD_ACCESS".
mi_cmd_stack_list_frames: Not enough frames in stack.
mi_cmd_stack_list_frames: Not enough frames in stack.
Do you suppose it means the variable "frames" of which I have one in every class, for holding MD2 frames?
The debugger gave back these 5 (in a C sense ;) ) things that appear to be errors:
#0 0xffff88e4 in objc_msgSend_rtp
#1 0x9001ada0 in fread
#2 0x00002768 in MD2::Open
#3 0x0000378c in init
#4 0x00003800 in main
#5 (null)
I think that means that in my main loop, where I call init() in which I call the MD2::Open function, in which fread is used, there is a problem. That's what I originally thought. What exactly does objc_msgSend_rtp means, does it help me in any way?
Fenris
2006.07.19, 06:26 PM
Gimme a second, I'm halfway through fixing it for you :P
Jones
2006.07.19, 06:32 PM
Gimme a second, I'm halfway through fixing it for you :P
If it's any help, I noticed in all the tutorials I followed, "header" is not a pointer, like I made it. I tried changing it to a non-pointer, in every case it's used. Should have worked, I figured, but I got more debug stuff. This time complaining about GMmalloc.
Fenris
2006.07.19, 06:33 PM
Right, there it was. In the MD2.h file, you're trying to fread the header into the header pointer. Only, that doesn't have any allocated memory to it. You're just reading the header into any random memory address, which can be anything. In my case, it thrashed the stack frames (which aren't related to MD2 frames, by the way. Just a bad name clash. :P )
Anyway, to fix it, just go
header = new header_MD2();
on line 144 (just before the fread call) and then add
delete header;
to the cleanse method, and you're good to go. :)
Fenris
2006.07.19, 06:36 PM
Anyway, if you hate SIGBUS/SIGSEGV with a passion, just turn on guard malloc, hit Cmd-Y and wait for the program to die. In 99% of the cases, it has broken on the selected line, and the problem is that you have either:
• Written to unallocated memory
• Overwritten a buffer
• Freed memory twice
Hope this helps. :)
Jones
2006.07.19, 06:46 PM
Hurray it's working!
Er... wait...
Almost! :p
It get's to "Read Skins." and then crashes now.
Actually, I would guess that it wouldn't be able to do that, but I have no skins in my test model, so I think that's why it thinks it's able to load them. :lol:
This is strange... the skins loader works, and it's basically no different that the texture coordinates fetching process. *scratches head* :???:
EDIT: I tried it with another model in which I placed skin data, and still claims it could load them. The error is now located in my malloc stuff, according to the debugger and not fread. Hmm.
Nothing looks wrong here, right?
texcoords = (texCoord_MD2 *)malloc(sizeof(texCoord_MD2) * header->num_TexCoords);
fseek(md2_open_fs, header->ofs_TexCoords, SEEK_SET);
fread(texcoords, sizeof(texCoord_MD2), header->num_TexCoords, md2_open_fs);
EDIT: Pasting it here caused me to see it... it should be a * not a comma. I'll try that...
EDIT: No, it was right.
Jones
2006.07.19, 11:22 PM
Perhaps if I tried some sort of alternative, like calloc, or somthing... :\
Oh fenris, I realized I forgot to thank you for your help, it was much appreciated. If I ever release/make anything with this, I'll stick your name in!
Fenris
2006.07.20, 03:22 AM
No problem, happy to help. :) I'm in a hurry to catch a plane at the moment, but if your problem still persists when I get back, I'll give it another shot. ;)
backslash
2006.07.20, 08:17 AM
Perhaps if I tried some sort of alternative, like calloc, or somthing...
For C++ you should use the keywords new and delete rather than malloc(), calloc() and free(). This is vital for classes if you want the constructor functions to run.
Jones
2006.07.20, 11:57 AM
For C++ you should use the keywords new and delete rather than malloc(), calloc() and free(). This is vital for classes if you want the constructor functions to run.
Well, no memory allocation goes on in my constructor functions. And can new declare multiple instances, like malloc can do, for example:
bob = (int)malloc(sizeof(int) * 10)
// Produces
bob[10];
What could my malloc stuff be doing wrong? (To the class, I mean.)
EDIT:
I've realised that the error is not in the memory allocation, it's in the reading. If I write this:
texcoords = (texCoord_MD2 *)malloc(sizeof(texCoord_MD2) * header->num_TexCoords);
cout << "Malloc tag: texcoords." << endl;
fseek(md2_open_fs, header->ofs_TexCoords, SEEK_SET);
cout << "Fseek tag: texcoords." << endl;
fread(texcoords, sizeof(texCoord_MD2), header->num_TexCoords, md2_open_fs);
cout << "Read Texture coords." << endl;
I'll get this back:
// Stuff from before the texcoords...
About to declare MD2...
Declared static MD2!
Read Header.
Read Skins.
// Texcoords...
Malloc tag: texcoords.
Fseek tag: texcoords.
// Failure!
OpenGL has exited due to signal 10 (SIGBUS).
Does the code I posted above seem wrong in any way?
EDIT 2: Forgot, the MD2 is not actually static, btw.
EDIT 3:
THEORY:
What needs to happen here, is for all this malloc junk to dissapear. Honestly, having to manage your own memory... what are we programming with here, fortran? :p No, I'll have to try something simpler... like declaring arrays with new, that are sized to the "num_" variables. That'll make things easier... I think.
Jones
2006.07.20, 03:35 PM
Well, I stuck in some "new" commands, like this:
texcoords = new texCoord_MD2[header->num_TexCoords];
But I get std::bad_alloc errors.
Well, I have no idea what the problem is here. :\
Maybe I'm trying to allocate too much memory, and it doesn't allocate all of it, then tries to read too much into not-enough memory? :???:
Jones
2006.07.20, 04:07 PM
SOLVED!
It was my endian-convertor functions. I changed all my ints to uints, and now it works!
Now... to see if it will actually draw anything...
zhivaja
2006.07.21, 05:41 AM
I have the same problem
Fenris
2006.07.21, 06:29 AM
Zhivaja: /exactly/ the same (with Md2 files) or just SIGBUS/SIGSEGV?
Jones
2006.07.29, 11:18 PM
EDIT: You can ignore this post, I'll try something else.
Muhahaha, I... Jones... have returned to dig up another thread, just as it was about to die!
Yeah, if the mods could rename this to suit the new problem that'd be great, something along the lines of "More MD2 troubles Part II extended edition" would suffice.
No malloc problems anymore, but the model does not show. The code has been reworked a bit, can't remember how much because I've already forgotten everything about this thread.
/* q2model.h
Written by Gareth Cross, 2006.
Special thanks to Fenris for
his efforts towards debugging
this class in particular.
*/
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include "simple_endian.h"
#include "normals.h"
using namespace std;
#define GOOD_MD2_ID 844121161
#define GOOD_MD2_VERSION 8
#define MD2_NONE_LOADED 652863
#define MD2_NO_FILE 289143
#define MD2_ALREADY_LOADED 579411
#define MD2_BAD_FILE 113278
#define MD2_NO_ERROR 973324
typedef struct MD2header {
unsigned int magicID; // MD2 identification, must be 844121161 ("IDP2").
unsigned int version; // MD2 version. Should always be 8.
unsigned int skinWidth; // Skin width, in pixels.
unsigned int skinHeight; // Skin height, in pixels.
unsigned int frameSize; // The size of each frame, in bytes.
unsigned int num_Skins; // Number of skins on this model.
unsigned int num_Vertices; // How many vertices for each frame.
unsigned int num_TexCoords; // Number of texture coordinates.
unsigned int num_Triangles; // This many triangles for each frame.
unsigned int num_GLCommands; // Number of GL commands in the list.
unsigned int num_Frames; // This many frames.
unsigned int ofs_Skins; // This many bytes until the skin list.
unsigned int ofs_TexCoords; // Number of bytes til the texture coords.
unsigned int ofs_Triangles; // Offset, in bytes, to the list of triangles.
unsigned int ofs_Frames; // This many bytes until the list of frames.
unsigned int ofs_GLCommands; // Offset until the GL commands list. (In bytes).
unsigned int ofs_End; // Number of bytes until the end of the file.
};
typedef struct MD2skin {
char name[64]; // Path to the skin file. It's relative to Q2's base.
};
typedef struct MD2texCoords {
unsigned short s; // X texture coordinate.
unsigned short t; // Y texture coordinate.
};
typedef struct MD2triangle {
unsigned short vertex[3]; // Indices to the vertices.
unsigned short texture[3]; // Insices to the texture coordinates.
};
typedef struct MD2vertex {
unsigned char v[3]; // X, Y & Z of the vertice.
unsigned char index; // Indice to the precalculated table of normals.
};
typedef struct MD2frame {
float scale[3]; // X, Y & Z scaling factor.
float translate[3]; // X, Y & Z translate factor.
char name[16]; // 16 letter long name of this frame.
MD2vertex *vertices; // The vertex array for this frame.
};
typedef struct MD2gl {
float s; // Texture mapping X.
float t; // Texture mapping Y.
unsigned int index; // Indice to the vertex arrays.
};
class MD2 {
protected:
MD2header *header; // Header.
MD2texCoords *texpos; // Texture coordinates.
MD2triangle *triangles; // Triangles.
MD2frame *frames; // Frames.
unsigned int *glCom; // OpenGL command lists.
bool modelLoaded; // This will tell us if a model has been loaded.
FILE *modelStream; // A file stream for loading the model.
unsigned int md2_cur_error_nu; // What error was just passed?
public:
MD2(); // Constructor.
bool Open(char*); // Open a model.
bool Render(unsigned int, bool); // Render the model.
bool IRender(unsigned int, float, bool); // Render the model... using interpolation.
bool Cleanse(); // Flush the model from memory.
unsigned int getErr(); // Get the last posted error.
// Skins are public so the user can load them.
MD2skin *skins; // Skins.
};
/* Constructor, real simple. */
MD2::MD2() {
// The model was just declared, so it's not loaded, and their is probably no error.
modelLoaded = FALSE;
md2_cur_error_nu = MD2_NO_ERROR;
}
/* Open: Loads the MD2 into memory. */
/* NOTES:
On a PowerPC, or even a SPARC?
No worries, this function handles
big and little endian systems.
*/
bool MD2::Open(char *modelToOpen) {
// If a model is already open.
if(modelLoaded == TRUE) {
md2_cur_error_nu = MD2_ALREADY_LOADED;
return(FALSE);
}
// Open the MD2.
modelStream = fopen(modelToOpen, "rb");
if (!modelStream) {
md2_cur_error_nu = MD2_NO_FILE;
return(FALSE);
}
// Allocate some memory to the file header.
header = new MD2header();
// Read the header.
fread(header, 1, sizeof(MD2header), modelStream);
// Big endian? Swap bytes!
#if defined(__BIG_ENDIAN__)
swapUINT(header->magicID);
swapUINT(header->version);
#endif
// Check if we're actually loading an MD2.
if((header->magicID != GOOD_MD2_ID) || (header->version != GOOD_MD2_VERSION)) {
// If not, close the file and return.
fclose(modelStream);
md2_cur_error_nu = MD2_BAD_FILE;
return(FALSE);
}
// It's now ok to swap the rest of the header, if needed.
#if defined(__BIG_ENDIAN__)
swapUINT(header->skinWidth);
swapUINT(header->skinHeight);
swapUINT(header->frameSize);
swapUINT(header->num_Skins);
swapUINT(header->num_Vertices);
swapUINT(header->num_TexCoords);
swapUINT(header->num_Triangles);
swapUINT(header->num_GLCommands);
swapUINT(header->num_Frames);
swapUINT(header->ofs_Skins);
swapUINT(header->ofs_TexCoords);
swapUINT(header->ofs_Triangles);
swapUINT(header->ofs_Frames);
swapUINT(header->ofs_GLCommands);
swapUINT(header->ofs_End);
#endif
// Allocate, and load skin information.
skins = (MD2skin*)malloc(sizeof(MD2skin) * header->num_Skins);
fseek(modelStream, header->ofs_Skins, SEEK_SET);
fread(skins, sizeof(MD2skin), header->num_Skins, modelStream);
// Allocate, and load texture coordinate information.
texpos = (MD2texCoords*)malloc(sizeof(MD2texCoords) * header->num_TexCoords);
fseek(modelStream, header->ofs_TexCoords, SEEK_SET);
fread(texpos, sizeof(MD2texCoords), header->num_TexCoords, modelStream);
// Swap all the texture coordinates, if we have to.
#if defined(__BIG_ENDIAN__)
for (unsigned int counter = 0; counter < header->num_TexCoords; counter++) {
swapUSHORT(texpos[counter].s);
swapUSHORT(texpos[counter].t);
}
#endif
// Allocate, and load triangle information.
triangles = (MD2triangle*)malloc(sizeof(MD2triangle) * header->num_Triangles);
fseek(modelStream, header->ofs_Triangles, SEEK_SET);
fread(triangles, sizeof(MD2triangle), header->num_Triangles, modelStream);
// If required, swap the tris.
#if defined(__BIG_ENDIAN__)
// For every triangle...
for (unsigned int counter2 = 0; counter2 < header->num_Triangles; counter2++) {
for (unsigned int counter3 = 0; counter3 < 3; counter3++) {
// Swap the vertice and texture bytes.
swapUSHORT(triangles[counter2].vertex[counter3]);
swapUSHORT(triangles[counter2].texture[counter3]);
}
}
#endif
// Allocate, and load the OpenGL command lists.
glCom = (unsigned int*)malloc(sizeof(unsigned int) * header->num_GLCommands);
fseek(modelStream, header->ofs_GLCommands, SEEK_SET);
fread(glCom, sizeof(MD2gl), header->num_GLCommands, modelStream);
// Go ahead and swap the GL comands if we have to.
#if defined(__BIG_ENDIAN__)
for (unsigned int counter4 = 0; counter4 < header->num_GLCommands; counter4++) {
swapUINT(glCom[counter4]);
}
#endif
// Allocate, and load the frame data.
frames = (MD2frame*)malloc(sizeof(MD2frame) * header->num_Frames);
fseek(modelStream, header->ofs_Frames, SEEK_SET);
// For all frames...
for (unsigned int counter5 = 0; counter5 < header->num_Frames; counter5++) {
// Allocate memory for the vertices of that frame.
frames[counter5].vertices = (MD2vertex *)malloc(sizeof(MD2vertex) * header->num_Vertices);
// Read the frame data.
fread(frames[counter5].scale, sizeof(float[3]), 1, modelStream);
fread(frames[counter5].translate, sizeof(float[3]), 1, modelStream);
fread(frames[counter5].name, sizeof(char), 16, modelStream);
fread(frames[counter5].vertices, sizeof(MD2vertex), header->num_Vertices, modelStream);
// If neccessary, swap the frame data.
#if defined(__BIG_ENDIAN__)
swapFLOAT(frames[counter5].scale[0]);
swapFLOAT(frames[counter5].scale[1]);
swapFLOAT(frames[counter5].scale[2]);
swapFLOAT(frames[counter5].translate[0]);
swapFLOAT(frames[counter5].translate[1]);
swapFLOAT(frames[counter5].translate[2]);
#endif
}
// Close the model, set the load check bool to true, and return ok.
fclose(modelStream);
modelLoaded = TRUE;
md2_cur_error_nu = MD2_NO_ERROR;
return(TRUE);
}
/* Render: Draws a frame, either with command lists or without. No interp is used. */
/* NOTES:
This code is fairly long because
I bothered to do everything in stages,
held in vector variables. The command
list code is weird, but avoids strange
C/C++ shorthand.
*/
bool MD2::Render(unsigned int thisFrame, bool fasterGL) {
// If no model is loaded.
if (modelLoaded == FALSE) {
md2_cur_error_nu = MD2_NONE_LOADED;
return(FALSE);
}
// Check the frame request.
if ((thisFrame < 1) || (thisFrame > header->num_Frames)) {
// Invalid frame? Then frame one!
thisFrame = 1;
}
// Use GL fans and strips? No.
if(fasterGL == FALSE) {
GLfloat render_v[3]; // A temporary vertex holder.
GLfloat render_n[3]; // A temporary vertex normal.
GLfloat render_t[2]; // A termporary texture coord box.
GLfloat render_s[3]; // Scaling value for decompression.
GLfloat render_m[3]; // Translate (move) value for decompression.
GLfloat render_c[3]; // Temporary holder for uncompressed vertex coordinates.
glBegin(GL_TRIANGLES);
// For every triangle...
for (unsigned int counter6 = 0; counter6 < header->num_Triangles; counter6++) {
// For every vertex of that triangle...
for (int counter7 = 0; counter7 < 3; counter7++) {
// Get the texture coordinates.
render_t[0] = (GLfloat)texpos[triangles[counter6].texture[counter7]].s / header->skinWidth;
render_t[1] = (GLfloat)texpos[triangles[counter6].texture[counter7]].t / header->skinHeight;
// Get the vertex normal. (Precalculated.)
int normalIndex = frames[thisFrame].vertices[triangles[counter6].vertex[counter7]].index;
render_n[0] = md2norms[normalIndex][0];
render_n[1] = md2norms[normalIndex][1];
render_n[2] = md2norms[normalIndex][2];
// Get the vertex points & scaling/translating values.
render_c[0] = frames[thisFrame].vertices[triangles[counter6].vertex[counter7]].v[0];
render_c[1] = frames[thisFrame].vertices[triangles[counter6].vertex[counter7]].v[1];
render_c[2] = frames[thisFrame].vertices[triangles[counter6].vertex[counter7]].v[2];
render_s[0] = frames[thisFrame].scale[0];
render_s[1] = frames[thisFrame].scale[1];
render_s[2] = frames[thisFrame].scale[2];
render_m[0] = frames[thisFrame].translate[0];
render_m[1] = frames[thisFrame].translate[1];
render_m[2] = frames[thisFrame].translate[2];
// Use them to compile final vertice coordinates.
render_v[0] = (render_c[0] * render_s[0]) + render_m[0];
render_v[1] = (render_c[1] * render_s[1]) + render_m[1];
render_v[2] = (render_c[2] * render_s[2]) + render_m[2];
// Give OpenGL the values it needs.
glTexCoord2fv(render_t);
glNormal3fv(render_n);
glVertex3fv(render_v);
}
}
glEnd();
}
// Are we using GL fans and strips? Yes.
else if (fasterGL == TRUE) {
MD2gl rendergl_p; // Packet to hold temporary gl commands.
GLfloat rendergl_v[3]; // Vertice.
GLfloat rendergl_n[3]; // Vertice normal holder.
GLfloat rendergl_s[3]; // Vertice scalar.
GLfloat rendergl_m[3]; // Translate value.
unsigned int counter8 = 0; // Counter, to run through the GL command list.
unsigned int nextMarker = 0; // How many ints till next triangle type marker.
unsigned int tempCom; // Holds current command list integer.
while (counter8 < header->num_GLCommands) {
tempCom = glCom[counter8];
// If we're at the next/or first triangle type marker.
if (counter8 == nextMarker) {
// Negative numbers mean a fan.
if (tempCom < 0) {
glBegin(GL_TRIANGLE_FAN); // Select a fan.
nextMarker = 3 * (tempCom * -1) + 1; // Next marker is this many ints.
// Marker = 3 (data nums) * current int (made positive) plus one.
}
// Postive numbers mean a strip.
else if (tempCom > 0) {
glBegin(GL_TRIANGLE_STRIP); // Select a strip.
nextMarker = 3 * (tempCom) + 1; // Next marker is this many ints.
// Marker = 3 (data nums) * current int plus one.
}
// If it's zero... we're done!
else if (tempCom == 0) {
glEnd(); // Finish drawing.
}
counter8++; // Next!
}
// If we're not at a triangle type marker.
else {
// For every vertice until the next marker...
for (unsigned int counter9 = counter8; counter9 < nextMarker - 1; counter9 += 3) {
// Get the vertice information.
rendergl_p.s = glCom[counter9];
rendergl_p.t = glCom[counter9 + 1];
rendergl_p.index = glCom[counter9 + 2];
// Get the vertex normal.
int normalIndex_gl = frames[thisFrame].vertices[rendergl_p.index].index;
rendergl_n[0] = md2norms[normalIndex_gl][0];
rendergl_n[1] = md2norms[normalIndex_gl][1];
rendergl_n[2] = md2norms[normalIndex_gl][2];
// Get the vertex points & scaling/translating values.
rendergl_v[0] = frames[thisFrame].vertices[rendergl_p.index].v[0];
rendergl_v[1] = frames[thisFrame].vertices[rendergl_p.index].v[1];
rendergl_v[2] = frames[thisFrame].vertices[rendergl_p.index].v[2];
rendergl_s[0] = frames[thisFrame].scale[0];
rendergl_s[1] = frames[thisFrame].scale[1];
rendergl_s[2] = frames[thisFrame].scale[2];
rendergl_m[0] = frames[thisFrame].translate[0];
rendergl_m[1] = frames[thisFrame].translate[1];
rendergl_m[2] = frames[thisFrame].translate[2];
// Finish off the final vertice coordinates.
rendergl_v[0] = (rendergl_v[0] * rendergl_s[0]) + rendergl_m[0];
rendergl_v[1] = (rendergl_v[1] * rendergl_s[1]) + rendergl_m[1];
rendergl_v[2] = (rendergl_v[2] * rendergl_s[2]) + rendergl_m[2];
// Give OpenGL what it needs to draw.
glTexCoord2f(rendergl_p.s, rendergl_p.t);
glNormal3fv(rendergl_n);
glVertex3fv(rendergl_v);
}
counter8 = counter8 + nextMarker;
}
}
}
// DONE! TEH WOOT! HURRAY!
md2_cur_error_nu = MD2_NO_ERROR;
return(TRUE);
}
bool MD2::IRender(unsigned int thisFrame, float itp, bool fasterGL) {
// Do we actually have a model to render?
if (modelLoaded == FALSE) {
md2_cur_error_nu = MD2_NONE_LOADED;
return(FALSE);
}
// Is the requested frame valid?
if ((thisFrame < 0) || (thisFrame > header->num_Frames)) {
// If not, choose frame one.
thisFrame = 1;
}
// Using triangle strips/fans? No.
if (fasterGL == FALSE) {
GLfloat irender_t[2]; // Texture coordinates.
GLfloat irender_v1[3], irender_v2[3], irender_v[3]; // Current, next & final vertice.
GLfloat irender_n1[3], irender_n2[3], irender_n[3]; // Current, next & final normals.
MD2vertex *irender_vs1, *irender_vs2; // Vertice info holders.
glBegin(GL_TRIANGLES);
// For every triangle.
for(unsigned int counter9 = 0; counter9 < header->num_Triangles; counter9++) {
// And every vertice.
for (unsigned int counter10 = 0; counter10 < 3; counter10++) {
// Get the temporary vertices, this frame and the next.
irender_vs1 = &frames[thisFrame].vertices[triangles[counter9].vertex[counter10]];
irender_vs2 = &frames[thisFrame + 1].vertices[triangles[counter9].vertex[counter10]];
// Setup an index, and use it to get and calculate texture coordinates.
unsigned int irender_ti = triangles[counter9].texture[counter10];
irender_t[0] = (GLfloat)texpos[irender_ti].s / header->skinWidth;
irender_t[1] = (GLfloat)texpos[irender_ti].t / header->skinHeight;
// This for loop system is different that past used methods, it's just an alternative. *shrug*
for (unsigned int counter11 = 0; counter11 < 3; counter11++) {
// Get the first normal.
irender_n1[counter11] = md2norms[irender_vs1->index][counter11];
// Get the second normal.
irender_n2[counter11] = md2norms[irender_vs2->index][counter11];
// Interpolate the two normals.
irender_n[counter11] = irender_n1[counter11] + itp * (irender_n2[counter11] - irender_n2[counter11]);
// Get the first vertice.
irender_v1[counter11] = frames[thisFrame].scale[counter11] * irender_vs1->v[counter11] + frames[thisFrame].translate[counter11];
// Get the second vertice.
irender_v2[counter11] = frames[thisFrame + 1].scale[counter11] * irender_vs2->v[counter11] + frames[thisFrame + 1].translate[counter11];
// Interpolate the two vertices.
irender_v[counter11] = irender_v1[counter11] + itp * (irender_v2[counter11] - irender_v1[counter11]);
}
// Pass values to OpenGL.
glTexCoord2fv(irender_t);
glNormal3fv(irender_n);
glVertex3fv(irender_v);
}
}
glEnd();
}
// Use triangle strip/fans? Yup.
else if (fasterGL = TRUE) {
MD2gl irendergl_p; // GL command packet.
MD2vertex *irendergl_vs1, *irendergl_vs2; // Vertice info packets.
GLfloat irendergl_v1[3], irendergl_v2[3]; // Current and next vertices.
GLfloat irendergl_v[3]; // Final vertex.
GLfloat irendergl_n1[3], irendergl_n2[3]; // Current and next normals.
GLfloat irendergl_n[3]; // Final normal.
unsigned int nextMarker_i = 0; // How many ints till next triangle type marker.
unsigned int counter12 = 0; // Yet another counter.
unsigned int tempCom_i; // Temporaray holder for the commands.
// While there are commands left to process.
while (counter12 < header->num_GLCommands) {
// Grab the current number.
tempCom_i = glCom[counter12];
// We're at the next triangle marker...
if (counter12 == nextMarker_i) {
// Negative numbers mean a fan.
if (tempCom_i < 0) {
glBegin(GL_TRIANGLE_FAN); // Choose a fan.
nextMarker_i = 3 * (tempCom_i * -1) + 1; // Set the next marker.
// Marker = 3 (data nums) * current int (made positive) plus one.
}
// Positive? Strip triangle.
else if (tempCom_i > 0) {
glBegin(GL_TRIANGLE_STRIP); // Take a strip tool.
nextMarker_i = 3 * (tempCom_i) + 1; // Marker.
// Marker = 3 (data nums) * current int plus one.
}
// Equal to zero means we're finished.
else if (tempCom_i == 0) {
glEnd(); // Finish rendering.
}
counter12++; // Next, please!
}
// Not a marker? Go on with vertice drawing then...
else {
// For every vertex. (Till the next marker.)
for (unsigned int counter13 = counter12; counter13 < nextMarker_i -1; counter13 += 3) {
// I want the vertex info!!!
irendergl_p.s = glCom[counter13];
irendergl_p.t = glCom[counter13 + 1];
irendergl_p.index = glCom[counter13 + 2];
// Fill up our temporary vertex slots.
irendergl_vs1 = &frames[thisFrame].vertices[irendergl_p.index];
irendergl_vs2 = &frames[thisFrame + 1].vertices[irendergl_p.index];
for (unsigned int counter14 = 0; counter14 < 3; counter14++) {
// Fill up the current, and next normal.
irendergl_n1[counter14] = md2norms[irendergl_vs1->index][counter14];
irendergl_n2[counter14] = md2norms[irendergl_vs2->index][counter14];
// Interpolate both normals.
irendergl_n[counter14] = irendergl_n1[counter14] + itp * (irendergl_n2[counter14] - irendergl_n1[counter14]);
// Get the current, and next vertice.
irendergl_v1[counter14] = frames[thisFrame].scale[counter14] * irendergl_vs1->v[counter14] + frames[thisFrame].translate[counter14];
irendergl_v2[counter14] = frames[thisFrame + 1].scale[counter14] * irendergl_vs2->v[counter14] + frames[thisFrame + 1].translate[counter14];
// Interpolate them! (The vertex coords.)
irendergl_v[counter14] = irendergl_v1[counter14] + itp * (irendergl_v2[counter14] - irendergl_v1[counter14]);
}
// Pass GL values to the renderer.
glTexCoord2f((GLfloat)irendergl_p.s, (GLfloat)irendergl_p.t);
glNormal3fv(irendergl_n);
glVertex3fv(irendergl_v);
}
}
}
}
// Done.
md2_cur_error_nu = MD2_NO_ERROR;
return(TRUE);
}
/* Cleanse: Just clean all the md2 data out of memory. */
/* NOTES:
The header is removed last, because
we need it to get rid of the frames.
*/
bool MD2::Cleanse() {
// No model to clean out ?
if (modelLoaded == FALSE) {
md2_cur_error_nu = MD2_NONE_LOADED;
return(FALSE);
}
// Remove the skins.
if(skins) {
free(skins);
skins = NULL;
}
// Remove the texture pos.
if(texpos) {
free(texpos);
texpos = NULL;
}
// Remove the triangle data.
if(triangles) {
free(triangles);
triangles = NULL;
}
// Remove the gl command lists.
if(glCom) {
free(glCom);
glCom = NULL;
}
// Remove the frames.
if(frames) {
// Make sure all the vertices are killed. It's a common error to leave them behind.
// That causes memory leaks!
for (unsigned int count_del = 0; count_del < header->num_Frames; count_del++) {
free(frames[count_del].vertices);
frames[count_del].vertices = NULL;
}
free(frames);
frames = NULL;
}
// Remove the header.
if(header) {
delete header; // The header is killed last because we still need to know the number of frames.
header = NULL;
}
modelLoaded = FALSE;
md2_cur_error_nu = MD2_NO_ERROR;
return(TRUE);
}
/* Simple function, return the last posted error. */
unsigned int MD2::getErr() {
return(md2_cur_error_nu);
}
I am so sick and tired of seeing nothing appear on my screen, every time I compile. If there is something wrong here, *please* *please* *please* point it out. I don't expect you to try and take the code and stick it in your own project and add your own tags and such, just *if* you see something wrong, please tell me!
However, should you *wish* to look at the source in closer detail, the project can be downloaded here:
http://homepage.mac.com/gareth.cross/md2/OpenGL.zip
The project is in xCode versions 2.0 and 2.3, no builds are included, and ignore everything in the "md2 work" folder. It is irrelevant. Also ignore all the camera code, I cut it out.
Thanks!
EDIT: I tried inserting more finely-placed error checkers, and I still get the no error signal.
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.