2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 ////////////////////////////////////////////////////////////////////////////////
7 // $Header: r:/t2repos/thief2/src/sim/wrbsp.cpp,v 1.11 2000/02/19 13:27:49 toml Exp $
9 // Run-time worldrep bsp tree
27 #include <dbmem.h> // must be last header!
29 ////////////////////////////////////////////////////////////////////////////////
31 cDynArray
<wrBspNode
> wrBspTree
;
33 wrBspNode
*g_wrBspTree
= NULL
;
34 int g_wrBspTreeSize
= 0;
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
);
75 ////////////////////////////////////////////////////////////////////////////////
77 PortalPlane
*FindPlaneInCell(mxs_vector
*plane_norm
, mxs_real plane_const
, int cell_id
)
79 PortalCell
*pCell
= WR_CELL(cell_id
);
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
];
98 BOOL
FindPortalPlaneRec(mxs_vector
*plane_norm
, mxs_real plane_const
, BspNode
*n
, PortalPlane
**pPlane
, BOOL
*reversed
)
105 if ((*pPlane
= FindPlaneInCell(plane_norm
, plane_const
, n
->cell_id
- 1)) != NULL
)
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
)
130 if (FindPortalPlaneRec(plane_norm
, plane_const
, n
->inside
, pPlane
, reversed
))
133 return FindPortalPlaneRec(plane_norm
, plane_const
, n
->outside
, pPlane
, reversed
);
137 BOOL
FindPortalPlane(BspNode
*n
, PortalPlane
**pPlane
, int *reversed
)
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
)
160 if ((*pPlane
= FindPlaneInCell(&rev_plane_norm
, rev_plane_const
, i
)) != NULL
)
171 // Add to our own plane list, if it wasn't found in the world
174 *pPlane
= AddExtraPlane(plane_norm
, plane_const
);
183 ////////////////////////////////////////////////////////////////////////////////
186 // Allocate a new leaf and initialize it
188 uint
wrBspLeafCreate(uint parent_index
, int cell_id
)
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
)
216 wrBspSetNode(&new_node
);
217 wrBspUnmark(&new_node
);
219 wrSetParent(&new_node
, parent_index
);
222 FindPortalPlane(n
, &new_node
.plane
, &reversed
);
224 AssertMsg(new_node
.plane
, "Unable to find matching splitplane!\n");
227 wrBspSetReversed(&new_node
);
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
))
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
)
258 if (wrBspTree
.Size() == 0)
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
;
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
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
)
301 // If it's the first recursion, initialize the BSP tree
302 if (parent_id
== WRBSP_INVALID
)
304 wrBspTree
.SetSize(0);
313 // Create leaf, but only assign a cell number if it's
314 // a non-solid (marked) leaf
316 new_node_index
= wrBspLeafCreate(parent_id
, node
->cell_id
- 1);
318 new_node_index
= WRBSP_INVALID
;
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];
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);
364 // Dumps the tree ever-so-ineligantly to the mono
366 void wrBspTreeDumpRec(uint node_index
)
368 if (node_index
== WRBSP_INVALID
)
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
);
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
);
393 wrBspTreeDumpRec(WRBSP_HEAD
);
397 ////////////////////////////////////////////////////////////////////////////////
399 void wrBspTreeAddPostSplit(BspNode
*n
, int cell_id
)
401 sPostSplit postSplit
;
403 postSplit
.cell_id
= cell_id
;
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
];
421 FindPortalPlane(gPostSplitList
[i
].n
, &pSplitLeaf
->plane
, &reversed
);
424 wrBspSetReversed(pSplitLeaf
);
426 wrBspSetNormal(pSplitLeaf
);
429 wrBspSetNode(pSplitLeaf
);
430 wrBspUnmark(pSplitLeaf
);
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 ////////////////////////////////////////////////////////////////////////////////
453 typedef cHashTableFunctions
<long> LongHashFunctions
;
454 typedef cHashTable
<long, sCellPlane
, LongHashFunctions
> cCellPlaneTable
;
456 cCellPlaneTable gCellPlaneTable
;
459 template cCellPlaneTable
;
462 void wrBspTreeWrite(PortalReadWrite write
)
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
);
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
;
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);
532 gCellPlaneTable
.Clear();
536 void wrBspTreeRead(PortalReadWrite read
)
538 sCellPlane cellplane
;
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];
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
;
577 g_wrBspTree
[i
].plane
= gExtraPlaneList
[cellplane
.plane_id
];
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);