debug_box.patch (9844B)
1 diff --git a/src/game/area.c b/src/game/area.c 2 index af9d0156..c68a7f6e 100644 3 --- a/src/game/area.c 4 +++ b/src/game/area.c 5 @@ -22,6 +22,7 @@ 6 #include "save_file.h" 7 #include "level_table.h" 8 #include "dialog_ids.h" 9 +#include "debug_box.h" 10 11 struct SpawnInfo gPlayerSpawnInfos[1]; 12 struct GraphNode *D_8033A160[0x100]; 13 @@ -363,6 +364,8 @@ void render_game(void) { 14 if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) { 15 geo_process_root(gCurrentArea->unk04, D_8032CE74, D_8032CE78, gFBSetColor); 16 17 + render_debug_boxes(); 18 + 19 gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&D_8032CF00)); 20 21 gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, 22 diff --git a/src/game/debug_box.c b/src/game/debug_box.c 23 new file mode 100644 24 index 00000000..1ffe0288 25 --- /dev/null 26 +++ b/src/game/debug_box.c 27 @@ -0,0 +1,281 @@ 28 +#include <ultra64.h> 29 + 30 +#include "sm64.h" 31 +#include "game/game_init.h" 32 +#include "game/geo_misc.h" 33 +#include "engine/math_util.h" 34 + 35 +#include "debug_box.h" 36 + 37 +/** 38 + * @file debug_box.c 39 + * Draws 3D boxes for debugging purposes. 40 + * 41 + * How to use: 42 + * 43 + * In render_game() in area.c, add a call to render_debug_boxes(): 44 + * 45 + * void render_game(void) { 46 + * if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) { 47 + * geo_process_root(...); 48 + * 49 + * render_debug_boxes(); // add here 50 + * 51 + * gSPViewport(...); 52 + * gDPSetScissor(...); 53 + * //... 54 + * 55 + * Now just call debug_box() whenever you want to draw one! 56 + * 57 + * debug_box by default takes two arguments: a center and bounds vec3f. 58 + * This will draw a box starting from the point (center - bounds) to (center + bounds). 59 + * 60 + * Use debug_box_rot to draw a box rotated in the xz-plane. 61 + * 62 + * If you want to draw a box by specifying min and max points, use debug_box_pos() instead. 63 + */ 64 + 65 +/** 66 + * Internal struct containing box info 67 + */ 68 +struct DebugBox { 69 + u32 color; 70 + Vec3s center; 71 + Vec3s bounds; 72 + s16 yaw; 73 +}; 74 + 75 +struct DebugBox sBoxes[MAX_DEBUG_BOXES]; 76 +s16 sNumBoxes = 0; 77 + 78 +extern Mat4 gMatStack[32]; //XXX: Hack 79 + 80 +/** 81 + * The debug boxes' default transparency 82 + */ 83 +#define DBG_BOX_ALPHA 0x7F 84 +/** 85 + * The debug boxes' default color. sCurBoxColor is reset to this every frame. 86 + */ 87 +#define DBG_BOX_DEF_COLOR 0xFF0000 88 + 89 +/** 90 + * The color that new boxes will be drawn with. 91 + */ 92 +u32 sCurBoxColor = DBG_BOX_ALPHA << 24 | DBG_BOX_DEF_COLOR; 93 + 94 +/** 95 + * The allocated size of a rotated box's dl 96 + */ 97 +#define DBG_BOX_ROT_DLSIZE ((s32)(6 * sizeof(Gfx) + 8 * sizeof(Vtx))) 98 +/** 99 + * The allocated size of a normal box's dl 100 + */ 101 +#define DBG_BOX_DLSIZE ((s32)(2 * sizeof(Gfx) + 8 * sizeof(Vtx))) 102 + 103 +/** 104 + * Sets up the RCP for drawing the boxes 105 + */ 106 +static const Gfx dl_debug_box_begin[] = { 107 + gsDPPipeSync(), 108 +#if DBG_BOX_ALPHA < 0xFF 109 + gsDPSetRenderMode(G_RM_ZB_XLU_SURF, G_RM_NOOP2), 110 +#else 111 + gsDPSetRenderMode(G_RM_ZB_OPA_SURF, G_RM_NOOP2), 112 +#endif 113 + gsSPClearGeometryMode(G_LIGHTING | G_CULL_BACK), 114 + gsSPSetGeometryMode(G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH), 115 + gsSPTexture(0, 0, 0, 0, G_OFF), 116 + gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), 117 + gsSPEndDisplayList(), 118 +}; 119 + 120 +/** 121 + * Actually draws the box 122 + */ 123 +static const Gfx dl_debug_draw_box[] = { 124 + gsSP2Triangles(5, 4, 6, 0x0, 5, 6, 7, 0x0), // front 125 + gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0), // back 126 + 127 + gsSP2Triangles(4, 0, 2, 0x0, 2, 6, 4, 0x0), // left 128 + gsSP2Triangles(1, 5, 3, 0x0, 3, 5, 7, 0x0), // right 129 + 130 + gsSP2Triangles(1, 0, 4, 0x0, 1, 4, 5, 0x0), // top 131 + gsSP2Triangles(2, 3, 6, 0x0, 6, 3, 7, 0x0), // bottom 132 + 133 + gsSPEndDisplayList(), 134 +}; 135 + 136 +/** 137 + * Adds a box to the list to be rendered this frame. 138 + * 139 + * If there are already MAX_DEBUG_BOXES boxes, does nothing. 140 + */ 141 +static void append_debug_box(Vec3f center, Vec3f bounds, s16 yaw) 142 +{ 143 + if (sNumBoxes >= MAX_DEBUG_BOXES) { 144 + return; 145 + } 146 + 147 + vec3f_to_vec3s(sBoxes[sNumBoxes].center, center); 148 + vec3f_to_vec3s(sBoxes[sNumBoxes].bounds, bounds); 149 + 150 + sBoxes[sNumBoxes].yaw = yaw; 151 + sBoxes[sNumBoxes].color = sCurBoxColor; 152 + 153 + ++sNumBoxes; 154 +} 155 + 156 +/** 157 + * Draw new boxes with the given color. 158 + * Color format is 32-bit ARGB. 159 + * If the alpha component is zero, DBG_BOX_ALPHA (0x7f) will be used instead. 160 + * Ex: 0xFF0000 becomes 0x7FFF0000 161 + */ 162 +void debug_box_color(u32 color) 163 +{ 164 + if ((color >> 24) == 0) color |= (DBG_BOX_ALPHA << 24); 165 + sCurBoxColor = color; 166 +} 167 + 168 +/** 169 + * Draws a debug box from (center - bounds) to (center + bounds) 170 + * To draw a rotated box, use debug_box_rot() 171 + * 172 + * @see debug_box_rot() 173 + */ 174 +void debug_box(Vec3f center, Vec3f bounds) 175 +{ 176 + append_debug_box(center, bounds, 0); 177 +} 178 + 179 +/** 180 + * Draws a debug box from (center - bounds) to (center + bounds), rotating it by `yaw` 181 + */ 182 +void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw) 183 +{ 184 + append_debug_box(center, bounds, yaw); 185 +} 186 + 187 +/** 188 + * Draws a debug box from pMin to pMax 189 + * To draw a rotated box this way, use debug_box_pos_rot() 190 + * 191 + * @see debug_box_pos_rot() 192 + */ 193 +void debug_box_pos(Vec3f pMin, Vec3f pMax) 194 +{ 195 + debug_box_pos_rot(pMin, pMax, 0); 196 +} 197 + 198 +/** 199 + * Draws a debug box from pMin to pMax, rotating it in the xz-plane by `yaw` 200 + */ 201 +void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw) 202 +{ 203 + Vec3f center, bounds; 204 + 205 + bounds[0] = (pMax[0] - pMin[0]) / 2.0f; 206 + bounds[1] = (pMax[1] - pMin[1]) / 2.0f; 207 + bounds[2] = (pMax[2] - pMin[2]) / 2.0f; 208 + 209 + center[0] = pMin[0] + bounds[0]; 210 + center[1] = pMin[1] + bounds[1]; 211 + center[2] = pMin[2] + bounds[2]; 212 + 213 + append_debug_box(center, bounds, yaw); 214 +} 215 + 216 +static void render_box(int index) 217 +{ 218 + Vtx *verts; 219 + Mtx *translate; 220 + Mtx *rotate; 221 + Mtx *translateback; 222 + struct DebugBox *box = &sBoxes[index]; 223 + u32 color = box->color; 224 + 225 + s32 x0 = box->center[0], 226 + y0 = box->center[1], 227 + z0 = box->center[2]; 228 + 229 + s32 xb = box->bounds[0], 230 + yb = box->bounds[1], 231 + zb = box->bounds[2]; 232 + 233 + if (box->yaw != 0 && (Gfx*)gGfxPoolEnd - gDisplayListHead < DBG_BOX_ROT_DLSIZE) 234 + return; 235 + else if ((Gfx*)gGfxPoolEnd - gDisplayListHead < DBG_BOX_DLSIZE) 236 + return; 237 + 238 + verts = alloc_display_list(8 * sizeof(Vtx)); 239 + 240 + if (verts != NULL) { 241 + if (box->yaw != 0) { 242 + // Translate to the origin, rotate, then translate back, effectively rotating the box about 243 + // its center 244 + translate = alloc_display_list(sizeof(Mtx)); 245 + rotate = alloc_display_list(sizeof(Mtx)); 246 + translateback = alloc_display_list(sizeof(Mtx)); 247 + 248 + guTranslate(translate, box->center[0], box->center[1], box->center[2]); 249 + guRotate(rotate, box->yaw / (float)0x10000 * 360.0f, 0, 1.0f, 0); 250 + guTranslate(translateback, -box->center[0], -box->center[1], -box->center[2]); 251 + 252 + gSPMatrix(gDisplayListHead++, translate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); 253 + gSPMatrix(gDisplayListHead++, rotate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); 254 + gSPMatrix(gDisplayListHead++, translateback, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); 255 + } 256 + 257 +#define DBG_BOX_COL /**/ (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, (color >> 24) & 0xff 258 +#define DBG_BOX_VTX(i, x, y, z) make_vertex(verts, i, x, y, z, 0, 0, DBG_BOX_COL) 259 + DBG_BOX_VTX(0, x0 - xb, y0 + yb, z0 - zb); 260 + DBG_BOX_VTX(1, x0 + xb, y0 + yb, z0 - zb); 261 + DBG_BOX_VTX(2, x0 - xb, y0 - yb, z0 - zb); 262 + DBG_BOX_VTX(3, x0 + xb, y0 - yb, z0 - zb); 263 + DBG_BOX_VTX(4, x0 - xb, y0 + yb, z0 + zb); 264 + DBG_BOX_VTX(5, x0 + xb, y0 + yb, z0 + zb); 265 + DBG_BOX_VTX(6, x0 - xb, y0 - yb, z0 + zb); 266 + DBG_BOX_VTX(7, x0 + xb, y0 - yb, z0 + zb); 267 +#undef DBG_BOX_VTX 268 + 269 + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 8, 0); 270 + 271 + gSPDisplayList(gDisplayListHead++, dl_debug_draw_box); 272 + 273 + if (box->yaw != 0) { 274 + gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW); 275 + } 276 + } 277 +} 278 + 279 +void render_debug_boxes(void) 280 +{ 281 + s32 i; 282 + Mtx *mtx; 283 + 284 + debug_box_color(DBG_BOX_DEF_COLOR); 285 + 286 + if (sNumBoxes == 0) { 287 + return; 288 + } 289 + 290 + mtx = alloc_display_list(sizeof(Mtx)); 291 + // Don't draw if there isn't space for the configuration + at least one box 292 + if (mtx == NULL || ((Gfx*)gGfxPoolEnd - gDisplayListHead) <= (s32)(2 * sizeof(Gfx)) + DBG_BOX_DLSIZE) { 293 + sNumBoxes = 0; 294 + return; 295 + } 296 + 297 + //XXX: This is hacky. Ths camera's look-at matrix is stored in gMatStack[1], so this is a simple way 298 + // of using it without reconstructing the matrix. 299 + mtxf_to_mtx(mtx, gMatStack[1]); 300 + gSPMatrix(gDisplayListHead++, mtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); 301 + gSPDisplayList(gDisplayListHead++, dl_debug_box_begin); 302 + 303 + for (i = 0; i < sNumBoxes; ++i) { 304 + render_box(i); 305 + } 306 + 307 + sNumBoxes = 0; 308 +} 309 diff --git a/src/game/debug_box.h b/src/game/debug_box.h 310 new file mode 100644 311 index 00000000..540c85e4 312 --- /dev/null 313 +++ b/src/game/debug_box.h 314 @@ -0,0 +1,26 @@ 315 +#ifndef DEBUG_BOX_H 316 +#define DEBUG_BOX_H 317 + 318 +/** 319 + * @file debug_box.h 320 + * Draws debug boxes, see debug_box.c for details 321 + */ 322 + 323 +#include "types.h" 324 + 325 +/** 326 + * The max amount of debug boxes before debug_box() just returns. 327 + * You can set this to something higher, but you might run out of space in the gfx pool. 328 + */ 329 +#define MAX_DEBUG_BOXES 512 330 + 331 +void debug_box_color(u32 color); 332 +void debug_box(Vec3f center, Vec3f bounds); 333 +void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw); 334 + 335 +void debug_box_pos(Vec3f pMin, Vec3f pMax); 336 +void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw); 337 + 338 +void render_debug_boxes(void); 339 + 340 +#endif /* DEBUG_BOX_H */