📄 portals.c
字号:
//nudge playerstart around if needed so clipping hulls allways
//have a valid point
if (!strcmp(cl, "info_player_start"))
{
for (x = -16; x <= 16; x += 16)
{
for (y = -16; y <= 16; y += 16)
{
origin[0] += x;
origin[1] += y;
if (PlaceOccupant(headnode, origin, &entities[i]))
{
inside = true;
x = 999; //stop for this info_player_start
break;
} //end if
origin[0] -= x;
origin[1] -= y;
} //end for
} //end for
} //end if
else
{
if (PlaceOccupant(headnode, origin, &entities[i]))
{
inside = true;
} //end if
} //end else
} //end for
if (!inside)
{
Log_Print("WARNING: no entities inside\n");
} //end if
else if (tree->outside_node.occupied)
{
Log_Print("WARNING: entity reached from outside\n");
} //end else if
return (qboolean)(inside && !tree->outside_node.occupied);
} //end of the function FloodEntities
/*
=========================================================
FILL OUTSIDE
=========================================================
*/
int c_outside;
int c_inside;
int c_solid;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FillOutside_r (node_t *node)
{
if (node->planenum != PLANENUM_LEAF)
{
FillOutside_r (node->children[0]);
FillOutside_r (node->children[1]);
return;
} //end if
// anything not reachable by an entity
// can be filled away (by setting solid contents)
if (!node->occupied)
{
if (!(node->contents & CONTENTS_SOLID))
{
c_outside++;
node->contents |= CONTENTS_SOLID;
} //end if
else
{
c_solid++;
} //end else
} //end if
else
{
c_inside++;
} //end else
} //end of the function FillOutside_r
//===========================================================================
// Fill all nodes that can't be reached by entities
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FillOutside (node_t *headnode)
{
c_outside = 0;
c_inside = 0;
c_solid = 0;
Log_Print("------- FillOutside --------\n");
FillOutside_r (headnode);
Log_Print("%5i solid leaves\n", c_solid);
Log_Print("%5i leaves filled\n", c_outside);
Log_Print("%5i inside leaves\n", c_inside);
} //end of the function FillOutside
/*
=========================================================
FLOOD AREAS
=========================================================
*/
int c_areas;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FloodAreas_r (node_t *node)
{
portal_t *p;
int s;
bspbrush_t *b;
entity_t *e;
if (node->contents == CONTENTS_AREAPORTAL)
{
// this node is part of an area portal
b = node->brushlist;
e = &entities[b->original->entitynum];
// if the current area has allready touched this
// portal, we are done
if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas)
return;
// note the current area as bounding the portal
if (e->portalareas[1])
{
Log_Print("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum);
return;
}
if (e->portalareas[0])
e->portalareas[1] = c_areas;
else
e->portalareas[0] = c_areas;
return;
} //end if
if (node->area)
return; // allready got it
node->area = c_areas;
for (p=node->portals ; p ; p = p->next[s])
{
s = (p->nodes[1] == node);
#if 0
if (p->nodes[!s]->occupied)
continue;
#endif
if (!Portal_EntityFlood (p, s))
continue;
FloodAreas_r (p->nodes[!s]);
} //end for
} //end of the function FloodAreas_r
//===========================================================================
// Just decend the tree, and for each node that hasn't had an
// area set, flood fill out from there
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FindAreas_r (node_t *node)
{
if (node->planenum != PLANENUM_LEAF)
{
FindAreas_r (node->children[0]);
FindAreas_r (node->children[1]);
return;
}
if (node->area)
return; // allready got it
if (node->contents & CONTENTS_SOLID)
return;
if (!node->occupied)
return; // not reachable by entities
// area portals are allways only flooded into, never
// out of
if (node->contents == CONTENTS_AREAPORTAL)
return;
c_areas++;
FloodAreas_r (node);
} //end of the function FindAreas_r
//===========================================================================
// Just decend the tree, and for each node that hasn't had an
// area set, flood fill out from there
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void SetAreaPortalAreas_r (node_t *node)
{
bspbrush_t *b;
entity_t *e;
if (node->planenum != PLANENUM_LEAF)
{
SetAreaPortalAreas_r (node->children[0]);
SetAreaPortalAreas_r (node->children[1]);
return;
} //end if
if (node->contents == CONTENTS_AREAPORTAL)
{
if (node->area)
return; // allready set
b = node->brushlist;
e = &entities[b->original->entitynum];
node->area = e->portalareas[0];
if (!e->portalareas[1])
{
Log_Print("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum);
return;
} //end if
} //end if
} //end of the function SetAreaPortalAreas_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
/*
void EmitAreaPortals(node_t *headnode)
{
int i, j;
entity_t *e;
dareaportal_t *dp;
if (c_areas > MAX_MAP_AREAS)
Error ("MAX_MAP_AREAS");
numareas = c_areas+1;
numareaportals = 1; // leave 0 as an error
for (i=1 ; i<=c_areas ; i++)
{
dareas[i].firstareaportal = numareaportals;
for (j=0 ; j<num_entities ; j++)
{
e = &entities[j];
if (!e->areaportalnum)
continue;
dp = &dareaportals[numareaportals];
if (e->portalareas[0] == i)
{
dp->portalnum = e->areaportalnum;
dp->otherarea = e->portalareas[1];
numareaportals++;
} //end if
else if (e->portalareas[1] == i)
{
dp->portalnum = e->areaportalnum;
dp->otherarea = e->portalareas[0];
numareaportals++;
} //end else if
} //end for
dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal;
} //end for
Log_Print("%5i numareas\n", numareas);
Log_Print("%5i numareaportals\n", numareaportals);
} //end of the function EmitAreaPortals
*/
//===========================================================================
// Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FloodAreas (tree_t *tree)
{
Log_Print("--- FloodAreas ---\n");
FindAreas_r (tree->headnode);
SetAreaPortalAreas_r (tree->headnode);
Log_Print("%5i areas\n", c_areas);
} //end of the function FloodAreas
//===========================================================================
// Finds a brush side to use for texturing the given portal
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FindPortalSide (portal_t *p)
{
int viscontents;
bspbrush_t *bb;
mapbrush_t *brush;
node_t *n;
int i,j;
int planenum;
side_t *side, *bestside;
float dot, bestdot;
plane_t *p1, *p2;
// decide which content change is strongest
// solid > lava > water, etc
viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents);
if (!viscontents)
return;
planenum = p->onnode->planenum;
bestside = NULL;
bestdot = 0;
for (j=0 ; j<2 ; j++)
{
n = p->nodes[j];
p1 = &mapplanes[p->onnode->planenum];
for (bb=n->brushlist ; bb ; bb=bb->next)
{
brush = bb->original;
if ( !(brush->contents & viscontents) )
continue;
for (i=0 ; i<brush->numsides ; i++)
{
side = &brush->original_sides[i];
if (side->flags & SFL_BEVEL)
continue;
if (side->texinfo == TEXINFO_NODE)
continue; // non-visible
if ((side->planenum&~1) == planenum)
{ // exact match
bestside = &brush->original_sides[i];
goto gotit;
} //end if
// see how close the match is
p2 = &mapplanes[side->planenum&~1];
dot = DotProduct (p1->normal, p2->normal);
if (dot > bestdot)
{
bestdot = dot;
bestside = side;
} //end if
} //end for
} //end for
} //end for
gotit:
if (!bestside)
Log_Print("WARNING: side not found for portal\n");
p->sidefound = true;
p->side = bestside;
} //end of the function FindPortalSide
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void MarkVisibleSides_r (node_t *node)
{
portal_t *p;
int s;
if (node->planenum != PLANENUM_LEAF)
{
MarkVisibleSides_r (node->children[0]);
MarkVisibleSides_r (node->children[1]);
return;
} //end if
// empty leaves are never boundary leaves
if (!node->contents) return;
// see if there is a visible face
for (p=node->portals ; p ; p = p->next[!s])
{
s = (p->nodes[0] == node);
if (!p->onnode)
continue; // edge of world
if (!p->sidefound)
FindPortalSide (p);
if (p->side)
p->side->flags |= SFL_VISIBLE;
} //end for
} //end of the function MarkVisibleSides_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void MarkVisibleSides(tree_t *tree, int startbrush, int endbrush)
{
int i, j;
mapbrush_t *mb;
int numsides;
Log_Print("--- MarkVisibleSides ---\n");
// clear all the visible flags
for (i=startbrush ; i<endbrush ; i++)
{
mb = &mapbrushes[i];
numsides = mb->numsides;
for (j=0 ; j<numsides ; j++)
mb->original_sides[j].flags &= ~SFL_VISIBLE;
}
// set visible flags on the sides that are used by portals
MarkVisibleSides_r (tree->headnode);
} //end of the function MarkVisibleSides
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -