diff --git a/include/QF/model.h b/include/QF/model.h index f60664fab..ac08414f5 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -230,6 +230,7 @@ typedef struct hull_s { vec3_t clip_mins; vec3_t clip_maxs; struct nodeleaf_s *nodeleafs; + int depth; ///< maximum depth of the tree } hull_t; // SPRITE MODELS ============================================================== @@ -393,6 +394,7 @@ typedef struct model_s { int numnodes; mnode_t *nodes; + int depth; ///< maximum depth of the tree int numtexinfo; mtexinfo_t *texinfo; @@ -449,6 +451,7 @@ void *Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, void *Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, int extra); +void Mod_FindClipDepth (hull_t *hull); void Mod_LoadBrushModel (model_t *mod, void *buffer); void Mod_FloodFillSkin (byte * skin, int skinwidth, int skinheight); diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 3b0bffbf4..7b7d0f8d9 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -880,6 +880,48 @@ do_checksums (const bsp_t *bsp, void *_mod) } } +static void +recurse_draw_tree (mnode_t *node, int depth) +{ + if (!node || node->contents < 0) { + if (depth > loadmodel->depth) + loadmodel->depth = depth; + return; + } + recurse_draw_tree (node->children[0], depth + 1); + recurse_draw_tree (node->children[1], depth + 1); +} + +static void +Mod_FindDrawDepth (void) +{ + loadmodel->depth = 0; + recurse_draw_tree (loadmodel->nodes, 1); +} + +static void +recurse_clip_tree (hull_t *hull, int num, int depth) +{ + mclipnode_t *node; + + if (num < 0) { + if (depth > hull->depth) + hull->depth = depth; + return; + } + node = hull->clipnodes + num; + recurse_clip_tree (hull, node->children[0], depth + 1); + recurse_clip_tree (hull, node->children[1], depth + 1); +} + +void +Mod_FindClipDepth (hull_t *hull) +{ + hull->depth = 0; + if (hull->clipnodes) // no hull 3? + recurse_clip_tree (hull, hull->firstclipnode, 1); +} + void Mod_LoadBrushModel (model_t *mod, void *buffer) { @@ -913,6 +955,10 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) Mod_MakeHull0 (); + Mod_FindDrawDepth (); + for (i = 0; i < MAX_MAP_HULLS; i++) + Mod_FindClipDepth (&mod->hulls[i]); + mod->numframes = 2; // regular and alternate animation // set up the submodels (FIXME: this is confusing) diff --git a/libs/models/test/testclip.c b/libs/models/test/testclip.c index ac6bad79d..df7649ae5 100644 --- a/libs/models/test/testclip.c +++ b/libs/models/test/testclip.c @@ -255,6 +255,8 @@ run_test (test_t *test) static int output = 0; portlist_t *portal_list = 0; + if (!test->hull->depth) + Mod_FindClipDepth (test->hull); if (!test->hull->nodeleafs) { hull_t *hull = test->hull; int i, j; diff --git a/libs/models/trace.c b/libs/models/trace.c index 73a50de2f..b852bbbc6 100644 --- a/libs/models/trace.c +++ b/libs/models/trace.c @@ -783,12 +783,16 @@ MOD_TraceLine (hull_t *hull, int num, vec3_t start, end, dist; int side; tracestack_t *tstack; - tracestack_t tracestack[256]; + tracestack_t *tracestack; mclipnode_t *node; plane_t *plane; clipleaf_t *leaf; trace_state_t trace_state; + if (!hull->depth) + Sys_Error ("hull depth not set"); + // +2 for paranoia + tracestack = alloca ((hull->depth + 2) * sizeof (tracestack_t)); VectorCopy (start_point, start); VectorCopy (end_point, end); VectorSubtract (end, start, trace_state.dist); diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index b73203b32..87ba5f3dd 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -652,16 +652,21 @@ test_node (mnode_t *node) } static void -R_VisitWorldNodes (mnode_t *node) +R_VisitWorldNodes (model_t *model) { -#define NODE_STACK 1024 - struct { + typedef struct { mnode_t *node; int side; - } *node_ptr, node_stack[NODE_STACK]; + } rstack_t; + rstack_t *node_ptr; + rstack_t *node_stack; + mnode_t *node; mnode_t *front; int side; + node = model->nodes; + // +2 for paranoia + node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { @@ -669,8 +674,6 @@ R_VisitWorldNodes (mnode_t *node) side = get_side (node); front = node->children[side]; if (test_node (front)) { - if (node_ptr - node_stack == NODE_STACK) - Sys_Error ("node_stack overflow"); node_ptr->node = node; node_ptr->side = side; node_ptr++; @@ -716,7 +719,7 @@ gl_R_DrawWorld (void) gl_R_DrawSky (); } - R_VisitWorldNodes (r_worldentity.model->nodes); + R_VisitWorldNodes (r_worldentity.model); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index a5c11f9af..b01d4c47e 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -743,16 +743,21 @@ test_node (mnode_t *node) } static void -R_VisitWorldNodes (mnode_t *node) +R_VisitWorldNodes (model_t *model) { -#define NODE_STACK 1024 - struct { + typedef struct { mnode_t *node; int side; - } *node_ptr, node_stack[NODE_STACK]; + } rstack_t; + rstack_t *node_ptr; + rstack_t *node_stack; + mnode_t *node; mnode_t *front; int side; + node = model->nodes; + // +2 for paranoia + node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { @@ -760,8 +765,6 @@ R_VisitWorldNodes (mnode_t *node) side = get_side (node); front = node->children[side]; if (test_node (front)) { - if (node_ptr - node_stack == NODE_STACK) - Sys_Error ("node_stack overflow"); node_ptr->node = node; node_ptr->side = side; node_ptr++; @@ -1097,7 +1100,7 @@ glsl_R_DrawWorld (void) currententity = &worldent; - R_VisitWorldNodes (worldent.model->nodes); + R_VisitWorldNodes (worldent.model); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) {