mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 23:32:02 +00:00
450 lines
12 KiB
C++
450 lines
12 KiB
C++
|
// 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;
|
||
|
}
|