sm64/enhancements/debug_box.patch
2020-02-03 00:51:26 -05:00

303 lines
8.5 KiB
Diff

diff --git a/src/game/area.c b/src/game/area.c
index 240605d8..88c1a314 100644
--- a/src/game/area.c
+++ b/src/game/area.c
@@ -19,6 +19,7 @@
#include "level_update.h"
#include "engine/geo_layout.h"
#include "save_file.h"
+#include "debug_box.h"
struct SpawnInfo gPlayerSpawnInfos[1];
struct GraphNode *D_8033A160[0x100];
@@ -352,6 +353,8 @@ void render_game(void) {
if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) {
geo_process_root(gCurrentArea->unk04, D_8032CE74, D_8032CE78, gFBSetColor);
+ render_debug_boxes();
+
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&D_8032CF00));
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH,
diff --git a/src/game/debug_box.c b/src/game/debug_box.c
new file mode 100644
index 00000000..0ee87ec7
--- /dev/null
+++ b/src/game/debug_box.c
@@ -0,0 +1,244 @@
+#include <ultra64.h>
+
+#include "sm64.h"
+#include "game/game.h"
+#include "game/geo_misc.h"
+#include "engine/math_util.h"
+
+#include "debug_box.h"
+
+/**
+ * @file debug_box.c
+ * Draws 3D boxes for debugging purposes.
+ *
+ * How to use:
+ *
+ * In render_game() in area.c, add a call to render_debug_boxes():
+ *
+ * void render_game(void) {
+ * if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) {
+ * geo_process_root(...);
+ *
+ * render_debug_boxes(); // add here
+ *
+ * gSPViewport(...);
+ * gDPSetScissor(...);
+ * //...
+ *
+ * Now just call debug_box() whenever you want to draw one!
+ *
+ * debug_box by default takes two arguments: a center and bounds vec3f.
+ * This will draw a box starting from the point (center - bounds) to (center + bounds).
+ *
+ * Use debug_box_rot to draw a box rotated in the xz-plane.
+ *
+ * If you want to draw a box by specifying min and max points, use debug_box_pos() instead.
+ */
+
+/**
+ * Internal struct containing box info
+ */
+struct DebugBox {
+ Vec3s center;
+ Vec3s bounds;
+ s16 yaw;
+};
+
+struct DebugBox *sBoxes[MAX_DEBUG_BOXES];
+s16 sNumBoxes = 0;
+
+extern Mat4 gMatStack[32]; //XXX: Hack
+
+/**
+ * The debug boxes' transparency
+ */
+#define DBG_BOX_ALPHA 0x7F
+/**
+ * The debug boxes' color
+ */
+#define DBG_BOX_COL 0xFF, 0x00, 0x00, DBG_BOX_ALPHA
+
+/**
+ * Sets up the RCP for drawing the boxes
+ */
+static const Gfx dl_debug_box_begin[] = {
+ gsDPPipeSync(),
+#if DBG_BOX_ALPHA < 0xFF
+ gsDPSetRenderMode(G_RM_ZB_XLU_SURF, G_RM_NOOP2),
+#else
+ gsDPSetRenderMode(G_RM_ZB_OPA_SURF, G_RM_NOOP2),
+#endif
+ gsSPClearGeometryMode(G_LIGHTING | G_CULL_BACK),
+ gsSPSetGeometryMode(G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH),
+ gsSPTexture(0, 0, 0, 0, G_OFF),
+ gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
+ gsSPEndDisplayList(),
+};
+
+/**
+ * Actually draws the box
+ */
+static const Gfx dl_debug_draw_box[] = {
+ gsSP2Triangles( 0, 1, 2, 0x0, 2, 1, 3, 0x0),
+ gsSP2Triangles( 2, 3, 6, 0x0, 6, 3, 7, 0x0),
+
+ gsSP2Triangles( 4, 0, 2, 0x0, 2, 6, 4, 0x0),
+ gsSP2Triangles( 1, 5, 3, 0x0, 3, 5, 7, 0x0),
+
+ gsSP2Triangles( 1, 0, 4, 0x0, 1, 4, 5, 0x0),
+ gsSP2Triangles( 5, 4, 6, 0x0, 5, 6, 7, 0x0),
+
+ gsSPEndDisplayList(),
+};
+
+/**
+ * Adds a box to the list to be rendered this frame.
+ *
+ * If there are already MAX_DEBUG_BOXES boxes, does nothing.
+ */
+static void append_debug_box(Vec3f center, Vec3f bounds, s16 yaw)
+{
+ if (sNumBoxes >= MAX_DEBUG_BOXES ||
+ (sBoxes[sNumBoxes] = mem_pool_alloc(gEffectsMemoryPool, sizeof(struct DebugBox))) == NULL) {
+ return;
+ }
+
+ vec3f_to_vec3s(sBoxes[sNumBoxes]->center, center);
+ vec3f_to_vec3s(sBoxes[sNumBoxes]->bounds, bounds);
+
+ sBoxes[sNumBoxes]->yaw = yaw;
+
+ ++sNumBoxes;
+}
+
+/**
+ * Draws a debug box from (center - bounds) to (center + bounds)
+ * To draw a rotated box, use debug_box_rot()
+ *
+ * @see debug_box_rot()
+ */
+void debug_box(Vec3f center, Vec3f bounds)
+{
+ append_debug_box(center, bounds, 0);
+}
+
+/**
+ * Draws a debug box from (center - bounds) to (center + bounds), rotating it by `yaw`
+ */
+void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw)
+{
+ append_debug_box(center, bounds, yaw);
+}
+
+/**
+ * Draws a debug box from pMin to pMax
+ * To draw a rotated box this way, use debug_box_pos_rot()
+ *
+ * @see debug_box_pos_rot()
+ */
+void debug_box_pos(Vec3f pMin, Vec3f pMax)
+{
+ debug_box_pos_rot(pMin, pMax, 0);
+}
+
+/**
+ * Draws a debug box from pMin to pMax, rotating it in the xz-plane by `yaw`
+ */
+void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw)
+{
+ Vec3f center, bounds;
+
+ bounds[0] = pMax[0] - pMin[0] / 2.0f;
+ bounds[1] = pMax[1] - pMin[1] / 2.0f;
+ bounds[2] = pMax[2] - pMin[2] / 2.0f;
+
+ center[0] = pMin[0] + bounds[0];
+ center[1] = pMin[1] + bounds[1];
+ center[2] = pMin[2] + bounds[2];
+
+ append_debug_box(center, bounds, yaw);
+}
+
+static void render_box(struct DebugBox *box)
+{
+ Vtx *verts = alloc_display_list(8 * sizeof(Vtx));
+ Mtx *translate;
+ Mtx *rotate;
+ Mtx *translateback;
+ s32 x0 = box->center[0],
+ y0 = box->center[1],
+ z0 = box->center[2];
+
+ s32 xb = box->bounds[0],
+ yb = box->bounds[1],
+ zb = box->bounds[2];
+
+ if (verts != NULL) {
+ if (box->yaw != 0) {
+ // Translate to the origin, rotate, then translate back, effectively rotating the box about
+ // its center
+ translate = alloc_display_list(sizeof(Mtx));
+ rotate = alloc_display_list(sizeof(Mtx));
+ translateback = alloc_display_list(sizeof(Mtx));
+
+ guTranslate(translate, box->center[0], box->center[1], box->center[2]);
+ guRotate(rotate, box->yaw / (float)0x10000 * 360.0f, 0, 1.0f, 0);
+ guTranslate(translateback, -box->center[0], -box->center[1], -box->center[2]);
+
+ gSPMatrix(gDisplayListHead++, translate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
+ gSPMatrix(gDisplayListHead++, rotate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
+ gSPMatrix(gDisplayListHead++, translateback, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
+ }
+
+#define DBG_BOX_VTX(i, x, y, z) make_vertex(verts, i, x, y, z, 0, 0, DBG_BOX_COL)
+ DBG_BOX_VTX(0, x0 - xb, y0 + yb, z0 - zb);
+ DBG_BOX_VTX(1, x0 + xb, y0 + yb, z0 - zb);
+ DBG_BOX_VTX(2, x0 - xb, y0 - yb, z0 - zb);
+ DBG_BOX_VTX(3, x0 + xb, y0 - yb, z0 - zb);
+ DBG_BOX_VTX(4, x0 - xb, y0 + yb, z0 + zb);
+ DBG_BOX_VTX(5, x0 + xb, y0 + yb, z0 + zb);
+ DBG_BOX_VTX(6, x0 - xb, y0 - yb, z0 + zb);
+ DBG_BOX_VTX(7, x0 + xb, y0 - yb, z0 + zb);
+#undef DBG_BOX_VTX
+
+ gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 8, 0);
+
+ gSPDisplayList(gDisplayListHead++, dl_debug_draw_box);
+
+ if (box->yaw != 0) {
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
+ }
+ }
+}
+
+void render_debug_boxes(void)
+{
+ s32 i;
+ Mtx *mtx;
+
+ if (sNumBoxes == 0) {
+ return;
+ }
+
+ mtx = alloc_display_list(sizeof(Mtx));
+ if (mtx == NULL) {
+ for (i = 0; i < sNumBoxes; ++i) {
+ mem_pool_free(gEffectsMemoryPool, sBoxes[i]);
+ }
+ sNumBoxes = 0;
+ return;
+ }
+
+ //XXX: This is hacky. Ths camera's look-at matrix is stored in gMatStack[1], so this is a simple way
+ // of using it without reconstructing the matrix.
+ mtxf_to_mtx(mtx, gMatStack[1]);
+ gSPMatrix(gDisplayListHead++, mtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
+ gSPDisplayList(gDisplayListHead++, dl_debug_box_begin);
+
+ for (i = 0; i < sNumBoxes; ++i) {
+ render_box(sBoxes[i]);
+ mem_pool_free(gEffectsMemoryPool, sBoxes[i]);
+ }
+
+ sNumBoxes = 0;
+}
diff --git a/src/game/debug_box.h b/src/game/debug_box.h
new file mode 100644
index 00000000..cdb3dc9d
--- /dev/null
+++ b/src/game/debug_box.h
@@ -0,0 +1,25 @@
+#ifndef _DEBUG_DRAW_CUBE_H
+#define _DEBUG_DRAW_CUBE_H
+
+/**
+ * @file debug_box.h
+ * Draws debug boxes, see debug_box.inc.c for details
+ */
+
+#include "types.h"
+
+/**
+ * The max amount of debug boxes before debug_box() just returns.
+ * You can set this to something higher like 1000, but things like text will stop rendering.
+ */
+#define MAX_DEBUG_BOXES 100
+
+void debug_box(Vec3f center, Vec3f bounds);
+void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw);
+
+void debug_box_pos(Vec3f pMin, Vec3f pMax);
+void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw);
+
+void render_debug_boxes(void);
+
+#endif /* _DEBUG_DRAW_CUBE_H */