Skip to content

Commit

Permalink
Refactor: Relocated P_PointInSubsector to GameMap
Browse files Browse the repository at this point in the history
Also renamed it (as SubsectorAtPointXY()) and various other functions
with more semantically correct names.

The broken P_PointInSector() algorithm has been replaced with one
that does not assume Sector = one contiguous polygon.
  • Loading branch information
danij-deng committed Mar 4, 2012
1 parent c154667 commit 76e0404
Show file tree
Hide file tree
Showing 24 changed files with 178 additions and 187 deletions.
2 changes: 1 addition & 1 deletion doomsday/engine/api/doomsday.def
Expand Up @@ -447,6 +447,7 @@ EXPORTS
P_PointOnDivlineSide @62 NONAME
P_InterceptVector @63 NONAME
P_LineOpening @64 NONAME
P_SubsectorAtPointXY @102 NONAME
P_MobjsBoxIterator @346 NONAME
P_LinesBoxIterator @435 NONAME
P_AllLinesBoxIterator @347 NONAME
Expand Down Expand Up @@ -649,7 +650,6 @@ EXPORTS
R_AddAnimGroupFrame @242 NONAME

R_PointToAngle2 @101 NONAME
R_PointInSubsector @102 NONAME
R_HSVToRGB @439 NONAME

R_CreateColorPalette @444 NONAME
Expand Down
4 changes: 3 additions & 1 deletion doomsday/engine/api/doomsday.h
Expand Up @@ -417,12 +417,15 @@ boolean ClMobj_LocalActionsEnabled(struct mobj_s* mo);

int P_PointOnLinedefSide(float xy[2], const struct linedef_s* lineDef);
int P_PointOnLinedefSideXY(float x, float y, const struct linedef_s* lineDef);

int P_BoxOnLineSide(const AABoxf* box, const struct linedef_s* ld);
void P_MakeDivline(struct linedef_s* li, divline_t* dl);
int P_PointOnDivlineSide(float x, float y, const divline_t* line);
float P_InterceptVector(divline_t* v2, divline_t* v1);
void P_LineOpening(struct linedef_s* linedef);

struct subsector_s* P_SubsectorAtPointXY(float x, float y);

// Object in bounding box iterators.
int P_MobjsBoxIterator(const AABoxf* box,
int (*func) (struct mobj_s*, void*),
Expand Down Expand Up @@ -640,7 +643,6 @@ void R_GetColorPaletteRGBf(colorpaletteid_t id, int colorIdx, float rgb[3], bool
void R_HSVToRGB(float* rgb, float h, float s, float v);

angle_t R_PointToAngle2(float x1, float y1, float x2, float y2);
struct subsector_s* R_PointInSubsector(float x, float y);

///@}

Expand Down
15 changes: 15 additions & 0 deletions doomsday/engine/portable/include/gamemap.h
Expand Up @@ -394,4 +394,19 @@ int GameMap_IterateCellPolyobjLineDefs(GameMap* map, const uint coords[2],
int GameMap_IterateCellBlockPolyobjLineDefs(GameMap* map, const GridmapBlock* blockCoords,
int (*callback) (linedef_t*, void*), void* paramaters);

/**
* Determine the BSP leaf (subsector) on the back side of the BS partition that
* lies in front of the specified point within the map's coordinate space.
*
* @note Always returns a valid subsector although the point may not actually lay
* within it (however it is on the same side of the space parition)!
*
* @param map GameMap instance.
* @param x X coordinate of the point to test.
* @param y Y coordinate of the point to test.
* @return Subsector instance for that BSP node's leaf.
*/
subsector_t* GameMap_SubsectorAtPoint(GameMap* map, float point[2]);
subsector_t* GameMap_SubsectorAtPointXY(GameMap* map, float x, float y);

#endif /// LIBDENG_GAMEMAP_H
39 changes: 39 additions & 0 deletions doomsday/engine/portable/include/p_maputil.h
Expand Up @@ -73,6 +73,45 @@ int P_PointOnDivLineSidef(fvertex_t *pnt, fdivline_t *dline);
float P_FloatInterceptVertex(fvertex_t *start, fvertex_t *end,
fdivline_t *fdiv, fvertex_t *inter);
void P_LineOpening(linedef_t* linedef);

/**
* Determine the BSP leaf (subsector) on the back side of the BS partition that
* lies in front of the specified point within the CURRENT map's coordinate space.
*
* @note Always returns a valid subsector although the point may not actually lay
* within it (however it is on the same side of the space parition)!
*
* @param x X coordinate of the point to test.
* @param y Y coordinate of the point to test.
* @return Subsector instance for that BSP node's leaf.
*/
subsector_t* P_SubsectorAtPointXY(float x, float y);

/**
* Is the point inside the sector, according to the edge lines of the subsector.
*
* @param X coordinate to test.
* @param Y coordinate to test.
* @param Sector to test.
*
* @return @c true, if the point is inside the sector.
*/
boolean P_IsPointXYInSector(float x, float y, const sector_t* sector);

/**
* Is the point inside the subsector, according to the edge lines of the subsector.
*
* @algorithm Uses the well-known algorithm described here:
* http://www.alienryderflex.com/polygon/
*
* @param x X coordinate to test.
* @param y Y coordinate to test.
* @param subsector Subsector to test.
*
* @return @c true, if the point is inside the subsector.
*/
boolean P_IsPointXYInSubsector(float x, float y, const subsector_t* subsector);

void P_MobjLink(mobj_t* mo, byte flags);
int P_MobjUnlink(mobj_t* mo);

Expand Down
10 changes: 2 additions & 8 deletions doomsday/engine/portable/include/r_util.h
Expand Up @@ -31,20 +31,14 @@

#include "m_vector.h"

int R_PointOnSide(const float x, const float y,
int P_PointOnPartitionSide(const float x, const float y,
const partition_t* par);
angle_t R_PointToAngle(float x, float y);
angle_t R_PointToAngle2(float x1, float y1,
float x2, float y2);
float R_PointToDist(const float x, const float y);
linedef_t* R_GetLineForSide(const uint sideIDX);
subsector_t* R_PointInSubsector(const float x, const float y);
boolean R_IsPointInSector(const float x, const float y,
const sector_t* sector);
boolean R_IsPointInSector2(const float x, const float y,
const sector_t* sector);
boolean R_IsPointInSubsector(const float x, const float y,
const subsector_t* subsector);

sector_t* R_GetSectorForOrigin(const void* ddMobjBase);

/**
Expand Down
2 changes: 1 addition & 1 deletion doomsday/engine/portable/src/cl_player.c
Expand Up @@ -356,7 +356,7 @@ void ClPlayer_MoveLocal(float dx, float dy, float z, boolean onground)
P_MobjLink(mo, DDLINK_SECTOR | DDLINK_BLOCKMAP);
}

mo->subsector = R_PointInSubsector(mo->pos[VX], mo->pos[VY]);
mo->subsector = P_SubsectorAtPointXY(mo->pos[VX], mo->pos[VY]);
mo->floorZ = mo->subsector->sector->SP_floorheight;
mo->ceilingZ = mo->subsector->sector->SP_ceilheight;

Expand Down
2 changes: 1 addition & 1 deletion doomsday/engine/portable/src/edit_bias.c
Expand Up @@ -753,7 +753,7 @@ static void SBE_DrawLevelGauge(const Point2Raw* origin, int height)
else
src = SBE_GetNearest();

ssec = R_PointInSubsector(src->pos[VX], src->pos[VY]);
ssec = P_SubsectorAtPointXY(src->pos[VX], src->pos[VY]);
if(!ssec) return;

sector = ssec->sector;
Expand Down
36 changes: 35 additions & 1 deletion doomsday/engine/portable/src/gamemap.c
Expand Up @@ -272,7 +272,7 @@ static void initPolyobj(polyobj_t* po)
}
V2_Scale(avg, 1.f / po->lineCount);

ssec = R_PointInSubsector(avg[VX], avg[VY]);
ssec = P_SubsectorAtPointXY(avg[VX], avg[VY]);
if(ssec)
{
if(ssec->polyObj)
Expand Down Expand Up @@ -853,3 +853,37 @@ int GameMap_IterateCellBlockPolyobjLineDefs(GameMap* map, const GridmapBlock* bl
return Blockmap_IterateCellBlockObjects(map->polyobjBlockmap, blockCoords,
blockmapCellPolyobjsIterator, (void*) &args);
}

subsector_t* GameMap_SubsectorAtPoint(GameMap* map, float point_[2])
{
node_t* node = 0;
uint nodenum = 0;
float point[2];

point[0] = point_? point_[0] : 0;
point[1] = point_? point_[1] : 0;

// single subsector is a special case
if(!map->numNodes)
{
return (subsector_t*) map->subsectors;
}

nodenum = map->numNodes - 1;
while(!(nodenum & NF_SUBSECTOR))
{
node = map->nodes + nodenum;
ASSERT_DMU_TYPE(node, DMU_NODE);
nodenum = node->children[P_PointOnPartitionSide(point[0], point[1], &node->partition)];
}

return map->subsectors + (nodenum & ~NF_SUBSECTOR);
}

subsector_t* GameMap_SubsectorAtPointXY(GameMap* map, float x, float y)
{
float point[2];
point[0] = x;
point[1] = y;
return GameMap_SubsectorAtPoint(map, point);
}
49 changes: 47 additions & 2 deletions doomsday/engine/portable/src/p_maputil.c
Expand Up @@ -509,6 +509,51 @@ void P_LineOpening(linedef_t* linedef)
openrange = opentop - openbottom;
}

/// @note Part of the Doomsday public API
subsector_t* P_SubsectorAtPointXY(float x, float y)
{
if(theMap)
{
return GameMap_SubsectorAtPointXY(theMap, x, y);
}
return NULL;
}

boolean P_IsPointXYInSubsector(float x, float y, const subsector_t* ssec)
{
fvertex_t* vi, *vj;
uint i;

if(!ssec) return false; // I guess?

for(i = 0; i < ssec->hedgeCount; ++i)
{
vi = &ssec->hedges[i]->HE_v1->v;
vj = &ssec->hedges[(i + 1) % ssec->hedgeCount]->HE_v1->v;

if(((vi->pos[VY] - y) * (vj->pos[VX] - vi->pos[VX]) -
(vi->pos[VX] - x) * (vj->pos[VY] - vi->pos[VY])) < 0)
{
// Outside the subsector's edges.
return false;
}
}

return true;
}

boolean P_IsPointXYInSector(float x, float y, const sector_t* sector)
{
subsector_t* ssec;
if(!sector) return false; // I guess?

/// @fixme Do not assume @a sector is from the current map.
ssec = GameMap_SubsectorAtPointXY(theMap, x, y);
if(ssec->sector != sector) return false;

return P_IsPointXYInSubsector(x, y, ssec);
}

/**
* Two links to update:
* 1) The link to us from the previous node (sprev, always set) will
Expand Down Expand Up @@ -671,7 +716,7 @@ void P_MobjLink(mobj_t* mo, byte flags)
sector_t* sec;

// Link into the sector.
mo->subsector = R_PointInSubsector(mo->pos[VX], mo->pos[VY]);
mo->subsector = P_SubsectorAtPointXY(mo->pos[VX], mo->pos[VY]);
sec = mo->subsector->sector;

if(flags & DDLINK_SECTOR)
Expand Down Expand Up @@ -715,7 +760,7 @@ void P_MobjLink(mobj_t* mo, byte flags)
ddplayer_t* player = mo->dPlayer;

player->inVoid = true;
if(R_IsPointInSector2(player->mo->pos[VX],
if(P_IsPointXYInSector(player->mo->pos[VX],
player->mo->pos[VY],
player->mo->subsector->sector) &&
(player->mo->pos[VZ] < player->mo->subsector->sector->SP_ceilvisheight + 4 &&
Expand Down
8 changes: 4 additions & 4 deletions doomsday/engine/portable/src/p_particle.c
Expand Up @@ -811,7 +811,7 @@ static void P_NewParticle(ptcgen_t* gen)
float y =
(bbox[BOXBOTTOM] + RNG_RandFloat() * (bbox[BOXTOP] - bbox[BOXBOTTOM]));

subsec = R_PointInSubsector(x, y);
subsec = P_SubsectorAtPointXY(x, y);

if(subsec->sector == sector)
break;
Expand All @@ -832,7 +832,7 @@ static void P_NewParticle(ptcgen_t* gen)
pt->pos[VX] = FLT2FIX(x);
pt->pos[VY] = FLT2FIX(y);

if(R_PointInSubsector(x, y) == subsec)
if(P_SubsectorAtPointXY(x, y) == subsec)
break; // This is a good place.
}

Expand Down Expand Up @@ -861,7 +861,7 @@ static void P_NewParticle(ptcgen_t* gen)
if(gen->plane)
pt->sector = gen->plane->sector;
else
pt->sector = R_PointInSubsector(FIX2FLT(pt->pos[VX]),
pt->sector = P_SubsectorAtPointXY(FIX2FLT(pt->pos[VX]),
FIX2FLT(pt->pos[VY]))->sector;

// Play a stage sound?
Expand Down Expand Up @@ -1348,7 +1348,7 @@ static void P_MoveParticle(ptcgen_t* gen, particle_t* pt)

// Should we update the sector pointer?
if(tmcross)
pt->sector = R_PointInSubsector(FIX2FLT(x), FIX2FLT(y))->sector;
pt->sector = P_SubsectorAtPointXY(FIX2FLT(x), FIX2FLT(y))->sector;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions doomsday/engine/portable/src/p_sight.c
Expand Up @@ -245,12 +245,12 @@ static boolean crossBSPNode(unsigned int bspNum, losdata_t* los)
while(!(bspNum & NF_SUBSECTOR))
{
const node_t* node = &nodes[bspNum];
int side = R_PointOnSide(
int side = P_PointOnPartitionSide(
FIX2FLT(los->trace.pos[VX]), FIX2FLT(los->trace.pos[VY]),
&node->partition);

// Would the trace completely cross this partition?
if(side == R_PointOnSide(los->to[VX], los->to[VY],
if(side == P_PointOnPartitionSide(los->to[VX], los->to[VY],
&node->partition))
{ // Yes, decend!
bspNum = node->children[side];
Expand Down
8 changes: 4 additions & 4 deletions doomsday/engine/portable/src/r_lgrid.c
Expand Up @@ -309,8 +309,8 @@ void LG_InitForMap(void)
sample.pos[VY] = lgOrigin[VY] + off[VY] + samplePoints[0].pos[VY];

ssamples[idx] =
R_PointInSubsector(sample.pos[VX], sample.pos[VY])->sector;
if(!R_IsPointInSector2(sample.pos[VX], sample.pos[VY], ssamples[idx]))
P_SubsectorAtPointXY(sample.pos[VX], sample.pos[VY])->sector;
if(!P_IsPointXYInSector(sample.pos[VX], sample.pos[VY], ssamples[idx]))
ssamples[idx] = NULL;

n++; // Offset the index in the samplePoints array bellow.
Expand Down Expand Up @@ -358,8 +358,8 @@ void LG_InitForMap(void)
sample.pos[VY] = lgOrigin[VY] + off[VY] + samplePoints[n].pos[VY];

ssamples[idx] =
R_PointInSubsector(sample.pos[VX], sample.pos[VY])->sector;
if(!R_IsPointInSector2(sample.pos[VX], sample.pos[VY], ssamples[idx]))
P_SubsectorAtPointXY(sample.pos[VX], sample.pos[VY])->sector;
if(!P_IsPointXYInSector(sample.pos[VX], sample.pos[VY], ssamples[idx]))
ssamples[idx] = NULL;
}
}
Expand Down

0 comments on commit 76e0404

Please sign in to comment.