Skip to content

Commit

Permalink
Added: Console variable "game-mobj-fracepsilon" (default: 0)
Browse files Browse the repository at this point in the history
The original Doom playsim logic used 16.16 fixed-point numbers,
which meant that there was a fixed (but universally constant) limit
on number precision.

Doomsday has been switched to using floating point coordinates.
However, floats can represent values with much higher precision.
This leads to behavioral discrepancies when compared to the
original logic.

This commit adds a FRACEPSILON constant for use with float
comparisons to match the precision of 16.16 fixed point values.
When the "game-mobj-fracepsilon" cvar is set to 1, mobj collision
tests are carried out so that FRACEPSILON is taken into consideration.

This fixes the problem in Doom E1M7 where a pillar doesn't lower
when the player crosses the trigger because the mobjs on the pillar
are placed so that their bounding boxes just touch the walls of the
sector.

"game-mobj-fracepsilon" presently defaults to zero.
  • Loading branch information
skyjake committed Feb 15, 2012
1 parent c81bd0e commit 30cfa18
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 30 deletions.
44 changes: 20 additions & 24 deletions doomsday/engine/api/dd_share.h
Expand Up @@ -147,24 +147,6 @@ float FloatSwap(float);
#define ULONG(x) ((uint32_t) LONG(x))
///@}

#define MAX_OF(x, y) ((x) > (y)? (x) : (y))
#define MIN_OF(x, y) ((x) < (y)? (x) : (y))
#define MINMAX_OF(a, x, b) ((x) < (a)? (a) : (x) > (b)? (b) : (x))
#define SIGN_OF(x) ((x) > 0? +1 : (x) < 0? -1 : 0)
#define INRANGE_OF(x, y, r) ((x) >= (y) - (r) && (x) <= (y) + (r))
#define FEQUAL(x, y) (INRANGE_OF(x, y, .000001f))
#define ROUND(x) ((int) (((x) < 0.0f)? ((x) - 0.5f) : ((x) + 0.5f)))
#define ABS(x) ((x) >= 0 ? (x) : -(x))
/// Ceiling of integer quotient of @a a divided by @a b.
#define CEILING(a, b) ((a) % (b) == 0 ? (a)/(b) : (a)/(b)+1)

/**
* Used to replace /255 as *reciprocal255 is less expensive with CPU cycles.
* Note that this should err on the side of being < 1/255 to prevent result
* exceeding 255 (e.g. 255 * reciprocal255).
*/
#define reciprocal255 0.003921568627f

/// Value types.
typedef enum {
DDVT_NONE = -1, ///< Not a read/writeable value type.
Expand Down Expand Up @@ -388,19 +370,33 @@ typedef struct gameinfo_s {
#define RF_FOUND 0x2 ///< Resource has been located.
///@}

//------------------------------------------------------------------------
//
// Fixed-Point Math
//
//------------------------------------------------------------------------

/**
* @defgroup math Math Routines
* @ingroup base
*/
///@{
#define FRACBITS 16
#define FRACUNIT (1<<FRACBITS)
#define FRACEPSILON (1.0f/65535.f) // ~ 1.5e-5

#define MAX_OF(x, y) ((x) > (y)? (x) : (y))
#define MIN_OF(x, y) ((x) < (y)? (x) : (y))
#define MINMAX_OF(a, x, b) ((x) < (a)? (a) : (x) > (b)? (b) : (x))
#define SIGN_OF(x) ((x) > 0? +1 : (x) < 0? -1 : 0)
#define INRANGE_OF(x, y, r) ((x) >= (y) - (r) && (x) <= (y) + (r))
#define FEQUAL(x, y) (INRANGE_OF(x, y, FRACEPSILON))
#define ROUND(x) ((int) (((x) < 0.0f)? ((x) - 0.5f) : ((x) + 0.5f)))
#define ABS(x) ((x) >= 0 ? (x) : -(x))

/// Ceiling of integer quotient of @a a divided by @a b.
#define CEILING(a, b) ((a) % (b) == 0 ? (a)/(b) : (a)/(b)+1)

/**
* Used to replace /255 as *reciprocal255 is less expensive with CPU cycles.
* Note that this should err on the side of being < 1/255 to prevent result
* exceeding 255 (e.g. 255 * reciprocal255).
*/
#define reciprocal255 0.003921568627f

#define FINEANGLES 8192
#define FINEMASK (FINEANGLES-1)
Expand Down
2 changes: 2 additions & 0 deletions doomsday/plugins/common/src/g_game.c
Expand Up @@ -450,6 +450,8 @@ void G_Register(void)

for(i = 0; gameCmds[i].name; ++i)
Con_AddCommand(gameCmds + i);

C_VAR_BYTE("game-mobj-fracepsilon", &cfg.fracEpsilonForCollisions, 0, 0, 1);
}

boolean G_QuitInProgress(void)
Expand Down
15 changes: 9 additions & 6 deletions doomsday/plugins/common/src/p_map.c
Expand Up @@ -457,6 +457,7 @@ int PIT_CheckThing(mobj_t* thing, void* data)
#if !__JHEXEN__
boolean overlap = false;
#endif
const float EPSILON = (cfg.fracEpsilonForCollisions? FRACEPSILON : 0);

// Don't clip against self.
if(thing == tmThing)
Expand Down Expand Up @@ -486,8 +487,9 @@ int PIT_CheckThing(mobj_t* thing, void* data)
#endif

blockdist = thing->radius + tmThing->radius;
if(fabs(thing->pos[VX] - tm[VX]) >= blockdist ||
fabs(thing->pos[VY] - tm[VY]) >= blockdist)
// floating point: f-EPSILON > g <==> fixed point: f >= g
if(fabs(thing->pos[VX] - tm[VX]) - EPSILON > blockdist ||
fabs(thing->pos[VY] - tm[VY]) - EPSILON > blockdist)
return false; // Didn't hit thing.

if(IS_CLIENT)
Expand Down Expand Up @@ -1122,6 +1124,7 @@ boolean P_CheckPosition3f(mobj_t* thing, float x, float y, float z)
{
sector_t* newSec;
AABoxf tmBoxExpanded;
const float EPSILON = (cfg.fracEpsilonForCollisions? FRACEPSILON : 0);

tmThing = thing;

Expand All @@ -1139,10 +1142,10 @@ boolean P_CheckPosition3f(mobj_t* thing, float x, float y, float z)
tm[VY] = y;
tm[VZ] = z;

tmBox.minX = tm[VX] - tmThing->radius;
tmBox.minY = tm[VY] - tmThing->radius;
tmBox.maxX = tm[VX] + tmThing->radius;
tmBox.maxY = tm[VY] + tmThing->radius;
tmBox.minX = tm[VX] - tmThing->radius + EPSILON;
tmBox.minY = tm[VY] - tmThing->radius + EPSILON;
tmBox.maxX = tm[VX] + tmThing->radius - EPSILON;
tmBox.maxY = tm[VY] + tmThing->radius - EPSILON;

newSec = P_GetPtrp(R_PointInSubsector(tm[VX], tm[VY]), DMU_SECTOR);

Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/jdoom/include/d_config.h
Expand Up @@ -163,6 +163,7 @@ typedef struct jdoom_config_s {
byte fallOff; // Objects fall under their own weight.
byte fixOuchFace;
byte fixStatusbarOwnedWeapons;
byte fracEpsilonForCollisions;

byte hudShownCheatCounters;
float hudCheatCounterScale;
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/jdoom64/include/d_config.h
Expand Up @@ -158,6 +158,7 @@ typedef struct jdoom64_config_s {
byte wallRunNorthOnly; // If handle large make exception for wallrunning
byte zombiesCanExit; // Zombie players can exit maps.
byte fallOff; // Objects fall under their own weight.
byte fracEpsilonForCollisions;

byte hudShownCheatCounters;
float hudCheatCounterScale;
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/jheretic/include/h_config.h
Expand Up @@ -160,6 +160,7 @@ typedef struct jheretic_config_s {
byte fallOff; // Objects fall under their own weight.
byte fixFloorFire; // Fix Heretic bug; explode Maulotaur floor fire when feetclipped.
byte fixPlaneScrollMaterialsEastOnly; // Fix Heretic bug; plane materials would only scroll east.
byte fracEpsilonForCollisions;

byte hudShownCheatCounters;
float hudCheatCounterScale;
Expand Down
2 changes: 2 additions & 0 deletions doomsday/plugins/jhexen/include/x_config.h
Expand Up @@ -116,6 +116,8 @@ typedef struct {
byte weaponNextMode; // if true use the weaponOrder for next/previous.
float filterStrength;

byte fracEpsilonForCollisions;

byte hudShownCheatCounters;
float hudCheatCounterScale;
byte hudCheatCounterShowWithAutomap; ///< Only show when the automap is open.
Expand Down

0 comments on commit 30cfa18

Please sign in to comment.