convert line ends
[canaan.git] / prj / cam / src / sim / wrbsp.cpp
blobb8387b24798ba45539ca8ea4a14781c25887f53f
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 ////////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/sim/wrbsp.cpp,v 1.11 2000/02/19 13:27:49 toml Exp $
8 //
9 // Run-time worldrep bsp tree
12 #include <lg.h>
13 #include <math.h>
14 #include <allocapi.h>
15 #include <hashpp.h>
16 #include <hshpptem.h>
17 #include <dynarray.h>
18 #include <wr.h>
19 #include <portal.h>
21 #include <media.h>
22 #include <bspdata.h>
23 #include <wrbsp.h>
25 #include <mprintf.h>
26 #include <memall.h>
27 #include <dbmem.h> // must be last header!
29 ////////////////////////////////////////////////////////////////////////////////
31 cDynArray<wrBspNode> wrBspTree;
33 wrBspNode *g_wrBspTree = NULL;
34 int g_wrBspTreeSize = 0;
36 struct sPostSplit
38 int cell_id;
39 BspNode *n;
42 cDynArray<sPostSplit> gPostSplitList;
44 ////////////////////////////////////////////////////////////////////////////////
46 cDynArray<PortalPlane *> gExtraPlaneList;
48 void ClearExtraPlanes()
50 for (int i=0; i<gExtraPlaneList.Size(); i++)
52 if (gExtraPlaneList[i] != NULL)
54 delete gExtraPlaneList[i];
55 gExtraPlaneList[i] = NULL;
58 gExtraPlaneList.SetSize(0);
61 PortalPlane *AddExtraPlane(mxs_vector plane_norm, mxs_real plane_const)
63 PortalPlane *pNewPlane = new PortalPlane;
65 pNewPlane->normal = plane_norm;
66 pNewPlane->plane_constant = plane_const;
68 LGALLOC_PUSH_CREDIT();
69 gExtraPlaneList.Append(pNewPlane);
70 LGALLOC_POP_CREDIT();
72 return pNewPlane;
75 ////////////////////////////////////////////////////////////////////////////////
77 PortalPlane *FindPlaneInCell(mxs_vector *plane_norm, mxs_real plane_const, int cell_id)
79 PortalCell *pCell = WR_CELL(cell_id);
80 Assert_(pCell);
82 mxs_vector norm_delta;
84 for (int i=0; i<pCell->num_planes; i++)
86 if (fabs(plane_const - pCell->plane_list[i].plane_constant) < 0.00001)
88 mx_sub_vec(&norm_delta, &pCell->plane_list[i].normal, plane_norm);
90 if (mx_mag2_vec(&norm_delta) < 0.00001)
91 return &pCell->plane_list[i];
95 return NULL;
98 BOOL FindPortalPlaneRec(mxs_vector *plane_norm, mxs_real plane_const, BspNode *n, PortalPlane **pPlane, BOOL *reversed)
100 if (n->leaf)
102 if (n->cell_id > 0)
105 if ((*pPlane = FindPlaneInCell(plane_norm, plane_const, n->cell_id - 1)) != NULL)
107 *reversed = FALSE;
108 return TRUE;
111 mxs_vector pnorm;
112 mxs_real pconst;
114 mx_scale_vec(&pnorm, plane_norm, -1.0);
115 pconst = plane_const * -1.0;
117 if ((*pPlane = FindPlaneInCell(&pnorm, pconst, n->cell_id - 1)) != NULL)
119 *reversed = TRUE;
120 return TRUE;
123 return FALSE;
125 else
126 return FALSE;
128 else
130 if (FindPortalPlaneRec(plane_norm, plane_const, n->inside, pPlane, reversed))
131 return TRUE;
133 return FindPortalPlaneRec(plane_norm, plane_const, n->outside, pPlane, reversed);
137 BOOL FindPortalPlane(BspNode *n, PortalPlane **pPlane, int *reversed)
139 BOOL found = FALSE;
141 mxs_vector plane_norm;
142 mxs_vector rev_plane_norm;
143 mxs_real plane_const = n->split_plane.d;
144 mxs_real rev_plane_const = -n->split_plane.d;
146 mx_mk_vec(&plane_norm, n->split_plane.a, n->split_plane.b, n->split_plane.c);
147 mx_mk_vec(&rev_plane_norm, -n->split_plane.a, -n->split_plane.b, -n->split_plane.c);
149 if (!FindPortalPlaneRec(&plane_norm, plane_const, n, pPlane, reversed))
151 for (int i=0; i<wr_num_cells; i++)
153 if ((*pPlane = FindPlaneInCell(&plane_norm, plane_const, i)) != NULL)
155 *reversed = FALSE;
156 found = TRUE;
157 break;
160 if ((*pPlane = FindPlaneInCell(&rev_plane_norm, rev_plane_const, i)) != NULL)
162 *reversed = TRUE;
163 found = TRUE;
164 break;
168 else
169 found = TRUE;
171 // Add to our own plane list, if it wasn't found in the world
172 if (!found)
174 *pPlane = AddExtraPlane(plane_norm, plane_const);
175 *reversed = FALSE;
177 found = TRUE;
180 return found;
183 ////////////////////////////////////////////////////////////////////////////////
186 // Allocate a new leaf and initialize it
188 uint wrBspLeafCreate(uint parent_index, int cell_id)
190 wrBspNode new_node;
192 new_node.flags = 0;
194 wrBspSetLeaf(&new_node);
195 wrBspUnmark(&new_node);
196 wrBspSetNormal(&new_node);
198 wrSetParent(&new_node, parent_index);
199 new_node.plane = NULL;
201 new_node.cell_id = cell_id;
203 LGALLOC_AUTO_CREDIT();
204 return wrBspTree.Append(new_node);
208 // Allocate a new node and initialize it
210 uint wrBspNodeCreate(BspNode *n, int cell_id, uint parent_index)
212 wrBspNode new_node;
214 new_node.flags = 0;
216 wrBspSetNode(&new_node);
217 wrBspUnmark(&new_node);
219 wrSetParent(&new_node, parent_index);
221 BOOL reversed;
222 FindPortalPlane(n, &new_node.plane, &reversed);
224 AssertMsg(new_node.plane, "Unable to find matching splitplane!\n");
226 if (reversed)
227 wrBspSetReversed(&new_node);
228 else
229 wrBspSetNormal(&new_node);
231 LGALLOC_AUTO_CREDIT();
232 return wrBspTree.Append(new_node);
236 // Search the tree for a leaf with the specified cell_id
237 // and return a pointer to the leaf
239 uint wrBspFindLeaf(int cell_id)
241 for (int i=0; i<wrBspTree.Size(); i++)
243 if (wrBspIsLeaf(&wrBspTree[i]) && (wrBspTree[i].cell_id == cell_id))
244 return i;
247 return WRBSP_INVALID;
251 // Point each cell at its leaf in the worldrep BSP
253 void wrBspTreeRefCells(uint node_index)
255 if (node_index == WRBSP_INVALID)
256 return;
258 if (wrBspTree.Size() == 0)
259 return;
261 wrBspNode *pCurNode = &wrBspTree[node_index];
263 if (wrBspIsLeaf(pCurNode))
265 if (pCurNode->cell_id != -1)
266 WR_CELL(pCurNode->cell_id)->leaf_index = node_index;
268 else
270 wrBspTreeRefCells(pCurNode->inside_index);
271 wrBspTreeRefCells(pCurNode->outside_index);
276 // Recursively copies the CSG's BSP tree. At each recursion it
277 // allocates the appropriate structure and copies it. Returned
278 // from each level of recursion is a pointer to the element
279 // created from the returning level of recursion. Note that a
280 // pointer from the current level of recursion is passed to the
281 // next level of recursion so that children can have links to
282 // their parents.
284 // When first calling, parent should be passed in as NULL.
286 // Also note that when this copy is taking place the cells
287 // have not yet been numbered or emitted. I am assuming that
288 // they will be numbered according to the existing CSG BSP
289 // tree (inorder traversal). Additional splits due to high-
290 // poly-count-cells will go to dummy nodes, whose numbers
291 // come *after* the original CSG BSP's cell's numbers.
293 // Of course, for this BSP tree, there will be no dummy
294 // nodes -- splits will actually create nodes in the tree.
295 // But that's handled later.
297 uint wrBspTreeCopy(BspNode *node, uint parent_id)
299 uint new_node_index;
301 // If it's the first recursion, initialize the BSP tree
302 if (parent_id == WRBSP_INVALID)
304 wrBspTree.SetSize(0);
305 g_wrBspTree = NULL;
306 g_wrBspTreeSize = 0;
308 ClearExtraPlanes();
311 if (node->ph)
313 // Create leaf, but only assign a cell number if it's
314 // a non-solid (marked) leaf
315 if (IS_MARKED(node))
316 new_node_index = wrBspLeafCreate(parent_id, node->cell_id - 1);
317 else
318 new_node_index = WRBSP_INVALID;
320 else
322 uint ret_index; // to enforce order of evaulation of assignment
324 new_node_index = wrBspNodeCreate(node, node->cell_id, parent_id);
326 AssertMsg(new_node_index != WRBSP_INVALID, "Invalid cration node index");
328 ret_index = wrBspTreeCopy(node->inside, new_node_index);
329 wrBspTree[new_node_index].inside_index = ret_index;
331 ret_index = wrBspTreeCopy(node->outside, new_node_index);
332 wrBspTree[new_node_index].outside_index = ret_index;
335 if (parent_id == WRBSP_INVALID)
337 wrBspTreeApplyPostSplits();
339 if (wrBspTree.Size() > 0)
340 g_wrBspTree = &wrBspTree[0];
341 else
342 g_wrBspTree = NULL;
344 g_wrBspTreeSize = wrBspTree.Size();
346 mprintf(" %d extra bsp planes created\n", gExtraPlaneList.Size());
349 return new_node_index;
353 // Deallocates a worldrep BSP tree
355 void wrBspTreeDeallocate()
357 wrBspTree.SetSize(0);
358 g_wrBspTree = NULL;
359 g_wrBspTreeSize = 0;
360 ClearExtraPlanes();
364 // Dumps the tree ever-so-ineligantly to the mono
366 void wrBspTreeDumpRec(uint node_index)
368 if (node_index == WRBSP_INVALID)
369 return;
371 wrBspNode *pCurNode = &wrBspTree[node_index];
373 if (wrBspIsLeaf(pCurNode))
375 mprintf(" LEAF (%d) %c\n", node_index, wrBspIsMarked(pCurNode) ? '*' : ' ');
376 mprintf(" parent_id = %d\n", wrParentIndex(pCurNode));
377 mprintf(" cell_id = %d\n", pCurNode->cell_id);
379 else
381 mprintf(" NODE (%d) %s\n", node_index, wrBspIsReversed(pCurNode) ? "rev" : " ");
382 mprintf(" %gx + %gy + %gz + %g\n", pCurNode->plane->normal.x,
383 pCurNode->plane->normal.y,
384 pCurNode->plane->normal.z,
385 pCurNode->plane->plane_constant);
386 wrBspTreeDumpRec(pCurNode->inside_index);
387 wrBspTreeDumpRec(pCurNode->outside_index);
391 void wrBspTreeDump()
393 wrBspTreeDumpRec(WRBSP_HEAD);
397 ////////////////////////////////////////////////////////////////////////////////
399 void wrBspTreeAddPostSplit(BspNode *n, int cell_id)
401 sPostSplit postSplit;
403 postSplit.cell_id = cell_id;
404 postSplit.n = n;
406 LGALLOC_AUTO_CREDIT();
407 gPostSplitList.Append(postSplit);
410 void wrBspTreeApplyPostSplits()
412 for (int i=0; i<gPostSplitList.Size(); i++)
414 uint split_index = wrBspFindLeaf(gPostSplitList[i].cell_id);
416 AssertMsg1(split_index != WRBSP_INVALID, "Unable to find cell %d to split!\n", gPostSplitList[i].cell_id);
418 wrBspNode *pSplitLeaf = &wrBspTree[split_index];
420 BOOL reversed;
421 FindPortalPlane(gPostSplitList[i].n, &pSplitLeaf->plane, &reversed);
423 if (reversed)
424 wrBspSetReversed(pSplitLeaf);
425 else
426 wrBspSetNormal(pSplitLeaf);
428 // Convert to a node
429 wrBspSetNode(pSplitLeaf);
430 wrBspUnmark(pSplitLeaf);
432 uint ret_index;
434 ret_index = wrBspLeafCreate(split_index, gPostSplitList[i].cell_id);
435 wrBspTree[split_index].inside_index = ret_index;
437 ret_index = wrBspLeafCreate(split_index, gPostSplitList[i].n->cell_id - 1);
438 wrBspTree[split_index].outside_index = ret_index;
441 gPostSplitList.SetSize(0);
445 ////////////////////////////////////////////////////////////////////////////////
447 typedef struct
449 int cell_id;
450 int plane_id;
451 } sCellPlane;
453 typedef cHashTableFunctions<long> LongHashFunctions;
454 typedef cHashTable<long, sCellPlane, LongHashFunctions> cCellPlaneTable;
456 cCellPlaneTable gCellPlaneTable;
458 #ifdef _MSC_VER
459 template cCellPlaneTable;
460 #endif
462 void wrBspTreeWrite(PortalReadWrite write)
464 int i, j;
465 sCellPlane cellplane;
467 gCellPlaneTable.Clear();
469 // First build a table of plane pointers to cell-plane ids
470 for (i=0; i<wr_num_cells; i++)
472 PortalCell *pCell = WR_CELL(i);
473 Assert_(pCell);
475 for (j=0; j<pCell->num_planes; j++)
477 cellplane.cell_id = i;
478 cellplane.plane_id = j;
480 gCellPlaneTable.Set((long)(&pCell->plane_list[j]), cellplane);
484 // Write out our extra planes
485 int size = gExtraPlaneList.Size();
487 write(&size, sizeof(int), 1);
488 for (i=0; i<size; i++)
490 PortalPlane* plane = gExtraPlaneList[i];
491 // You kids are so cute, writing out each field like this
492 write(&plane->normal,sizeof(plane->normal),1);
493 write(&plane->plane_constant,sizeof(plane->plane_constant),1);
496 // Then write out our array, replacing plane pointers will cellplanes
497 write(&g_wrBspTreeSize, sizeof(int), 1);
499 for (i=0; i<g_wrBspTreeSize; i++)
501 write(&g_wrBspTree[i].parent_index, sizeof(uint), 1);
503 cellplane.cell_id = -1;
504 cellplane.plane_id = -1;
506 if (g_wrBspTree[i].plane)
508 if (!gCellPlaneTable.Lookup((long)g_wrBspTree[i].plane, &cellplane))
510 // Must be an extra plane
511 for (int j=0; j<gExtraPlaneList.Size(); j++)
513 if (g_wrBspTree[i].plane == gExtraPlaneList[j])
515 cellplane.plane_id = j;
516 break;
521 AssertMsg(cellplane.plane_id != -1, "Unable to match plane pointer in BSP save");
524 write(&cellplane, sizeof(sCellPlane), 1);
526 write(&g_wrBspTree[i].inside_index, sizeof(uint), 1);
527 write(&g_wrBspTree[i].outside_index, sizeof(uint), 1);
530 // And clean up
532 gCellPlaneTable.Clear();
536 void wrBspTreeRead(PortalReadWrite read)
538 sCellPlane cellplane;
539 int i;
541 int size;
543 read(&size, sizeof(int), 1);
545 gExtraPlaneList.SetSize(size);
546 for (i=0; i<size; i++)
548 PortalPlane* plane = new PortalPlane;
549 read(&plane->normal,sizeof(plane->normal),1);
550 read(&plane->plane_constant,sizeof(plane->plane_constant),1);
552 gExtraPlaneList[i] = plane;
555 read(&g_wrBspTreeSize, sizeof(int), 1);
557 LGALLOC_PUSH_CREDIT();
558 wrBspTree.SetSize(g_wrBspTreeSize);
559 LGALLOC_POP_CREDIT();
561 if (g_wrBspTreeSize > 0)
562 g_wrBspTree = &wrBspTree[0];
563 else
564 g_wrBspTree = NULL;
566 for (i=0; i<g_wrBspTreeSize; i++)
568 read(&g_wrBspTree[i].parent_index, sizeof(uint), 1);
570 read(&cellplane, sizeof(sCellPlane), 1);
572 if (cellplane.cell_id == -1)
574 if (cellplane.plane_id == -1)
575 g_wrBspTree[i].plane = NULL;
576 else
577 g_wrBspTree[i].plane = gExtraPlaneList[cellplane.plane_id];
579 else
580 g_wrBspTree[i].plane = &WR_CELL(cellplane.cell_id)->plane_list[cellplane.plane_id];
582 read(&g_wrBspTree[i].inside_index, sizeof(uint), 1);
583 read(&g_wrBspTree[i].outside_index, sizeof(uint),1);