save a few more cycles by just using raw pointers. it's a bit uglier, but this is hard to represent with shared_ptr and I think it was the wrong choice anyways since the ownership chain is difficult to represent in a shared_ptr here.

This commit is contained in:
Jonathan 2022-06-17 14:56:17 -04:00
parent c3bb07acaa
commit b0dad9d01d
4 changed files with 110 additions and 107 deletions

View File

@ -784,11 +784,20 @@ public:
return w; return w;
} }
void flip_to(winding_base_t &winding_out) const
{
if (winding_out.size() < size()) {
winding_out.resize(size());
}
std::reverse_copy(begin(), end(), winding_out.begin());
}
winding_base_t flip() const winding_base_t flip() const
{ {
winding_base_t result(count); winding_base_t result(count);
std::reverse_copy(begin(), end(), result.begin()); flip_to(result);
return result; return result;
} }

View File

@ -39,17 +39,6 @@ enum pstatus_t
pstat_done pstat_done
}; };
struct portal_t
{
qplane3d plane; // normal pointing into neighbor
int leaf; // neighbor
std::shared_ptr<struct winding_t> winding;
pstatus_t status;
leafbits_t visbits, mightsee;
int nummightsee;
int numcansee;
};
struct winding_t : polylib::winding_base_t<MAX_WINDING_FIXED> struct winding_t : polylib::winding_base_t<MAX_WINDING_FIXED>
{ {
qvec3d origin; // Bounding sphere for fast clipping tests qvec3d origin; // Bounding sphere for fast clipping tests
@ -106,18 +95,31 @@ struct winding_t : polylib::winding_base_t<MAX_WINDING_FIXED>
Used for visdist to get the distance from a winding to a portal Used for visdist to get the distance from a winding to a portal
============================================================================ ============================================================================
*/ */
float distFromPortal(portal_t *p) inline float distFromPortal(struct portal_t *p);
{
vec_t mindist = 1e20;
for (size_t i = 0; i < size(); ++i) {
mindist = std::min(mindist, fabs(p->plane.distance_to(at(i))));
}
return mindist;
}
}; };
struct portal_t
{
qplane3d plane; // normal pointing into neighbor
int leaf; // neighbor
winding_t winding;
pstatus_t status;
leafbits_t visbits, mightsee;
int nummightsee;
int numcansee;
};
inline float winding_t::distFromPortal(struct portal_t *p)
{
vec_t mindist = 1e20;
for (size_t i = 0; i < size(); ++i) {
mindist = std::min(mindist, fabs(p->plane.distance_to(at(i))));
}
return mindist;
}
struct sep_t struct sep_t
{ {
sep_t *next; sep_t *next;
@ -149,7 +151,7 @@ struct pstack_t
pstack_t *next; pstack_t *next;
leaf_t *leaf; leaf_t *leaf;
portal_t *portal; // portal exiting portal_t *portal; // portal exiting
std::shared_ptr<winding_t> source, pass; winding_t *source, *pass;
winding_t windings[STACK_WINDINGS]; // Fixed size windings winding_t windings[STACK_WINDINGS]; // Fixed size windings
bool windings_used[STACK_WINDINGS]; // whether the winding is used currently bool windings_used[STACK_WINDINGS]; // whether the winding is used currently
qplane3d portalplane; qplane3d portalplane;
@ -158,9 +160,9 @@ struct pstack_t
int numseparators[2]; int numseparators[2];
}; };
std::shared_ptr<winding_t> AllocStackWinding(pstack_t *stack); winding_t *AllocStackWinding(pstack_t &stack);
void FreeStackWinding(std::shared_ptr<winding_t> &w, pstack_t *stack); void FreeStackWinding(winding_t *&w, pstack_t &stack);
std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, pstack_t *stack, qplane3d *split); winding_t *ClipStackWinding(winding_t *&in, pstack_t &stack, const qplane3d &split);
struct threaddata_t struct threaddata_t
{ {

View File

@ -29,8 +29,8 @@ static int c_leafskip;
pointer, was measurably faster pointer, was measurably faster
============== ==============
*/ */
static void ClipToSeparators(const std::shared_ptr<winding_t> &source, const qplane3d src_pl, static void ClipToSeparators(winding_t *const &source, const qplane3d src_pl,
const std::shared_ptr<winding_t> &pass, std::shared_ptr<winding_t> &target, unsigned int test, pstack_t *stack) winding_t *const &pass, winding_t *&target, unsigned int test, pstack_t &stack)
{ {
int i, j, k, l; int i, j, k, l;
qplane3d sep; qplane3d sep;
@ -107,13 +107,13 @@ static void ClipToSeparators(const std::shared_ptr<winding_t> &source, const qpl
/* Cache separating planes for tests 0, 1 */ /* Cache separating planes for tests 0, 1 */
if (test < 2) { if (test < 2) {
if (stack->numseparators[test] == MAX_SEPARATORS) if (stack.numseparators[test] == MAX_SEPARATORS)
FError("MAX_SEPARATORS"); FError("MAX_SEPARATORS");
stack->separators[test][stack->numseparators[test]] = sep; stack.separators[test][stack.numseparators[test]] = sep;
stack->numseparators[test]++; stack.numseparators[test]++;
} }
target = ClipStackWinding(target, stack, &sep); target = ClipStackWinding(target, stack, sep);
if (!target) if (!target)
return; // target is not visible return; // target is not visible
@ -141,7 +141,7 @@ static int CheckStack(leaf_t *leaf, threaddata_t *thread)
If src_portal is NULL, this is the originating leaf If src_portal is NULL, this is the originating leaf
================== ==================
*/ */
static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevstack) static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t &prevstack)
{ {
pstack_t stack; pstack_t stack;
portal_t *p; portal_t *p;
@ -170,7 +170,7 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
thread->base->numcansee++; thread->base->numcansee++;
} }
prevstack->next = &stack; prevstack.next = &stack;
stack.next = NULL; stack.next = NULL;
stack.leaf = leaf; stack.leaf = leaf;
@ -191,7 +191,7 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
for (i = 0; i < leaf->numportals; i++) { for (i = 0; i < leaf->numportals; i++) {
p = leaf->portals[i]; p = leaf->portals[i];
if (!(*prevstack->mightsee)[p->leaf]) { if (!(*prevstack.mightsee)[p->leaf]) {
c_leafskip++; c_leafskip++;
continue; // can't possibly see it continue; // can't possibly see it
} }
@ -210,7 +210,7 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
uint32_t more = 0; uint32_t more = 0;
numblocks = (portalleafs + leafbits_t::mask) >> leafbits_t::shift; numblocks = (portalleafs + leafbits_t::mask) >> leafbits_t::shift;
for (j = 0; j < numblocks; j++) { for (j = 0; j < numblocks; j++) {
might[j] = prevstack->mightsee->data()[j] & test[j]; might[j] = prevstack.mightsee->data()[j] & test[j];
more |= (might[j] & ~vis[j]); more |= (might[j] & ~vis[j]);
} }
@ -223,7 +223,7 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
stack.portalplane = p->plane; stack.portalplane = p->plane;
backplane = -p->plane; backplane = -p->plane;
if (qv::epsilonEqual(prevstack->portalplane.normal, backplane.normal, EQUAL_EPSILON)) if (qv::epsilonEqual(prevstack.portalplane.normal, backplane.normal, EQUAL_EPSILON))
continue; // can't go out a coplanar face continue; // can't go out a coplanar face
c_portalcheck++; c_portalcheck++;
@ -243,27 +243,28 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
*/ */
/* Clip any part of the target portal behind the source portal */ /* Clip any part of the target portal behind the source portal */
stack.pass = ClipStackWinding(p->winding, &stack, &thread->pstack_head.portalplane); stack.pass = &p->winding;
stack.pass = ClipStackWinding(stack.pass, stack, thread->pstack_head.portalplane);
if (!stack.pass) if (!stack.pass)
continue; continue;
if (!prevstack->pass) { if (!prevstack.pass) {
// the second leaf can only be blocked if coplanar // the second leaf can only be blocked if coplanar
stack.source = prevstack->source; stack.source = prevstack.source;
RecursiveLeafFlow(p->leaf, thread, &stack); RecursiveLeafFlow(p->leaf, thread, stack);
FreeStackWinding(stack.pass, &stack); FreeStackWinding(stack.pass, stack);
continue; continue;
} }
/* Clip any part of the target portal behind the pass portal */ /* Clip any part of the target portal behind the pass portal */
stack.pass = ClipStackWinding(stack.pass, &stack, &prevstack->portalplane); stack.pass = ClipStackWinding(stack.pass, stack, prevstack.portalplane);
if (!stack.pass) if (!stack.pass)
continue; continue;
/* Clip any part of the source portal in front of the target portal */ /* Clip any part of the source portal in front of the target portal */
stack.source = ClipStackWinding(prevstack->source, &stack, &backplane); stack.source = ClipStackWinding(prevstack.source, stack, backplane);
if (!stack.source) { if (!stack.source) {
FreeStackWinding(stack.pass, &stack); FreeStackWinding(stack.pass, stack);
continue; continue;
} }
@ -273,17 +274,17 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
if (options.level.value() > 0) { if (options.level.value() > 0) {
if (stack.numseparators[0]) { if (stack.numseparators[0]) {
for (j = 0; j < stack.numseparators[0]; j++) { for (j = 0; j < stack.numseparators[0]; j++) {
stack.pass = ClipStackWinding(stack.pass, &stack, &stack.separators[0][j]); stack.pass = ClipStackWinding(stack.pass, stack, stack.separators[0][j]);
if (!stack.pass) if (!stack.pass)
break; break;
} }
} else { } else {
/* Using prevstack source for separator cache correctness */ /* Using prevstack source for separator cache correctness */
ClipToSeparators( ClipToSeparators(
prevstack->source, thread->pstack_head.portalplane, prevstack->pass, stack.pass, 0, &stack); prevstack.source, thread->pstack_head.portalplane, prevstack.pass, stack.pass, 0, stack);
} }
if (!stack.pass) { if (!stack.pass) {
FreeStackWinding(stack.source, &stack); FreeStackWinding(stack.source, stack);
continue; continue;
} }
} }
@ -292,34 +293,34 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
if (options.level.value() > 1) { if (options.level.value() > 1) {
if (stack.numseparators[1]) { if (stack.numseparators[1]) {
for (j = 0; j < stack.numseparators[1]; j++) { for (j = 0; j < stack.numseparators[1]; j++) {
stack.pass = ClipStackWinding(stack.pass, &stack, &stack.separators[1][j]); stack.pass = ClipStackWinding(stack.pass, stack, stack.separators[1][j]);
if (!stack.pass) if (!stack.pass)
break; break;
} }
} else { } else {
/* Using prevstack source for separator cache correctness */ /* Using prevstack source for separator cache correctness */
ClipToSeparators(prevstack->pass, prevstack->portalplane, prevstack->source, stack.pass, 1, &stack); ClipToSeparators(prevstack.pass, prevstack.portalplane, prevstack.source, stack.pass, 1, stack);
} }
if (!stack.pass) { if (!stack.pass) {
FreeStackWinding(stack.source, &stack); FreeStackWinding(stack.source, stack);
continue; continue;
} }
} }
/* TEST 2 :: target -> pass -> source */ /* TEST 2 :: target -> pass -> source */
if (options.level.value() > 2) { if (options.level.value() > 2) {
ClipToSeparators(stack.pass, stack.portalplane, prevstack->pass, stack.source, 2, &stack); ClipToSeparators(stack.pass, stack.portalplane, prevstack.pass, stack.source, 2, stack);
if (!stack.source) { if (!stack.source) {
FreeStackWinding(stack.pass, &stack); FreeStackWinding(stack.pass, stack);
continue; continue;
} }
} }
/* TEST 3 :: pass -> target -> source */ /* TEST 3 :: pass -> target -> source */
if (options.level.value() > 3) { if (options.level.value() > 3) {
ClipToSeparators(prevstack->pass, prevstack->portalplane, stack.pass, stack.source, 3, &stack); ClipToSeparators(prevstack.pass, prevstack.portalplane, stack.pass, stack.source, 3, stack);
if (!stack.source) { if (!stack.source) {
FreeStackWinding(stack.pass, &stack); FreeStackWinding(stack.pass, stack);
continue; continue;
} }
} }
@ -327,10 +328,10 @@ static void RecursiveLeafFlow(int leafnum, threaddata_t *thread, pstack_t *prevs
c_portalpass++; c_portalpass++;
// flow through it for real // flow through it for real
RecursiveLeafFlow(p->leaf, thread, &stack); RecursiveLeafFlow(p->leaf, thread, stack);
FreeStackWinding(stack.source, &stack); FreeStackWinding(stack.source, stack);
FreeStackWinding(stack.pass, &stack); FreeStackWinding(stack.pass, stack);
} }
} }
@ -351,11 +352,11 @@ void PortalFlow(portal_t *p)
data.base = p; data.base = p;
data.pstack_head.portal = p; data.pstack_head.portal = p;
data.pstack_head.source = p->winding; data.pstack_head.source = &p->winding;
data.pstack_head.portalplane = p->plane; data.pstack_head.portalplane = p->plane;
data.pstack_head.mightsee = &p->mightsee; data.pstack_head.mightsee = &p->mightsee;
RecursiveLeafFlow(p->leaf, &data, &data.pstack_head); RecursiveLeafFlow(p->leaf, &data, data.pstack_head);
} }
/* /*
@ -399,7 +400,7 @@ static void BasePortalThread(size_t portalnum)
leafbits_t portalsee(numportals * 2); leafbits_t portalsee(numportals * 2);
p = portals + portalnum; p = portals + portalnum;
winding_t &w = *p->winding; winding_t &w = p->winding;
p->mightsee.resize(portalleafs); p->mightsee.resize(portalleafs);
@ -407,7 +408,7 @@ static void BasePortalThread(size_t portalnum)
if (tp == p) if (tp == p)
continue; continue;
winding_t &tw = *tp->winding; winding_t &tw = tp->winding;
// Quick test - completely at the back? // Quick test - completely at the back?
d = p->plane.distance_to(tw.origin); d = p->plane.distance_to(tw.origin);
@ -438,8 +439,8 @@ static void BasePortalThread(size_t portalnum)
continue; // no points on back continue; // no points on back
if (options.visdist.value() > 0) { if (options.visdist.value() > 0) {
if (tp->winding->distFromPortal(p) > options.visdist.value() || if (tp->winding.distFromPortal(p) > options.visdist.value() ||
p->winding->distFromPortal(tp) > options.visdist.value()) p->winding.distFromPortal(tp) > options.visdist.value())
continue; continue;
} }

View File

@ -63,10 +63,6 @@ void vis_settings::initialize(int argc, const char **argv)
settings::vis_settings options; settings::vis_settings options;
fs::path portalfile, statefile, statetmpfile; fs::path portalfile, statefile, statetmpfile;
struct noop_delete {
void operator()(winding_t *p) const { }
};
/* /*
================== ==================
@ -75,14 +71,12 @@ struct noop_delete {
Return a pointer to a free fixed winding on the stack Return a pointer to a free fixed winding on the stack
================== ==================
*/ */
std::shared_ptr<winding_t> AllocStackWinding(pstack_t *stack) winding_t *AllocStackWinding(pstack_t &stack)
{ {
for (size_t i = 0; i < STACK_WINDINGS; i++) { for (size_t i = 0; i < STACK_WINDINGS; i++) {
if (!stack->windings_used[i]) { if (!stack.windings_used[i]) {
stack->windings_used[i] = true; stack.windings_used[i] = true;
return std::shared_ptr<winding_t>(&stack->windings[i], [stack, i]([[maybe_unused]] winding_t *) { return &stack.windings[i];
stack->windings_used[i] = false;
});
} }
} }
@ -101,11 +95,12 @@ std::shared_ptr<winding_t> AllocStackWinding(pstack_t *stack)
for stack windings is safe for stack windings is safe
================== ==================
*/ */
void FreeStackWinding(std::shared_ptr<winding_t> &w, pstack_t *stack) void FreeStackWinding(winding_t *&w, pstack_t &stack)
{ {
for (size_t i = 0; i < STACK_WINDINGS; i++) { for (size_t i = 0; i < STACK_WINDINGS; i++) {
if (stack->windings_used[i] && &stack->windings[i] == w.get()) { if (stack.windings_used[i] && &stack.windings[i] == w) {
w.reset(); stack.windings_used[i] = false;
w = nullptr;
return; return;
} }
} }
@ -121,7 +116,7 @@ void FreeStackWinding(std::shared_ptr<winding_t> &w, pstack_t *stack)
is returned. is returned.
================== ==================
*/ */
std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, pstack_t *stack, qplane3d *split) winding_t *ClipStackWinding(winding_t *&in, pstack_t &stack, const qplane3d &split)
{ {
vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (in->size() + 1)); vec_t *dists = (vec_t *)alloca(sizeof(vec_t) * (in->size() + 1));
int *sides = (int *)alloca(sizeof(int) * (in->size() + 1)); int *sides = (int *)alloca(sizeof(int) * (in->size() + 1));
@ -129,10 +124,10 @@ std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, psta
int i, j; int i, j;
/* Fast test first */ /* Fast test first */
vec_t dot = split->distance_to(in->origin); vec_t dot = split.distance_to(in->origin);
if (dot < -in->radius) { if (dot < -in->radius) {
FreeStackWinding(in, stack); FreeStackWinding(in, stack);
return NULL; return nullptr;
} else if (dot > in->radius) { } else if (dot > in->radius) {
return in; return in;
} }
@ -144,7 +139,7 @@ std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, psta
/* determine sides for each point */ /* determine sides for each point */
for (i = 0; i < in->size(); i++) { for (i = 0; i < in->size(); i++) {
dot = split->distance_to((*in)[i]); dot = split.distance_to((*in)[i]);
dists[i] = dot; dists[i] = dot;
if (dot > ON_EPSILON) if (dot > ON_EPSILON)
sides[i] = SIDE_FRONT; sides[i] = SIDE_FRONT;
@ -167,7 +162,7 @@ std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, psta
if (!counts[0]) { if (!counts[0]) {
FreeStackWinding(in, stack); FreeStackWinding(in, stack);
return NULL; return nullptr;
} }
if (!counts[1]) if (!counts[1])
return in; return in;
@ -201,10 +196,10 @@ std::shared_ptr<winding_t> ClipStackWinding(std::shared_ptr<winding_t> &in, psta
vec_t fraction = dists[i] / (dists[i] - dists[i + 1]); vec_t fraction = dists[i] / (dists[i] - dists[i + 1]);
for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
/* avoid round off error when possible */ /* avoid round off error when possible */
if (split->normal[j] == 1) if (split.normal[j] == 1)
mid[j] = split->dist; mid[j] = split.dist;
else if (split->normal[j] == -1) else if (split.normal[j] == -1)
mid[j] = -split->dist; mid[j] = -split.dist;
else else
mid[j] = p1[j] + fraction * (p2[j] - p1[j]); mid[j] = p1[j] + fraction * (p2[j] - p1[j]);
} }
@ -279,16 +274,14 @@ portal_t *GetNextPortal(void)
Called with the lock held. Called with the lock held.
============= =============
*/ */
static void UpdateMightsee(const leaf_t *source, const leaf_t *dest) static void UpdateMightsee(const leaf_t &source, const leaf_t &dest)
{ {
int i, leafnum; size_t leafnum = &dest - leafs;
portal_t *p; for (size_t i = 0; i < source.numportals; i++) {
portal_t *p = source.portals[i];
leafnum = dest - leafs; if (p->status != pstat_none) {
for (i = 0; i < source->numportals; i++) {
p = source->portals[i];
if (p->status != pstat_none)
continue; continue;
}
if (p->mightsee[leafnum]) { if (p->mightsee[leafnum]) {
p->mightsee[leafnum] = false; p->mightsee[leafnum] = false;
p->nummightsee--; p->nummightsee--;
@ -312,7 +305,6 @@ static void PortalCompleted(portal_t *completed)
int i, j, k, bit, numblocks; int i, j, k, bit, numblocks;
int leafnum; int leafnum;
const portal_t *p, *p2; const portal_t *p, *p2;
const leaf_t *myleaf;
const uint32_t *might, *vis; const uint32_t *might, *vis;
uint32_t changed; uint32_t changed;
@ -324,9 +316,9 @@ static void PortalCompleted(portal_t *completed)
* For each portal on the leaf, check the leafs we eliminated from * For each portal on the leaf, check the leafs we eliminated from
* mightsee during the full vis so far. * mightsee during the full vis so far.
*/ */
myleaf = &leafs[completed->leaf]; const leaf_t &myleaf = leafs[completed->leaf];
for (i = 0; i < myleaf->numportals; i++) { for (i = 0; i < myleaf.numportals; i++) {
p = myleaf->portals[i]; p = myleaf.portals[i];
if (p->status != pstat_done) if (p->status != pstat_done)
continue; continue;
@ -342,10 +334,10 @@ static void PortalCompleted(portal_t *completed)
* If any of these changed bits are still visible from another * If any of these changed bits are still visible from another
* portal, we can't update yet. * portal, we can't update yet.
*/ */
for (k = 0; k < myleaf->numportals; k++) { for (k = 0; k < myleaf.numportals; k++) {
if (k == i) if (k == i)
continue; continue;
p2 = myleaf->portals[k]; p2 = myleaf.portals[k];
if (p2->status == pstat_done) if (p2->status == pstat_done)
changed &= ~p2->visbits.data()[j]; changed &= ~p2->visbits.data()[j];
else else
@ -361,7 +353,7 @@ static void PortalCompleted(portal_t *completed)
bit = ffsl(changed) - 1; bit = ffsl(changed) - 1;
changed &= ~nth_bit(bit); changed &= ~nth_bit(bit);
leafnum = (j << leafbits_t::shift) + bit; leafnum = (j << leafbits_t::shift) + bit;
UpdateMightsee(leafs + leafnum, myleaf); UpdateMightsee(leafs[leafnum], myleaf);
} }
} }
} }
@ -660,10 +652,11 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
for (i = 0, p = portals; i < numportals; i++) { for (i = 0, p = portals; i < numportals; i++) {
const auto &sourceportal = prtfile.portals[i]; const auto &sourceportal = prtfile.portals[i];
p->winding = std::make_shared<winding_t>(sourceportal.winding.begin(), sourceportal.winding.end()); p->winding = { sourceportal.winding.begin(), sourceportal.winding.end() };
p->winding.SetWindingSphere();
// calc plane // calc plane
plane = p->winding->plane(); plane = p->winding.plane();
// create forward portal // create forward portal
l = &leafs[sourceportal.leafnums[0]]; l = &leafs[sourceportal.leafnums[0]];
@ -674,7 +667,6 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
p->plane = -plane; p->plane = -plane;
p->leaf = sourceportal.leafnums[1]; p->leaf = sourceportal.leafnums[1];
p->winding->SetWindingSphere();
p++; p++;
// create backwards portal // create backwards portal
@ -685,11 +677,10 @@ static void LoadPortals(const fs::path &name, mbsp_t *bsp)
l->numportals++; l->numportals++;
// Create a reverse winding // Create a reverse winding
const auto flipped = sourceportal.winding.flip(); sourceportal.winding.flip_to(p->winding);
p->winding = std::make_shared<winding_t>(flipped.begin(), flipped.end()); p->winding.SetWindingSphere();
p->plane = plane; p->plane = plane;
p->leaf = sourceportal.leafnums[0]; p->leaf = sourceportal.leafnums[0];
p->winding->SetWindingSphere();
p++; p++;
} }