Add code to rebuild the bsp brushes.

Names and locations of declarations are still up in the air, but things
seem to be working assuming my test code is correct.
This commit is contained in:
Bill Currie 2011-11-15 12:57:08 +09:00
parent 853bf13d9e
commit d61cb25a44
5 changed files with 333 additions and 33 deletions

View file

@ -202,6 +202,7 @@ typedef struct hull_s {
int lastclipnode; int lastclipnode;
vec3_t clip_mins; vec3_t clip_mins;
vec3_t clip_maxs; vec3_t clip_maxs;
struct nodeleaf_s *nodeleafs;
} hull_t; } hull_t;
// SPRITE MODELS ============================================================== // SPRITE MODELS ==============================================================

View file

@ -118,4 +118,22 @@ hull_t *SV_HullForEntity (struct edict_s *ent, const vec3_t mins,
void MOD_TraceLine (hull_t *hull, int num, void MOD_TraceLine (hull_t *hull, int num,
const vec3_t start, const vec3_t end, trace_t *trace); const vec3_t start, const vec3_t end, trace_t *trace);
typedef struct clipport_s {
int planenum;
struct clipport_s *next[2]; ///< front, back
struct clipleaf_s *leafs[2]; ///< front, back
struct winding_s *winding;
} clipport_t;
typedef struct clipleaf_s {
clipport_t *portals;
int contents;
} clipleaf_t;
typedef struct nodeleaf_s {
clipleaf_t *leafs[2]; ///< front, back. If null, node's child is a node
} nodeleaf_t;
nodeleaf_t *MOD_BuildBrushes (hull_t *hull);
#endif // __world_h #endif // __world_h

View file

@ -7,7 +7,7 @@ INCLUDES= -I$(top_srcdir)/include
lib_LTLIBRARIES= libQFmodels.la @VID_MODEL_TARGETS@ lib_LTLIBRARIES= libQFmodels.la @VID_MODEL_TARGETS@
EXTRA_LTLIBRARIES= libQFmodels_gl.la libQFmodels_sw.la EXTRA_LTLIBRARIES= libQFmodels_gl.la libQFmodels_sw.la
models_sources = clip_hull.c model.c trace.c winding.c models_sources = clip_hull.c model.c portal.c trace.c winding.c
libQFmodels_la_LDFLAGS= -version-info $(QUAKE_LIBRARY_VERSION_INFO) -no-undefined libQFmodels_la_LDFLAGS= -version-info $(QUAKE_LIBRARY_VERSION_INFO) -no-undefined
libQFmodels_la_LIBADD= brush/libbrush.la $(top_builddir)/libs/util/libQFutil.la libQFmodels_la_LIBADD= brush/libbrush.la $(top_builddir)/libs/util/libQFutil.la

181
libs/models/portal.c Normal file
View file

@ -0,0 +1,181 @@
/*
#FILENAME#
#DESCRIPTION#
Copyright (C) 2011 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2011/11/14
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((used)) const char rcsid[] = "$Id$";
#include <stdlib.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <stdio.h>
#include "QF/model.h"
#include "QF/winding.h"
#include "world.h"
static clipleaf_t *
alloc_leaf (void)
{
return calloc (1, sizeof (clipleaf_t));
}
static clipport_t *
alloc_portal (void)
{
return calloc (1, sizeof (clipport_t));
}
static void
remove_portal (clipport_t *portal, clipleaf_t *leaf)
{
clipport_t **p;
int side;
for (p = &leaf->portals; *p; p = &(*p)->next[side]) {
side = (*p)->leafs[1] == leaf;
if (*p == portal) {
*p = portal->next[side];
portal->next[side] = 0;
break;
}
}
}
static void
add_portal (clipport_t *portal, clipleaf_t *front, clipleaf_t *back)
{
portal->leafs[0] = front;
portal->next[0] = front->portals;
front->portals = portal;
portal->leafs[1] = back;
portal->next[1] = back->portals;
back->portals = portal;
}
static clipleaf_t *
carve_leaf (hull_t *hull, nodeleaf_t *nodeleafs, clipleaf_t *leaf, int num)
{
mclipnode_t *node;
plane_t *plane;
winding_t *winding, *fw, *bw;
clipport_t *portal;
clipport_t *new_portal;
clipport_t *next_portal;
clipleaf_t *other_leaf;
clipleaf_t *new_leaf;
plane_t clipplane;
int side;
if (num < 0) {
// we've hit a leaf. all done
leaf->contents = num;
return leaf;
}
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
winding = BaseWindingForPlane (plane);
for (portal = leaf->portals; portal; portal = portal->next[side]) {
clipplane = hull->planes[portal->planenum];
side = (portal->leafs[1] == leaf);
if (side)
PlaneFlip (&clipplane, &clipplane);
winding = ClipWinding (winding, &clipplane, true);
}
new_leaf = alloc_leaf ();
portal = leaf->portals;
leaf->portals = 0;
for (; portal; portal = next_portal) {
side = (portal->leafs[1] == leaf);
next_portal = portal->next[side];
other_leaf = portal->leafs[!side];
remove_portal (portal, other_leaf);
DivideWinding (portal->winding, plane, &fw, &bw);
if (!fw) {
if (side)
add_portal (portal, other_leaf, new_leaf);
else
add_portal (portal, new_leaf, other_leaf);
continue;
}
if (!bw) {
if (side)
add_portal (portal, other_leaf, leaf);
else
add_portal (portal, leaf, other_leaf);
continue;
}
new_portal = alloc_portal ();
new_portal->planenum = portal->planenum;
new_portal->winding = bw;
FreeWinding (portal->winding);
portal->winding = fw;
if (side) {
add_portal (portal, other_leaf, leaf);
add_portal (new_portal, other_leaf, new_leaf);
} else {
add_portal (portal, leaf, other_leaf);
add_portal (new_portal, new_leaf, other_leaf);
}
}
new_portal = alloc_portal ();
new_portal->planenum = node->planenum;
new_portal->winding = winding;
add_portal (new_portal, leaf, new_leaf);
nodeleafs[num].leafs[0] = carve_leaf (hull, nodeleafs, leaf,
node->children[0]);
nodeleafs[num].leafs[1] = carve_leaf (hull, nodeleafs, new_leaf,
node->children[1]);
return 0;
}
nodeleaf_t *
MOD_BuildBrushes (hull_t *hull)
{
int numnodes = hull->lastclipnode + 1;
nodeleaf_t *nodeleafs;
clipleaf_t *root; // this will be carved into all the actual leafs
nodeleafs = calloc (numnodes, sizeof (nodeleaf_t));
root = alloc_leaf ();
carve_leaf (hull, nodeleafs, root, hull->firstclipnode);
return nodeleafs;
}

View file

@ -275,6 +275,7 @@ typedef struct {
qboolean startsolid; qboolean startsolid;
qboolean inopen; qboolean inopen;
qboolean inwater; qboolean inwater;
int num_portals;
} expect; } expect;
} test_t; } test_t;
@ -284,76 +285,76 @@ box_t player = { {16, 16, 28} };
test_t tests[] = { test_t tests[] = {
{"Point, Three parallel planes 1", &point, &hull_tpp1, {"Point, Three parallel planes 1", &point, &hull_tpp1,
{-64, 0, 0}, { 64, 0, 0}, { 1, 1, 1, 0, 0}}, {-64, 0, 0}, { 64, 0, 0}, { 1, 1, 1, 0, 0, 3}},
{"Point, Three parallel planes 1", &point, &hull_tpp1, {"Point, Three parallel planes 1", &point, &hull_tpp1,
{ 0, 0, 0}, { 40, 0, 0}, { 1, 0, 1, 1, 0}}, { 0, 0, 0}, { 40, 0, 0}, { 1, 0, 1, 1, 0, 3}},
{"Point, Three parallel planes 1", &point, &hull_tpp1, {"Point, Three parallel planes 1", &point, &hull_tpp1,
{ 40, 0, 0}, {-88, 0, 0}, {0.0625, 0, 0, 1, 0}}, { 40, 0, 0}, {-88, 0, 0}, {0.0625, 0, 0, 1, 0, 3}},
{"Point, Three parallel planes 1", &point, &hull_tpp1, {"Point, Three parallel planes 1", &point, &hull_tpp1,
{ 0, 0, 0}, { 64, 0, 0}, { 0.75, 0, 1, 1, 0}}, { 0, 0, 0}, { 64, 0, 0}, { 0.75, 0, 1, 1, 0, 3}},
{"Point, Three parallel planes 1", &point, &hull_tpp1, {"Point, Three parallel planes 1", &point, &hull_tpp1,
{ 0, 0, 0}, { 0, 8, 0}, { 1, 1, 1, 0, 0}}, { 0, 0, 0}, { 0, 8, 0}, { 1, 1, 1, 0, 0, 3}},
{"Point, Three parallel planes 1", &point, &hull_tpp1, {"Point, Three parallel planes 1", &point, &hull_tpp1,
{ 40, 0, 0}, { 40, 8, 0}, { 1, 0, 0, 1, 0}}, { 40, 0, 0}, { 40, 8, 0}, { 1, 0, 0, 1, 0, 3}},
{"Point, Three parallel planes 2", &point, &hull_tpp2, {"Point, Three parallel planes 2", &point, &hull_tpp2,
{-64, 0, 0}, { 64, 0, 0}, { 1, 1, 1, 0, 0}}, {-64, 0, 0}, { 64, 0, 0}, { 1, 1, 1, 0, 0, 3}},
{"Point, Three parallel planes 2", &point, &hull_tpp2, {"Point, Three parallel planes 2", &point, &hull_tpp2,
{ 0, 0, 0}, { 40, 0, 0}, { 1, 0, 1, 1, 0}}, { 0, 0, 0}, { 40, 0, 0}, { 1, 0, 1, 1, 0, 3}},
{"Point, Three parallel planes 2", &point, &hull_tpp2, {"Point, Three parallel planes 2", &point, &hull_tpp2,
{ 40, 0, 0}, {-88, 0, 0}, {0.0625, 0, 0, 1, 0}}, { 40, 0, 0}, {-88, 0, 0}, {0.0625, 0, 0, 1, 0, 3}},
{"Point, Three parallel planes 2", &point, &hull_tpp2, {"Point, Three parallel planes 2", &point, &hull_tpp2,
{ 0, 0, 0}, { 64, 0, 0}, { 0.75, 0, 1, 1, 0}}, { 0, 0, 0}, { 64, 0, 0}, { 0.75, 0, 1, 1, 0, 3}},
{"Point, Three parallel planes with water", &point, &hull_tppw, {"Point, Three parallel planes with water", &point, &hull_tppw,
{-64, 0, 0}, { 64, 0, 0}, { 0.875, 0, 1, 1, 1}}, {-64, 0, 0}, { 64, 0, 0}, { 0.875, 0, 1, 1, 1, 3}},
{"Point, Three parallel planes with water", &point, &hull_tppw, {"Point, Three parallel planes with water", &point, &hull_tppw,
{ 0, 0, 0}, { 40, 0, 0}, { 1, 0, 0, 1, 1}}, { 0, 0, 0}, { 40, 0, 0}, { 1, 0, 0, 1, 1, 3}},
{"Point, Three parallel planes with water", &point, &hull_tppw, {"Point, Three parallel planes with water", &point, &hull_tppw,
{ 40, 0, 0}, {-88, 0, 0}, {0.5625, 0, 0, 1, 1}}, { 40, 0, 0}, {-88, 0, 0}, {0.5625, 0, 0, 1, 1, 3}},
{"Point, Three parallel planes with water", &point, &hull_tppw, {"Point, Three parallel planes with water", &point, &hull_tppw,
{ 0, 0, 0}, { 64, 0, 0}, { 0.75, 0, 0, 1, 1}}, { 0, 0, 0}, { 64, 0, 0}, { 0.75, 0, 0, 1, 1, 3}},
{"Point, Three parallel planes with water", &point, &hull_tppw, {"Point, Three parallel planes with water", &point, &hull_tppw,
{ 0, 0, 0}, { 0, 8, 0}, { 1, 0, 0, 1, 0}}, { 0, 0, 0}, { 0, 8, 0}, { 1, 0, 0, 1, 0, 3}},
{"Point, Three parallel planes with water", &point, &hull_tppw, {"Point, Three parallel planes with water", &point, &hull_tppw,
{ 40, 0, 0}, { 40, 8, 0}, { 1, 0, 0, 0, 1}}, { 40, 0, 0}, { 40, 8, 0}, { 1, 0, 0, 0, 1, 3}},
{"Point, Three parallel planes with water", &point, &hull_tppw, {"Point, Three parallel planes with water", &point, &hull_tppw,
{ 0, 0, 0}, { 40, 0, 0}, { 1, 0, 0, 1, 1}}, { 0, 0, 0}, { 40, 0, 0}, { 1, 0, 0, 1, 1, 3}},
{"Point, Step 1", &point, &hull_step1, {"Point, Step 1", &point, &hull_step1,
{ -16, 0, 8}, {16, 0, 24}, { 0.5, 0, 0, 1, 0}}, { -16, 0, 8}, {16, 0, 24}, { 0.5, 0, 0, 1, 0, 5}},
{"Box, Step 1", &box, &hull_step1, {"Box, Step 1", &box, &hull_step1,
{ -16, 0, 8}, {16, 0, 24}, { 0.25, 0, 0, 1, 0}}, { -16, 0, 8}, {16, 0, 24}, { 0.25, 0, 0, 1, 0, 5}},
{"Box, Step 1", &box, &hull_step1, {"Box, Step 1", &box, &hull_step1,
{ -16, 0, 8}, {16, 0, 40}, { 0.25, 0, 0, 1, 0}}, { -16, 0, 8}, {16, 0, 40}, { 0.25, 0, 0, 1, 0, 5}},
{"Box, Step 1", &box, &hull_step1, {"Box, Step 1", &box, &hull_step1,
{ -16, 0, 8}, {16, 0, 135}, { 0.25, 0, 0, 1, 0}}, { -16, 0, 8}, {16, 0, 135}, { 0.25, 0, 0, 1, 0, 5}},
// 136 is a corner case caused by back/front side issues and 0 // 136 is a corner case caused by back/front side issues and 0
{"Box, Step 1", &box, &hull_step1, {"Box, Step 1", &box, &hull_step1,
{ -16, 0, 8}, {16, 0, 137}, { 1, 0, 0, 1, 0}}, { -16, 0, 8}, {16, 0, 137}, { 1, 0, 0, 1, 0, 5}},
{"Point, Covered Step", &point, &hull_covered_step, {"Point, Covered Step", &point, &hull_covered_step,
{ -24, 0, 8}, {-24, 0, 72}, { 0.5, 0, 0, 1, 0}}, { -24, 0, 8}, {-24, 0, 72}, { 0.5, 0, 0, 1, 0, 9}},
{"Box, Covered Step", &box, &hull_covered_step, {"Box, Covered Step", &box, &hull_covered_step,
{ -32, 0, 8}, {-32, 0, 72}, { 0.375, 0, 0, 1, 0}}, { -32, 0, 8}, {-32, 0, 72}, { 0.375, 0, 0, 1, 0, 9}},
{"Box, Covered Step", &box, &hull_covered_step, {"Box, Covered Step", &box, &hull_covered_step,
{ -24, 0, 8}, {-24, 0, 72}, { 0.375, 0, 0, 1, 0}}, { -24, 0, 8}, {-24, 0, 72}, { 0.375, 0, 0, 1, 0, 9}},
{"Box, Covered Step", &box, &hull_covered_step, {"Box, Covered Step", &box, &hull_covered_step,
{ -25, 0, 8}, {7, 0, 72}, { 0.375, 0, 0, 1, 0}}, { -25, 0, 8}, {7, 0, 72}, { 0.375, 0, 0, 1, 0, 9}},
{"Box, Covered Step", &box, &hull_covered_step, {"Box, Covered Step", &box, &hull_covered_step,
{ -8, 0, 40}, {-16, 0, 40}, { 0.5, 0, 0, 1, 0}}, { -8, 0, 40}, {-16, 0, 40}, { 0.5, 0, 0, 1, 0, 9}},
{"Box, Covered Step", &box, &hull_covered_step, {"Box, Covered Step", &box, &hull_covered_step,
{ -17, 0, 8}, {-1, 0, 72}, { 1, 0, 0, 1, 0}}, { -17, 0, 8}, {-1, 0, 72}, { 1, 0, 0, 1, 0, 9}},
{"Box, Covered Step", &box, &hull_covered_step, {"Box, Covered Step", &box, &hull_covered_step,
{ -8, 0, 40}, {8, 0, 72}, { 1, 0, 0, 1, 0}}, { -8, 0, 40}, {8, 0, 72}, { 1, 0, 0, 1, 0, 9}},
{"Box, Step 2", &box, &hull_step2, {"Box, Step 2", &box, &hull_step2,
{ 0, 0, 64}, {0, 0, 0}, { 0.375, 0, 0, 1, 0}}, { 0, 0, 64}, {0, 0, 0}, { 0.375, 0, 0, 1, 0, 5}},
{"Box, Step 3", &box, &hull_step3, {"Box, Step 3", &box, &hull_step3,
{ 0, 0, 64}, {0, 0, 0}, { 0.375, 0, 0, 1, 0}}, { 0, 0, 64}, {0, 0, 0}, { 0.375, 0, 0, 1, 0, 5}},
{"Box, Ramp", &box, &hull_ramp, {"Box, Ramp", &box, &hull_ramp,
{ 0, 0, 16}, {0, 0, 0}, { 0.5, 0, 0, 1, 0}}, { 0, 0, 16}, {0, 0, 0}, { 0.5, 0, 0, 1, 0, 4}},
}; };
#define num_tests (sizeof (tests) / sizeof (tests[0])) #define num_tests (sizeof (tests) / sizeof (tests[0]))
@ -378,6 +379,30 @@ do_trace (box_t *box, hull_t *hull, vec3_t start, vec3_t end)
return trace; return trace;
} }
typedef struct portlist_s {
struct portlist_s *next;
clipport_t *portal;
} portlist_t;
static portlist_t *
collect_portals (clipport_t *portal, portlist_t *portal_list)
{
portlist_t *p;
if (!portal)
return portal_list;
for (p = portal_list; p; p = p->next)
if (p->portal == portal)
return portal_list;
p = malloc (sizeof (portlist_t));
p->portal = portal;
p->next = portal_list;
portal_list = p;
portal_list = collect_portals (portal->next[0], portal_list);
portal_list = collect_portals (portal->next[1], portal_list);
return portal_list;
}
static int static int
run_test (test_t *test) run_test (test_t *test)
{ {
@ -387,6 +412,81 @@ run_test (test_t *test)
char *expect; char *expect;
char *got; char *got;
static int output = 0; static int output = 0;
portlist_t *portal_list = 0;
if (!test->hull->nodeleafs) {
hull_t *hull = test->hull;
int i, j;
portlist_t *p;
clipport_t *portal;
clipleaf_t *leaf;
int side;
hull->nodeleafs = MOD_BuildBrushes (hull);
for (i = hull->firstclipnode; i <= hull->lastclipnode; i++) {
for (j = 0; j < 2; j++) {
if (((hull->clipnodes[i].children[j] >= 0)
!= (!hull->nodeleafs[i].leafs[j]))
|| (hull->nodeleafs[i].leafs[j]
&& (hull->nodeleafs[i].leafs[j]->contents
!= hull->clipnodes[i].children[j]))) {
printf ("bad nodeleaf %d %d\n", i, j);
res = 1;
}
}
if (hull->nodeleafs[i].leafs[0]
&& (hull->nodeleafs[i].leafs[0]
== hull->nodeleafs[i].leafs[1])) {
printf ("bad nodeleaf %d %d\n", i, j);
res = 1;
}
}
if (res)
goto nodeleaf_bail;
for (i = hull->firstclipnode; i <= hull->lastclipnode; i++) {
for (j = 0; j < 2; j++) {
leaf = hull->nodeleafs[i].leafs[j];
if (!leaf)
continue;
portal_list = collect_portals (leaf->portals, portal_list);
}
}
for (i = 0, p = portal_list; p; i++, p = p->next)
;
if (i != test->expect.num_portals) {
res = 1;
printf ("bad portal count: %d %d\n", test->expect.num_portals, i);
goto nodeleaf_bail;
}
for (p = portal_list; p; p = p->next) {
for (j = 0; j < 2; j++) {
int found = 0;
leaf = p->portal->leafs[j];
for (portal = leaf->portals; portal;
portal = portal->next[side]) {
//printf("%p %d %p %p %p\n", p, j, leaf, portal, p->portal);
side = portal->leafs[1] == leaf;
if (!side && portal->leafs[0] != leaf) {
printf ("mislinked portal\n");
res = 1;
}
if (portal == p->portal)
found = 1;
}
if (!found) {
printf ("portal unreachable from leaf\n");
res = 1;
}
}
}
}
nodeleaf_bail:
while (portal_list) {
portlist_t *t = portal_list;
portal_list = portal_list->next;
free (t);
}
VectorSubtract (test->end, test->start, end); VectorSubtract (test->end, test->start, end);
VectorMultAdd (test->start, test->expect.frac, end, end); VectorMultAdd (test->start, test->expect.frac, end, end);