[quad3d] Crash!
ngiacomelli

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 
7typedef struct VTX
8{
9 fixed x, y, z;
10} VTX;
11 
12typedef struct QUAD
13{
14 VTX *vtxlist;
15 int id;
16 int v1, v2, v3, v4;
17} QUAD;
18 
19typedef struct SHAPE
20{
21 fixed x, y, z;
22 fixed rx, ry, rz;
23 fixed dz;
24 fixed drx, dry, drz;
25} SHAPE;
26 
27VTX 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 
39QUAD 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 
49SHAPE nav_cube;
50VTX output_points[NUM_VERTICES];
51QUAD output_faces[NUM_FACES];
52 
53int mov_count, mov_direction;
54 
55BITMAP *nav_texture[6], *plank;
56char keybuf[KEY_MAX];
57 
58#endif

Here's the code that renders and translates the cube:

1void 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 
28void 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 
51int 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 
67void 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:

1int 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?

kdevil

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.

Arthur Kalliokoski

The crashing numbers include 320 and 120. Do those particular values occur somewhere else? Just a guess... a wild pointer is stuffing them everywhere

ngiacomelli

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:

#SelectExpand
1#ifndef nav3d 2#define nav3d 3 4#define NUM_VERTICES 8 5#define NUM_FACES 6 6 7typedef struct VTX 8{ 9 fixed x, y, z; 10} VTX; 11 12typedef struct QUAD 13{ 14 VTX *vtxlist; 15 int id; 16 int v1, v2, v3, v4; 17} QUAD; 18 19typedef struct SHAPE 20{ 21 fixed x, y, z; 22 fixed rx, ry, rz; 23 fixed dz; 24 fixed drx, dry, drz; 25} SHAPE; 26 27VTX 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 39QUAD 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 49SHAPE nav_cube; 50VTX output_points[NUM_VERTICES]; 51QUAD output_faces[NUM_FACES]; 52 53int mov_count, mov_direction; 54 55BITMAP *nav_texture[6]; 56BITMAP *plank; 57char keybuf[KEY_MAX]; 58 59#endif

Full source:

#SelectExpand
1#include <allegro.h> 2#include "application.h" 3#include "canvas.h" 4#include "object.h" 5#include "nav3d.h" 6 7void draw_quad(BITMAP *b, VTX *v1, VTX *v2, VTX *v3, VTX *v4, int face); 8 9int setup_navigation() 10{ 11 12 int i = 0, x = 0, y = 0, i_a = 0; 13 14 nav_cube.x = 0; nav_cube.y = 0; nav_cube.z = 150 << 16; 15 nav_cube.rx = 0; nav_cube.ry = 0; nav_cube.rz = 0; 16 nav_cube.dz = 0; nav_cube.drx = 0; nav_cube.dry = 0; nav_cube.drz = 0; 17 18 mov_count = 0; mov_direction = 0; 19 20 set_projection_viewport(0, 0, 320, 240); 21 22 nav_texture[0] = load_bitmap("gfx/hud/tex0.bmp", NULL); 23 nav_texture[1] = load_bitmap("gfx/hud/tex1.bmp", NULL); 24 nav_texture[2] = load_bitmap("gfx/hud/tex2.bmp", NULL); 25 nav_texture[3] = load_bitmap("gfx/hud/tex3.bmp", NULL); 26 nav_texture[4] = load_bitmap("gfx/hud/tex4.bmp", NULL); 27 nav_texture[5] = load_bitmap("gfx/hud/tex5.bmp", NULL); 28 29 plank = load_bitmap("gfx/hud/plank.bmp", NULL); 30 31 if( nav_texture[0] == NULL || nav_texture[1] == NULL || nav_texture[2] == NULL || nav_texture[3] == NULL || 32 nav_texture[5] == NULL || plank == NULL ) return 1; 33 34 return 0; 35 36} 37 38void update_navigation(void) 39{ 40 41 nav_cube.z += nav_cube.dz; 42 43 if ((nav_cube.z > itofix(1024)) || (nav_cube.z < itofix(192))) nav_cube.dz = -nav_cube.dz; 44 45 nav_cube.rx += nav_cube.drx; 46 nav_cube.ry += nav_cube.dry; 47 nav_cube.rz += nav_cube.drz; 48 49} 50 51void translate_shapes(void) 52{ 53 54 int c, d; 55 MATRIX matrix; 56 VTX *outpoint = output_points; 57 QUAD *outface = output_faces; 58 59 get_transformation_matrix(&matrix, itofix(1), nav_cube.rx, nav_cube.ry, nav_cube.rz, nav_cube.x, nav_cube.y, nav_cube.z); 60 61 for (d = 0; d < NUM_VERTICES; d++) { 62 apply_matrix(&matrix, points[d].x, points[d].y, points[d].z, 63 &outpoint[d].x, &outpoint[d].y, &outpoint[d].z); 64 persp_project(outpoint[d].x, outpoint[d].y, outpoint[d].z, 65 &outpoint[d].x, &outpoint[d].y); 66 } 67 68 for (d=0; d<NUM_FACES; d++) { 69 outface[d] = faces[d]; 70 outface[d].vtxlist = outpoint; 71 } 72 73 outpoint += NUM_VERTICES; 74 outface += NUM_FACES; 75 76} 77 78void draw_quad(BITMAP *b, VTX *v1, VTX *v2, VTX *v3, VTX *v4, int face) 79{ 80 81 V3D vtx1 = { 0, 0, 0, 0, 0, 0 }; 82 V3D vtx2 = { 0, 0, 0, 32<<16, 0, 0 }; 83 V3D vtx3 = { 0, 0, 0, 32<<16, 32<<16, 0 }; 84 V3D vtx4 = { 0, 0, 0, 0, 32<<16, 0 }; 85 86 vtx1.x = v1->x; vtx1.y = v1->y; vtx1.z = v1->z; 87 vtx2.x = v2->x; vtx2.y = v2->y; vtx2.z = v2->z; 88 vtx3.x = v3->x; vtx3.y = v3->y; vtx3.z = v3->z; 89 vtx4.x = v4->x; vtx4.y = v4->y; vtx4.z = v4->z; 90 91 log_write(" vtx1: %i %i %i", vtx1.x, vtx1.y, vtx1.z ); 92 log_write(" vtx2: %i %i %i", vtx2.x, vtx2.y, vtx2.z ); 93 log_write(" vtx3: %i %i %i", vtx3.x, vtx3.y, vtx3.z ); 94 log_write(" vtx4: %i %i %i", vtx4.x, vtx4.y, vtx4.z ); 95 96 quad3d(b, POLYTYPE_PTEX, nav_texture[face], &vtx1, &vtx2, &vtx3, &vtx4); // Crashes here! 97 98} 99 100int quad_cmp(const void *e1, const void *e2) 101{ 102 103 QUAD *q1 = (QUAD *)e1; 104 QUAD *q2 = (QUAD *)e2; 105 106 fixed d1 = q1->vtxlist[q1->v1].z + q1->vtxlist[q1->v2].z + 107 q1->vtxlist[q1->v3].z + q1->vtxlist[q1->v4].z; 108 109 fixed d2 = q2->vtxlist[q2->v1].z + q2->vtxlist[q2->v2].z + 110 q2->vtxlist[q2->v3].z + q2->vtxlist[q2->v4].z; 111 112 return d2 - d1; 113 114} 115 116void draw_shapes(BITMAP *b) 117{ 118 119 int c; 120 QUAD *face = output_faces; 121 VTX *v1, *v2, *v3, *v4; 122 qsort(output_faces, NUM_FACES, sizeof(QUAD), quad_cmp); 123 124 for (c=0; c < NUM_FACES; c++) { 125 126 v1 = face->vtxlist + face->v1; 127 v2 = face->vtxlist + face->v2; 128 v3 = face->vtxlist + face->v3; 129 v4 = face->vtxlist + face->v4; 130 131 draw_quad(b, v1, v2, v3, v4, face->id); 132 133 face++; 134 135 } 136 137} 138 139int get_look_face() 140{ 141 142 int c; 143 144 QUAD *face = output_faces; 145 146 qsort(output_faces, NUM_FACES, sizeof(QUAD), quad_cmp); 147 148 for( c = 0; c < NUM_FACES; c++ ) { 149 150 if( c == (NUM_FACES-1) ) return face->id; 151 face++; 152 153 } 154 155 return -1; 156 157} 158 159void menu_logic() { 160 161 update_navigation(); 162 translate_shapes(); 163 164 if( mov_count > 0 ) { 165 166 mov_count += 2; 167 168 switch( mov_direction ) { 169 170 case 0: 171 nav_cube.rx += itofix(2); 172 break; 173 case 1: 174 nav_cube.rx -= itofix(2); 175 break; 176 case 2: 177 nav_cube.ry -= itofix(2); 178 break; 179 case 3: 180 nav_cube.ry += itofix(2); 181 break; 182 183 } 184 185 if( mov_count > 64 ) { 186 mov_count = 0; 187 } 188 189 } 190 191} 192 193void menu_input() { 194 195 if( key[KEY_D] && !keybuf[KEY_D] && mov_count <= 0 ) { 196 197 mov_count = 1; mov_direction = 3; 198 199 } 200 201 if( key[KEY_A] && !keybuf[KEY_A] && mov_count <= 0 ) { 202 203 mov_count = 1; mov_direction = 2; 204 205 } 206 207 if( key[KEY_S] && !keybuf[KEY_S] && mov_count <= 0 ) { 208 209 mov_count = 1; mov_direction = 0; 210 211 } 212 213 if( key[KEY_W] && !keybuf[KEY_W] && mov_count <= 0 ) { 214 215 mov_count = 1; mov_direction = 1; 216 217 } 218 219 if( key[KEY_SPACE] && !keybuf[KEY_SPACE] && mov_count <= 0 ) { 220 221 switch( get_look_face() ) { 222 223 case 0: 224 application_set_state(APP_GAME); 225 break; 226 case 1: 227 application_set_state(APP_TERMINATING); 228 break; 229 230 } 231 232 } 233 234 memcpy((void*)keybuf,(void*)key,sizeof(keybuf)); 235 236} 237 238void render_menu() 239{ 240 241 int x = 0, y = 0; 242 243 clear_to_color( buffer, makecol( 0, 0, 0 ) ); 244 245 draw_shapes( buffer ); 246 draw_sprite( buffer, plank, 110, 168 ); 247 248 if( mov_count <= 0 ) { 249 250 switch( get_look_face() ) { 251 252 case 0: 253 textprintf_centre_ex(buffer, small_n, 160, 181, makecol(0, 0, 0), -1, "NEW GAME"); 254 textprintf_centre_ex(buffer, small_n, 160, 180, makecol(255, 255, 255), -1, "NEW GAME"); 255 break; 256 case 1: 257 textprintf_centre_ex(buffer, small_n, 160, 181, makecol(0, 0, 0), -1, "EXIT"); 258 textprintf_centre_ex(buffer, small_n, 160, 180, makecol(255, 255, 255), -1, "EXIT"); 259 break; 260 case 2: 261 textprintf_centre_ex(buffer, small_n, 160, 181, makecol(0, 0, 0), -1, "CREDITS"); 262 textprintf_centre_ex(buffer, small_n, 160, 180, makecol(255, 255, 255), -1, "CREDITS"); 263 break; 264 case 3: 265 textprintf_centre_ex(buffer, small_n, 160, 181, makecol(0, 0, 0), -1, "OPTIONS"); 266 textprintf_centre_ex(buffer, small_n, 160, 180, makecol(255, 255, 255), -1, "OPTIONS"); 267 break; 268 case 4: 269 textprintf_centre_ex(buffer, small_n, 160, 181, makecol(0, 0, 0), -1, "LOAD GAME"); 270 textprintf_centre_ex(buffer, small_n, 160, 180, makecol(255, 255, 255), -1, "LOAD GAME"); 271 break; 272 case 5: 273 textprintf_centre_ex(buffer, small_n, 160, 181, makecol(0, 0, 0), -1, "SAVE GAME"); 274 textprintf_centre_ex(buffer, small_n, 160, 180, makecol(255, 255, 255), -1, "SAVE GAME"); 275 break; 276 277 } 278 279 } 280 281 stretch_blit(buffer, screen, 0, 0, 320, 240, 0, 0, 640, 480); 282 283}

kazzmir

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.

Thread #589610. Printed from Allegro.cc