I noticed that my game was crashing with a call to quad3d. This happens randomly, so I initially suspected overflow, or something similarly nasty and subversive! Basically, on my menu screen, the player can rotate a cube to select what he or she wants to do (New Game, Exit, etc).
I logged some of the values that my game was passing to quad3d:
Here's the call:
quad3d(b, POLYTYPE_PTEX, nav_texture[face], &vtx1, &vtx2, &vtx3, &vtx4);
Here's the type of numbers you see when the program doesn't crash:
vtx1: 8642240 6481680 11927552 vtx2: 8642240 9246960 11927552 vtx3: 12329280 9246960 11927552 vtx4: 12329280 6481680 11927552
Here's some from when it does:
vtx1: 320 120 2097169 vtx2: 320 15728520 2097169 vtx3: 20971360 15728520 2097169 vtx4: 20971360 120 2097169
The entire 3d navigation code is relatively self-contained. It's also part of a game started during a hack, so it's pretty messy:
Header:
| 1 | #ifndef nav3d |
| 2 | #define nav3d |
| 3 | |
| 4 | #define NUM_VERTICES 8 |
| 5 | #define NUM_FACES 6 |
| 6 | |
| 7 | typedef struct VTX |
| 8 | { |
| 9 | fixed x, y, z; |
| 10 | } VTX; |
| 11 | |
| 12 | typedef struct QUAD |
| 13 | { |
| 14 | VTX *vtxlist; |
| 15 | int id; |
| 16 | int v1, v2, v3, v4; |
| 17 | } QUAD; |
| 18 | |
| 19 | typedef struct SHAPE |
| 20 | { |
| 21 | fixed x, y, z; |
| 22 | fixed rx, ry, rz; |
| 23 | fixed dz; |
| 24 | fixed drx, dry, drz; |
| 25 | } SHAPE; |
| 26 | |
| 27 | VTX points[] = |
| 28 | { |
| 29 | { -32 << 16, -32 << 16, -32 << 16 }, |
| 30 | { -32 << 16, 32 << 16, -32 << 16 }, |
| 31 | { 32 << 16, 32 << 16, -32 << 16 }, |
| 32 | { 32 << 16, -32 << 16, -32 << 16 }, |
| 33 | { -32 << 16, -32 << 16, 32 << 16 }, |
| 34 | { -32 << 16, 32 << 16, 32 << 16 }, |
| 35 | { 32 << 16, 32 << 16, 32 << 16 }, |
| 36 | { 32 << 16, -32 << 16, 32 << 16 }, |
| 37 | }; |
| 38 | |
| 39 | QUAD faces[] = |
| 40 | { |
| 41 | { points, 0, 0, 3, 2, 1 }, |
| 42 | { points, 1, 4, 5, 6, 7 }, |
| 43 | { points, 2, 0, 1, 5, 4 }, |
| 44 | { points, 3, 2, 3, 7, 6 }, |
| 45 | { points, 4, 0, 4, 7, 3 }, |
| 46 | { points, 5, 1, 2, 6, 5 } |
| 47 | }; |
| 48 | |
| 49 | SHAPE nav_cube; |
| 50 | VTX output_points[NUM_VERTICES]; |
| 51 | QUAD output_faces[NUM_FACES]; |
| 52 | |
| 53 | int mov_count, mov_direction; |
| 54 | |
| 55 | BITMAP *nav_texture[6], *plank; |
| 56 | char keybuf[KEY_MAX]; |
| 57 | |
| 58 | #endif |
Here's the code that renders and translates the cube:
| 1 | void translate_shapes(void) |
| 2 | { |
| 3 | |
| 4 | int c, d; |
| 5 | MATRIX matrix; |
| 6 | VTX *outpoint = output_points; |
| 7 | QUAD *outface = output_faces; |
| 8 | |
| 9 | get_transformation_matrix(&matrix, itofix(1), nav_cube.rx, nav_cube.ry, nav_cube.rz, nav_cube.x, nav_cube.y, nav_cube.z); |
| 10 | |
| 11 | for (d = 0; d < NUM_VERTICES; d++) { |
| 12 | apply_matrix(&matrix, points[d].x, points[d].y, points[d].z, |
| 13 | &outpoint[d].x, &outpoint[d].y, &outpoint[d].z); |
| 14 | persp_project(outpoint[d].x, outpoint[d].y, outpoint[d].z, |
| 15 | &outpoint[d].x, &outpoint[d].y); |
| 16 | } |
| 17 | |
| 18 | for (d=0; d<NUM_FACES; d++) { |
| 19 | outface[d] = faces[d]; |
| 20 | outface[d].vtxlist = outpoint; |
| 21 | } |
| 22 | |
| 23 | outpoint += NUM_VERTICES; |
| 24 | outface += NUM_FACES; |
| 25 | |
| 26 | } |
| 27 | |
| 28 | void draw_quad(BITMAP *b, VTX *v1, VTX *v2, VTX *v3, VTX *v4, int face) |
| 29 | { |
| 30 | |
| 31 | /* four vertices */ |
| 32 | V3D vtx1 = { 0, 0, 0, 0, 0, 0 }; |
| 33 | V3D vtx2 = { 0, 0, 0, 32<<16, 0, 0 }; |
| 34 | V3D vtx3 = { 0, 0, 0, 32<<16, 32<<16, 0 }; |
| 35 | V3D vtx4 = { 0, 0, 0, 0, 32<<16, 0 }; |
| 36 | |
| 37 | vtx1.x = v1->x; vtx1.y = v1->y; vtx1.z = v1->z; |
| 38 | vtx2.x = v2->x; vtx2.y = v2->y; vtx2.z = v2->z; |
| 39 | vtx3.x = v3->x; vtx3.y = v3->y; vtx3.z = v3->z; |
| 40 | vtx4.x = v4->x; vtx4.y = v4->y; vtx4.z = v4->z; |
| 41 | |
| 42 | log_write(" vtx1: %i %i %i", vtx1.x, vtx1.y, vtx1.z ); |
| 43 | log_write(" vtx2: %i %i %i", vtx2.x, vtx2.y, vtx2.z ); |
| 44 | log_write(" vtx3: %i %i %i", vtx3.x, vtx3.y, vtx3.z ); |
| 45 | log_write(" vtx4: %i %i %i", vtx4.x, vtx4.y, vtx4.z ); |
| 46 | |
| 47 | quad3d(b, POLYTYPE_PTEX, nav_texture[face], &vtx1, &vtx2, &vtx3, &vtx4); // Crashes here! |
| 48 | |
| 49 | } |
| 50 | |
| 51 | int quad_cmp(const void *e1, const void *e2) |
| 52 | { |
| 53 | |
| 54 | QUAD *q1 = (QUAD *)e1; |
| 55 | QUAD *q2 = (QUAD *)e2; |
| 56 | |
| 57 | fixed d1 = q1->vtxlist[q1->v1].z + q1->vtxlist[q1->v2].z + |
| 58 | q1->vtxlist[q1->v3].z + q1->vtxlist[q1->v4].z; |
| 59 | |
| 60 | fixed d2 = q2->vtxlist[q2->v1].z + q2->vtxlist[q2->v2].z + |
| 61 | q2->vtxlist[q2->v3].z + q2->vtxlist[q2->v4].z; |
| 62 | |
| 63 | return d2 - d1; |
| 64 | |
| 65 | } |
| 66 | |
| 67 | void draw_shapes(BITMAP *b) |
| 68 | { |
| 69 | |
| 70 | int c; |
| 71 | QUAD *face = output_faces; |
| 72 | VTX *v1, *v2, *v3, *v4; |
| 73 | |
| 74 | qsort(output_faces, NUM_FACES, sizeof(QUAD), quad_cmp); |
| 75 | |
| 76 | for (c=0; c < NUM_FACES; c++) { |
| 77 | |
| 78 | v1 = face->vtxlist + face->v1; |
| 79 | v2 = face->vtxlist + face->v2; |
| 80 | v3 = face->vtxlist + face->v3; |
| 81 | v4 = face->vtxlist + face->v4; |
| 82 | |
| 83 | draw_quad(b, v1, v2, v3, v4, face->id); |
| 84 | |
| 85 | face++; |
| 86 | |
| 87 | } |
| 88 | |
| 89 | } |
Here's how I set everything up:
| 1 | int setup_navigation() |
| 2 | { |
| 3 | |
| 4 | int i = 0, x = 0, y = 0, i_a = 0; |
| 5 | |
| 6 | nav_cube.x = 0; nav_cube.y = 0; nav_cube.z = 150 << 16; |
| 7 | nav_cube.rx = 0; nav_cube.ry = 0; nav_cube.rz = 0; |
| 8 | nav_cube.dz = 0; nav_cube.drx = 0; nav_cube.dry = 0; nav_cube.drz = 0; |
| 9 | |
| 10 | mov_count = 0; mov_direction = 0; |
| 11 | |
| 12 | set_projection_viewport(0, 0, 320, 240); |
| 13 | |
| 14 | nav_texture[0] = load_bitmap("gfx/hud/tex0.bmp", NULL); |
| 15 | nav_texture[1] = load_bitmap("gfx/hud/tex1.bmp", NULL); |
| 16 | nav_texture[2] = load_bitmap("gfx/hud/tex2.bmp", NULL); |
| 17 | nav_texture[3] = load_bitmap("gfx/hud/tex3.bmp", NULL); |
| 18 | nav_texture[4] = load_bitmap("gfx/hud/tex4.bmp", NULL); |
| 19 | nav_texture[5] = load_bitmap("gfx/hud/tex5.bmp", NULL); |
| 20 | |
| 21 | plank = load_bitmap("gfx/hud/plank.bmp", NULL); |
| 22 | |
| 23 | if( nav_texture[0] == NULL || nav_texture[1] == NULL || nav_texture[2] == NULL || nav_texture[3] == NULL || |
| 24 | nav_texture[5] == NULL || plank == NULL ) return 1; |
| 25 | |
| 26 | return 0; |
| 27 | |
| 28 | } |
Any suggestions?
v1 = face->vtxlist + face->v1;
v2 = face->vtxlist + face->v2;
v3 = face->vtxlist + face->v3;
v4 = face->vtxlist + face->v4;
The only suggestion I have is to add some logging before those statements and make sure you're getting what you expect for face->vtxlist.
The crashing numbers include 320 and 120. Do those particular values occur somewhere else? Just a guess... a wild pointer is stuffing them everywhere
EDIT: Looks like the navigation code is fine. If I skip its execution entirely, the game will still crash at random points. Looks like it's a rogue pointer, or something equally horrible!
EDIT 2: Scratch that. Actually, with the navigation code entirely commented out, I have no crash problems. It's in there, somewhere.
Full header:
Full source:
Would you mind attaching the source to the entire project? Im willing to debug it but I dont want to hack together the source from your code pastes.