gzdoom/src/r_interpolate.cpp

450 lines
12 KiB
C++
Raw Normal View History

- Changed: The texture loader now looks for a TEXTURES lump for text based texture definitions. HIRESTEX is still supported but deprecated. - Removed all 16 bit values from texture manager. - Changed: The texture manager now sorts all textures for a WAD by type to avoid priority issues with HIRESTEX defined textures. - Changed sidedef flag WALLF_ADDTRANS into a linedef flag because it is always the same for both sides of a linedef. This also makes handling this in the UDMF parser easier because the linedef parsing function does not need to access the sidedef data. - Added new ZDoom specific UDMF linedef and sidedef properties to map parser. - Added new ZDoom specific UDMF sector properties to map parser. - Added class definitions for new interpolators that are better equipped to interact with the interpolated objects. - Separated interpolation code into its own file r_interpolate.cpp. - Added some simple customization options to the end game screens. - Fixed: Polyobject detection in the internal node builder did not work anymore due to some code rearrangement for UDMF map loading. To keep it compatible between all map formats the THINGS lump of binary format maps must be loaded before building the nodes. This also means that the spawning itself can be done in the same function for all map types (except Build) now. - Changed 'Smooth mouse movement' menu option from m_filter to smooth_mouse which is more what would be expected from this option. - Fixed: Weapons and ammo items that were modified by Dehacked gave full ammo when being dropped by monsters. To properly handle this the handling of spawning Dehacked modified pickups was changed to use the DECORATE replacement feature instead of hacking the spawn state of the original item and calling a spawn function from there. SVN r1001 (trunk)
2008-05-30 06:56:50 +00:00
// Stuff from BUILD to interpolate floors and ceilings
//
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
// This code has been modified from its original form.
#include "r_data.h"
#include "p_3dmidtex.h"
#include "stats.h"
struct FActiveInterpolation
{
FActiveInterpolation *Next;
void *Address;
EInterpType Type;
friend FArchive &operator << (FArchive &arc, FActiveInterpolation *&interp);
static int CountInterpolations ();
static int CountInterpolations (int *usedbuckets, int *minbucketfill, int *maxbucketfill);
private:
fixed_t oldipos[2], bakipos[2];
void CopyInterpToOld();
void CopyBakToInterp();
void DoAnInterpolation(fixed_t smoothratio);
static size_t HashKey(EInterpType type, void *interptr);
static FActiveInterpolation *FindInterpolation(EInterpType, void *interptr, FActiveInterpolation **&interp_p);
friend void updateinterpolations();
friend void setinterpolation(EInterpType, void *interptr, bool dolinks);
friend void stopinterpolation(EInterpType, void *interptr, bool dolinks);
friend void dointerpolations(fixed_t smoothratio);
friend void restoreinterpolations();
friend void clearinterpolations();
friend void SerializeInterpolations(FArchive &arc);
static FActiveInterpolation *curiposhash[INTERPOLATION_BUCKETS];
};
static bool didInterp;
FActiveInterpolation *FActiveInterpolation::curiposhash[INTERPOLATION_BUCKETS];
void FActiveInterpolation::CopyInterpToOld ()
{
switch (Type)
{
case INTERP_SectorFloor:
oldipos[0] = ((sector_t*)Address)->floorplane.d;
oldipos[1] = ((sector_t*)Address)->floortexz;
break;
case INTERP_SectorCeiling:
oldipos[0] = ((sector_t*)Address)->ceilingplane.d;
oldipos[1] = ((sector_t*)Address)->ceilingtexz;
break;
case INTERP_Vertex:
oldipos[0] = ((vertex_t*)Address)->x;
oldipos[1] = ((vertex_t*)Address)->y;
break;
case INTERP_FloorPanning:
oldipos[0] = ((sector_t*)Address)->floor_xoffs;
oldipos[1] = ((sector_t*)Address)->floor_yoffs;
break;
case INTERP_CeilingPanning:
oldipos[0] = ((sector_t*)Address)->ceiling_xoffs;
oldipos[1] = ((sector_t*)Address)->ceiling_yoffs;
break;
case INTERP_WallPanning_Top:
case INTERP_WallPanning_Mid:
case INTERP_WallPanning_Bottom:
oldipos[0] = ((side_t*)Address)->GetTextureYOffset(Type - INTERP_WallPanning_Top);
oldipos[1] = ((side_t*)Address)->GetTextureXOffset(Type - INTERP_WallPanning_Top);
break;
}
}
void FActiveInterpolation::CopyBakToInterp ()
{
switch (Type)
{
case INTERP_SectorFloor:
((sector_t*)Address)->floorplane.d = bakipos[0];
((sector_t*)Address)->floortexz = bakipos[1];
break;
case INTERP_SectorCeiling:
((sector_t*)Address)->ceilingplane.d = bakipos[0];
((sector_t*)Address)->ceilingtexz = bakipos[1];
break;
case INTERP_Vertex:
((vertex_t*)Address)->x = bakipos[0];
((vertex_t*)Address)->y = bakipos[1];
break;
case INTERP_FloorPanning:
((sector_t*)Address)->floor_xoffs = bakipos[0];
((sector_t*)Address)->floor_yoffs = bakipos[1];
break;
case INTERP_CeilingPanning:
((sector_t*)Address)->ceiling_xoffs = bakipos[0];
((sector_t*)Address)->ceiling_yoffs = bakipos[1];
break;
case INTERP_WallPanning_Top:
case INTERP_WallPanning_Mid:
case INTERP_WallPanning_Bottom:
((side_t*)Address)->SetTextureYOffset(Type - INTERP_WallPanning_Top, bakipos[0]);
((side_t*)Address)->SetTextureXOffset(Type - INTERP_WallPanning_Top, bakipos[1]);
break;
}
}
void FActiveInterpolation::DoAnInterpolation (fixed_t smoothratio)
{
fixed_t *adr1, *adr2, pos;
int v1, v2;
switch (Type)
{
case INTERP_SectorFloor:
adr1 = &((sector_t*)Address)->floorplane.d;
adr2 = &((sector_t*)Address)->floortexz;
break;
case INTERP_SectorCeiling:
adr1 = &((sector_t*)Address)->ceilingplane.d;
adr2 = &((sector_t*)Address)->ceilingtexz;
break;
case INTERP_Vertex:
adr1 = &((vertex_t*)Address)->x;
adr2 = &((vertex_t*)Address)->y;
break;
case INTERP_FloorPanning:
adr1 = &((sector_t*)Address)->floor_xoffs;
adr2 = &((sector_t*)Address)->floor_yoffs;
break;
case INTERP_CeilingPanning:
adr1 = &((sector_t*)Address)->ceiling_xoffs;
adr2 = &((sector_t*)Address)->ceiling_yoffs;
break;
case INTERP_WallPanning_Top:
case INTERP_WallPanning_Mid:
case INTERP_WallPanning_Bottom:
v1 = ((side_t*)Address)->GetTextureYOffset(Type - INTERP_WallPanning_Top);
v2 = ((side_t*)Address)->GetTextureXOffset(Type - INTERP_WallPanning_Top);
adr1 = &v1;
adr2 = &v2;
break;
default:
return;
}
pos = bakipos[0] = *adr1;
*adr1 = oldipos[0] + FixedMul (pos - oldipos[0], smoothratio);
pos = bakipos[1] = *adr2;
*adr2 = oldipos[1] + FixedMul (pos - oldipos[1], smoothratio);
switch (Type)
{
case INTERP_WallPanning_Top:
case INTERP_WallPanning_Mid:
case INTERP_WallPanning_Bottom:
((side_t*)Address)->SetTextureYOffset(Type - INTERP_WallPanning_Top, v1);
((side_t*)Address)->SetTextureXOffset(Type - INTERP_WallPanning_Top, v2);
break;
default:
return;
}
}
size_t FActiveInterpolation::HashKey (EInterpType type, void *interptr)
{
return (size_t)type * ((size_t)interptr>>5);
}
int FActiveInterpolation::CountInterpolations ()
{
int d1, d2, d3;
return CountInterpolations (&d1, &d2, &d3);
}
int FActiveInterpolation::CountInterpolations (int *usedbuckets, int *minbucketfill, int *maxbucketfill)
{
int count = 0;
int inuse = 0;
int minuse = INT_MAX;
int maxuse = INT_MIN;
for (int i = INTERPOLATION_BUCKETS-1; i >= 0; --i)
{
int use = 0;
FActiveInterpolation *probe = FActiveInterpolation::curiposhash[i];
if (probe != NULL)
{
inuse++;
}
while (probe != NULL)
{
count++;
use++;
probe = probe->Next;
}
if (use > 0 && use < minuse)
{
minuse = use;
}
if (use > maxuse)
{
maxuse = use;
}
}
*usedbuckets = inuse;
*minbucketfill = minuse == INT_MAX ? 0 : minuse;
*maxbucketfill = maxuse;
return count;
}
FActiveInterpolation *FActiveInterpolation::FindInterpolation (EInterpType type, void *interptr, FActiveInterpolation **&interp_p)
{
size_t hash = HashKey (type, interptr) % INTERPOLATION_BUCKETS;
FActiveInterpolation *probe, **probe_p;
for (probe_p = &curiposhash[hash], probe = *probe_p;
probe != NULL;
probe_p = &probe->Next, probe = *probe_p)
{
if (probe->Address > interptr)
{ // We passed the place it would have been, so it must not be here.
probe = NULL;
break;
}
if (probe->Address == interptr && probe->Type == type)
{ // Found it.
break;
}
}
interp_p = probe_p;
return probe;
}
void clearinterpolations()
{
for (int i = INTERPOLATION_BUCKETS-1; i >= 0; --i)
{
for (FActiveInterpolation *probe = FActiveInterpolation::curiposhash[i];
probe != NULL; )
{
FActiveInterpolation *next = probe->Next;
delete probe;
probe = next;
}
FActiveInterpolation::curiposhash[i] = NULL;
}
}
void updateinterpolations() //Stick at beginning of domovethings
{
for (int i = INTERPOLATION_BUCKETS-1; i >= 0; --i)
{
for (FActiveInterpolation *probe = FActiveInterpolation::curiposhash[i];
probe != NULL; probe = probe->Next)
{
probe->CopyInterpToOld ();
}
}
}
void setinterpolation(EInterpType type, void *posptr, bool dolinks)
{
FActiveInterpolation **interp_p;
FActiveInterpolation *interp = FActiveInterpolation::FindInterpolation (type, posptr, interp_p);
if (interp != NULL) return; // It's already active
interp = new FActiveInterpolation;
interp->Type = type;
interp->Address = posptr;
interp->Next = *interp_p;
*interp_p = interp;
interp->CopyInterpToOld ();
if (dolinks)
{
if (type == INTERP_SectorFloor)
{
P_Start3dMidtexInterpolations((sector_t*)posptr, false);
P_StartLinkedSectorInterpolations((sector_t*)posptr, false);
}
else if (type == INTERP_SectorCeiling)
{
P_Start3dMidtexInterpolations((sector_t*)posptr, true);
P_StartLinkedSectorInterpolations((sector_t*)posptr, true);
}
}
}
void stopinterpolation(EInterpType type, void *posptr, bool dolinks)
{
FActiveInterpolation **interp_p;
FActiveInterpolation *interp = FActiveInterpolation::FindInterpolation (type, posptr, interp_p);
if (interp != NULL)
{
*interp_p = interp->Next;
delete interp;
if (dolinks)
{
if (type == INTERP_SectorFloor)
{
P_Stop3dMidtexInterpolations((sector_t*)posptr, false);
P_StopLinkedSectorInterpolations((sector_t*)posptr, false);
}
else if (type == INTERP_SectorCeiling)
{
P_Stop3dMidtexInterpolations((sector_t*)posptr, true);
P_StopLinkedSectorInterpolations((sector_t*)posptr, true);
}
}
}
}
void dointerpolations(fixed_t smoothratio) //Stick at beginning of drawscreen
{
if (smoothratio == FRACUNIT)
{
didInterp = false;
return;
}
didInterp = true;
for (int i = INTERPOLATION_BUCKETS-1; i >= 0; --i)
{
for (FActiveInterpolation *probe = FActiveInterpolation::curiposhash[i];
probe != NULL; probe = probe->Next)
{
probe->DoAnInterpolation (smoothratio);
}
}
}
void restoreinterpolations() //Stick at end of drawscreen
{
if (didInterp)
{
didInterp = false;
for (int i = INTERPOLATION_BUCKETS-1; i >= 0; --i)
{
for (FActiveInterpolation *probe = FActiveInterpolation::curiposhash[i];
probe != NULL; probe = probe->Next)
{
probe->CopyBakToInterp ();
}
}
}
}
void SerializeInterpolations (FArchive &arc)
{
FActiveInterpolation *interp;
int numinterpolations;
int i;
if (arc.IsStoring ())
{
numinterpolations = FActiveInterpolation::CountInterpolations();
arc.WriteCount (numinterpolations);
for (i = INTERPOLATION_BUCKETS-1; i >= 0; --i)
{
for (interp = FActiveInterpolation::curiposhash[i];
interp != NULL; interp = interp->Next)
{
arc << interp;
}
}
}
else
{
clearinterpolations ();
numinterpolations = arc.ReadCount ();
for (i = numinterpolations; i > 0; --i)
{
FActiveInterpolation **interp_p;
arc << interp;
if (FActiveInterpolation::FindInterpolation (interp->Type, interp->Address, interp_p) == NULL)
{ // Should always return NULL, because there should never be any duplicates stored.
interp->Next = *interp_p;
*interp_p = interp;
}
}
}
}
FArchive &operator << (FArchive &arc, FActiveInterpolation *&interp)
{
BYTE type;
union
{
vertex_t *vert;
sector_t *sect;
side_t *side;
void *ptr;
} ptr;
if (arc.IsStoring ())
{
type = interp->Type;
ptr.ptr = interp->Address;
arc << type;
switch (type)
{
case INTERP_Vertex: arc << ptr.vert; break;
case INTERP_WallPanning_Top:
case INTERP_WallPanning_Mid:
case INTERP_WallPanning_Bottom:
arc << ptr.side; break;
default: arc << ptr.sect; break;
}
}
else
{
interp = new FActiveInterpolation;
arc << type;
interp->Type = (EInterpType)type;
switch (type)
{
case INTERP_Vertex: arc << ptr.vert; break;
case INTERP_WallPanning_Top:
case INTERP_WallPanning_Mid:
case INTERP_WallPanning_Bottom:
arc << ptr.side; break;
default: arc << ptr.sect; break;
}
interp->Address = ptr.ptr;
}
return arc;
}
ADD_STAT (interpolations)
{
int inuse, minuse, maxuse, total;
FString out;
total = FActiveInterpolation::CountInterpolations (&inuse, &minuse, &maxuse);
out.Format ("%d interpolations buckets:%3d min:%3d max:%3d avg:%3d %d%% full %d%% buckfull",
total, inuse, minuse, maxuse, inuse?total/inuse:0, total*100/INTERPOLATION_BUCKETS, inuse*100/INTERPOLATION_BUCKETS);
return out;
}