620 lines
23 KiB
C
620 lines
23 KiB
C
// R_plane.c
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include "D_global.h"
|
|
#include "d_disk.h"
|
|
#include "R_refdef.h"
|
|
int backvertex; // the farthest vertex in a tile, whcih is t
|
|
|
|
int ceilingbit; // set to CEILINGBIT when on ceiling, else 0
|
|
|
|
int mr_y, mr_x1, mr_x2; // used by mapplane to calculate texture end
|
|
fixed_t mr_deltaheight; //
|
|
|
|
fixed_t mapcache_height[MAX_VIEW_HEIGHT];
|
|
fixed_t mapcache_pointz[MAX_VIEW_HEIGHT];
|
|
|
|
//
|
|
// vertexes for drawable polygon
|
|
//
|
|
int numvertex;
|
|
int vertexy[10];
|
|
int vertexx[10];
|
|
|
|
//
|
|
// vertexes in need of Z clipping
|
|
//
|
|
clippoint_t vertexpt[10];
|
|
|
|
//
|
|
// coefficients of the plane equation for sloping polygons
|
|
//
|
|
fixed_t planeA, planeB, planeC, planeD;
|
|
|
|
#define COPYFLOOR(s,d) \
|
|
vertexpt[d].tx = vertex[s]->tx; \
|
|
vertexpt[d].ty = vertex[s]->floorheight; \
|
|
vertexpt[d].tz = vertex[s]->tz; \
|
|
vertexpt[d].px = vertex[s]->px; \
|
|
vertexpt[d].py = vertex[s]->floory;
|
|
|
|
#define COPYCEILING(s,d) \
|
|
vertexpt[d].tx = vertex[s]->tx; \
|
|
vertexpt[d].ty = vertex[s]->ceilingheight; \
|
|
vertexpt[d].tz = vertex[s]->tz; \
|
|
vertexpt[d].px = vertex[s]->px; \
|
|
vertexpt[d].py = vertex[s]->ceilingy;
|
|
|
|
|
|
//============================================================
|
|
|
|
/* */
|
|
/*=============== */
|
|
/*= */
|
|
/*= ClearMapCache */
|
|
/*= */
|
|
/*= Invalidates any cached calculations */
|
|
/*= */
|
|
/*=============== */
|
|
/* */
|
|
|
|
void ClearMapCache(void)
|
|
{
|
|
memset(mapcache_height, 0xf0, sizeof(mapcache_height));
|
|
}
|
|
|
|
//=========================================================
|
|
|
|
/* */
|
|
/*================== */
|
|
/*= */
|
|
/*= FlatSpan */
|
|
/*= */
|
|
/*= used for flat floors and ceilings, coordinates must be pre clipped */
|
|
/*= */
|
|
/*= mr_deltaheight is planeheight - viewheight, with height values incre*/
|
|
/*= */
|
|
/*= mr_picture and mr_deltaheight are set once per polygon */
|
|
/*= */
|
|
/*================== */
|
|
/* */
|
|
|
|
void FlatSpan(void)
|
|
{
|
|
fixed_t pointz; // row's distance to view plane
|
|
span_t *span_p;
|
|
unsigned span;
|
|
|
|
#ifdef VALIDATE
|
|
if (numspans==MAXSPANS)
|
|
MS_Error("MAXSPANS exceeded");
|
|
if ((mr_x1<0)||(mr_x2>windowWidth)||(mr_x1>=mr_x2)||(mr_y<0)||(mr_y>=windowWidth))
|
|
MS_Error("Bad MapPlane coordinates");
|
|
#endif
|
|
|
|
//
|
|
// use cached pointz if valid
|
|
//
|
|
if (mapcache_height[mr_y]==mr_deltaheight)
|
|
pointz=mapcache_pointz[mr_y];
|
|
else {
|
|
mapcache_height[mr_y]=mr_deltaheight;
|
|
pointz=mapcache_pointz[mr_y]=FIXEDDIV(mr_deltaheight, yslope[mr_y]);
|
|
}
|
|
if (pointz>MAXZ)
|
|
return;
|
|
//
|
|
// post the span in the draw list
|
|
//
|
|
span=(pointz<<ZTOFRAC)&ZMASK;
|
|
span|=ceilingbit;
|
|
span|=(mr_x1^0x1ff)<<XSHIFT; // invert x1 so they are sorted in ascen
|
|
// while Z is sorted in decending order
|
|
span|=numspans;
|
|
spantags[0][numspans]=span;
|
|
|
|
span_p=&spans[numspans];
|
|
span_p->spantype=sp_flat;
|
|
span_p->picture=mr_picture;
|
|
span_p->x2=mr_x2;
|
|
span_p->y=mr_y;
|
|
|
|
numspans++;
|
|
}
|
|
|
|
//=========================================================
|
|
|
|
/* */
|
|
/*================== */
|
|
/*= */
|
|
/*= SlopeSpan */
|
|
/*= */
|
|
/*= used for sloping floors and ceilings */
|
|
/*= */
|
|
/*= planeA, planeB, planeC, planeD must be precalculated */
|
|
/*= */
|
|
/*= mr_picture is set once per polygon */
|
|
/*= */
|
|
/*================== */
|
|
/* */
|
|
|
|
void SlopeSpan(void)
|
|
{
|
|
fixed_t pointz, pointz2; // row's distance to view plane
|
|
fixed_t partial, denom;
|
|
span_t *span_p;
|
|
unsigned span;
|
|
|
|
#ifdef VALIDATE
|
|
if (numspans==MAXSPANS)
|
|
MS_Error("MAXSPANS exceeded");
|
|
if ((mr_x1<0)||(mr_x2>windowWidth)||(mr_x1>=mr_x2)||(mr_y<0)||(mr_y>=windowWidth))
|
|
MS_Error("Bad MapPlane coordinates");
|
|
#endif
|
|
//
|
|
// calculate the Z values for each end of the span
|
|
//
|
|
partial=FIXEDMUL(planeB, yslope[mr_y])+planeC;
|
|
denom=FIXEDMUL(planeA, xslope[mr_x1])+partial;
|
|
pointz=FIXEDDIV(planeD, denom);
|
|
denom=FIXEDMUL(planeA, xslope[mr_x2])+partial;
|
|
pointz2=FIXEDDIV(planeD, denom);
|
|
|
|
if (pointz>MAXZ||pointz2>MAXZ)
|
|
return;
|
|
|
|
//
|
|
// post the span in the draw list
|
|
//
|
|
span=(pointz<<ZTOFRAC)&ZMASK;
|
|
span|=ceilingbit;
|
|
span|=(mr_x1^0x1ff)<<XSHIFT; // invert x1 so they are sorted in ascen
|
|
// while Z is sorted in decending order
|
|
span|=numspans;
|
|
spantags[0][numspans]=span;
|
|
|
|
span_p=&spans[numspans];
|
|
span_p->spantype=sp_slope;
|
|
span_p->picture=mr_picture;
|
|
span_p->x2=mr_x2;
|
|
span_p->y=mr_y;
|
|
span_p->yh=pointz2;
|
|
|
|
numspans++;
|
|
}
|
|
|
|
//=========================================================
|
|
|
|
/* */
|
|
/*================== */
|
|
/*= */
|
|
/*= RenderPolygon */
|
|
/*= */
|
|
/*= Vertex list must be precliped, convex, and in clockwise order */
|
|
/*= Backfaces (not in clockwise order) generate no pixels */
|
|
/*= */
|
|
/*= The polygon is divided into trapezoids (from 1 to numvertex-1 can be*/
|
|
/*= which have a constant slope on both sides */
|
|
/*= */
|
|
/*= mr_x1 screen coordinates of the span to draw, used by map */
|
|
/*= mr_x2 plane to calculate textures at the endpoints */
|
|
/*= mr_y along with mr_deltaheight */
|
|
/*= */
|
|
/*= mr_dest pointer inside viewbuffer where span starts */
|
|
/*= mr_count length of span to draw (mr_x2 - mr_x1) */
|
|
/*= */
|
|
/*= spanfunction is a pointer to a function that will handle determining*/
|
|
/*= in the calculated span (FlatSpan or SlopeSpan) */
|
|
/*= */
|
|
/*================== */
|
|
/* */
|
|
|
|
void RenderPolygon(void (*spanfunction)(void))
|
|
{
|
|
int stopy;
|
|
fixed_t leftfrac, rightfrac;
|
|
fixed_t leftstep, rightstep;
|
|
int leftvertex, rightvertex;
|
|
int deltax, deltay;
|
|
int oldx;
|
|
|
|
//
|
|
// find topmost vertex
|
|
//
|
|
rightvertex=0; // topmost so far
|
|
for (leftvertex=1; leftvertex<numvertex; leftvertex++)
|
|
if (vertexy[leftvertex]<vertexy[rightvertex])
|
|
rightvertex=leftvertex;
|
|
|
|
//
|
|
// ride down the left and right edges
|
|
//
|
|
leftvertex=rightvertex;
|
|
mr_y=vertexy[rightvertex];
|
|
|
|
if (mr_y>=windowHeight)
|
|
return; // totally off bottom
|
|
|
|
do {
|
|
if (mr_y==vertexy[rightvertex]) {
|
|
skiprightvertex : oldx=vertexx[rightvertex];
|
|
if (++rightvertex==numvertex)
|
|
rightvertex=0;
|
|
deltay=vertexy[rightvertex]-mr_y;
|
|
if (!deltay) {
|
|
if (leftvertex==rightvertex)
|
|
return; // the last edge is exactly horizontal
|
|
goto skiprightvertex;
|
|
}
|
|
deltax=vertexx[rightvertex]-oldx;
|
|
rightfrac=(oldx<<FRACBITS); // fix roundoff
|
|
rightstep=(deltax<<FRACBITS)/deltay;
|
|
}
|
|
if (mr_y==vertexy[leftvertex]) {
|
|
skipleftvertex : oldx=vertexx[leftvertex];
|
|
if (--leftvertex==-1)
|
|
leftvertex=numvertex-1;
|
|
deltay=vertexy[leftvertex]-mr_y;
|
|
if (!deltay)
|
|
goto skipleftvertex;
|
|
deltax=vertexx[leftvertex]-oldx;
|
|
leftfrac=(oldx<<FRACBITS); // fix roundoff
|
|
leftstep=(deltax<<FRACBITS)/deltay;
|
|
}
|
|
if (vertexy[rightvertex]<vertexy[leftvertex])
|
|
stopy=vertexy[rightvertex];
|
|
else
|
|
stopy=vertexy[leftvertex];
|
|
|
|
//
|
|
// draw a trapezoid
|
|
//
|
|
if (stopy<=0) {
|
|
leftfrac+=leftstep *(stopy-mr_y);
|
|
rightfrac+=rightstep *(stopy-mr_y);
|
|
mr_y=stopy;
|
|
continue;
|
|
}
|
|
if (mr_y<0) {
|
|
leftfrac-=leftstep *mr_y;
|
|
rightfrac-=rightstep *mr_y;
|
|
mr_y=0;
|
|
}
|
|
if (stopy>windowHeight)
|
|
stopy=windowHeight;
|
|
|
|
for (; mr_y<stopy; mr_y++) {
|
|
mr_x1=leftfrac>>FRACBITS;
|
|
mr_x2=rightfrac>>FRACBITS;
|
|
if (mr_x1<xclipl)
|
|
mr_x1=xclipl;
|
|
if (mr_x2>xcliph)
|
|
mr_x2=xcliph;
|
|
|
|
if (mr_x1<xcliph&&mr_x2>mr_x1)
|
|
spanfunction(); // different functions for flat and slop
|
|
|
|
leftfrac+=leftstep;
|
|
rightfrac+=rightstep;
|
|
}
|
|
} while ((rightvertex!=leftvertex)&&(mr_y!=windowHeight));
|
|
|
|
}
|
|
|
|
|
|
//============================================================
|
|
|
|
/* */
|
|
/*================== */
|
|
/*= */
|
|
/*= CalcPlaneEquation */
|
|
/*= */
|
|
/*= Calculates planeA, planeB, planeC, planeD */
|
|
/*= planeD is actually -planeD */
|
|
/*= */
|
|
/*= for vertexpt[0-2] */
|
|
/*= */
|
|
/*================== */
|
|
/* */
|
|
|
|
void CalcPlaneEquation(void)
|
|
{
|
|
fixed_t x1, y1, z1;
|
|
fixed_t x2, y2, z2;
|
|
fixed_t check1, check2;
|
|
|
|
//
|
|
// calculate two vectors going away from the middle vertex
|
|
//
|
|
x1=vertexpt[0].tx-vertexpt[1].tx;
|
|
y1=vertexpt[0].ty-vertexpt[1].ty;
|
|
z1=vertexpt[0].tz-vertexpt[1].tz;
|
|
|
|
x2=vertexpt[2].tx-vertexpt[1].tx;
|
|
y2=vertexpt[2].ty-vertexpt[1].ty;
|
|
z2=vertexpt[2].tz-vertexpt[1].tz;
|
|
|
|
//
|
|
// the A, B, C coefficients are the cross product of v1 and v2
|
|
// shift over to save some precision bits
|
|
planeA=(FIXEDMUL(y1, z2)-FIXEDMUL(z1, y2))>>8;
|
|
planeB=(FIXEDMUL(z1, x2)-FIXEDMUL(x1, z2))>>8;
|
|
planeC=(FIXEDMUL(x1, y2)-FIXEDMUL(y1, x2))>>8;
|
|
|
|
//
|
|
// calculate D based on A,B,C and one of the vertex points
|
|
//
|
|
planeD=FIXEDMUL(planeA, vertexpt[0].tx)
|
|
+FIXEDMUL(planeB, vertexpt[0].ty)
|
|
+FIXEDMUL(planeC, vertexpt[0].tz);
|
|
|
|
check1=FIXEDMUL(planeA, vertexpt[1].tx)
|
|
+FIXEDMUL(planeB, vertexpt[1].ty)
|
|
+FIXEDMUL(planeC, vertexpt[1].tz);
|
|
check2=FIXEDMUL(planeA, vertexpt[2].tx)
|
|
+FIXEDMUL(planeB, vertexpt[2].ty)
|
|
+FIXEDMUL(planeC, vertexpt[2].tz);
|
|
}
|
|
|
|
//============================================================
|
|
|
|
/* */
|
|
/*================== */
|
|
/*= */
|
|
/*= ZClipPolygon */
|
|
/*= */
|
|
/*= Returns true if the polygon should be rendered */
|
|
/*= */
|
|
/*================== */
|
|
/* */
|
|
|
|
boolean ZClipPolygon(int numvertexpts, fixed_t minz)
|
|
{
|
|
int v;
|
|
fixed_t scale;
|
|
fixed_t frac, cliptx, clipty;
|
|
clippoint_t *p1, *p2;
|
|
|
|
numvertex=0;
|
|
|
|
if (minz<MINZ) // less than this will cause problems
|
|
minz=MINZ;
|
|
|
|
p1=&vertexpt[0];
|
|
|
|
for (v=1; v<=numvertexpts; v++) {
|
|
p2=p1; // p2 is old point
|
|
if (v!=numvertexpts)
|
|
p1=&vertexpt[v]; // p1 is new point
|
|
else
|
|
p1=&vertexpt[0];
|
|
|
|
if ((p1->tz<minz)^(p2->tz<minz)) {
|
|
scale=FIXEDDIV(SCALE, minz);
|
|
frac=FIXEDDIV((p1->tz-minz), (p1->tz-p2->tz));
|
|
|
|
cliptx=p1->tx+FIXEDMUL((p2->tx-p1->tx), frac);
|
|
clipty=p1->ty+FIXEDMUL((p2->ty-p1->ty), frac);
|
|
|
|
vertexx[numvertex]=CENTERX+(FIXEDMUL(cliptx, scale)>>FRACBITS);
|
|
vertexy[numvertex]=CENTERY-(FIXEDMUL(clipty, scale)>>FRACBITS);
|
|
numvertex++;
|
|
}
|
|
if (p1->tz>=minz) {
|
|
vertexx[numvertex]=p1->px;
|
|
vertexy[numvertex]=p1->py;
|
|
numvertex++;
|
|
}
|
|
}
|
|
if (!numvertex)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//================================================================
|
|
|
|
/* */
|
|
/*==================*/
|
|
/*= */
|
|
/*= RenderTileEnds */
|
|
/*= */
|
|
/*= Draw the floor */
|
|
/*= and ceiling for */
|
|
/*= a tile */
|
|
/*==================*/
|
|
/* */
|
|
|
|
void RenderTileEnds(void)
|
|
{
|
|
int flatpic;
|
|
int flags, polytype;
|
|
|
|
xcliph++; // debug: handle this globally
|
|
flags=mapflags[mapspot];
|
|
|
|
//
|
|
// draw the floor
|
|
//
|
|
flatpic=floorpic[mapspot];
|
|
#ifdef VALIDATE
|
|
if (flatpic>=numflats)
|
|
MS_Error("RenderTileEnds: Invalid floorpic at (%i,%i)", tilex, tiley);
|
|
#endif
|
|
flatpic=flattranslation[flatpic];
|
|
#ifdef VALIDATE
|
|
if (flatpic>=numflats)
|
|
MS_Error("RenderTileEnds: Invalid translated floor");
|
|
#endif
|
|
mr_picture=lumpmain[flatlump+flatpic];
|
|
ceilingbit=0;
|
|
|
|
polytype=(flags&FL_FLOOR)>>FLS_FLOOR;
|
|
switch (polytype) {
|
|
case POLY_FLAT:
|
|
mr_deltaheight=vertex[0]->floorheight;
|
|
if (mr_deltaheight<0) {
|
|
COPYFLOOR(0, 0);
|
|
COPYFLOOR(1, 1);
|
|
COPYFLOOR(2, 2);
|
|
COPYFLOOR(3, 3);
|
|
if (ZClipPolygon(4, -mr_deltaheight))
|
|
RenderPolygon(FlatSpan);
|
|
}
|
|
break;
|
|
|
|
case POLY_SLOPE:
|
|
COPYFLOOR(0, 0);
|
|
COPYFLOOR(1, 1);
|
|
COPYFLOOR(2, 2);
|
|
COPYFLOOR(3, 3);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(4, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
break;
|
|
|
|
case POLY_ULTOLR:
|
|
COPYFLOOR(0, 0);
|
|
COPYFLOOR(1, 1);
|
|
COPYFLOOR(2, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
|
|
COPYFLOOR(2, 0);
|
|
COPYFLOOR(3, 1);
|
|
COPYFLOOR(0, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
break;
|
|
|
|
case POLY_URTOLL:
|
|
COPYFLOOR(0, 0);
|
|
COPYFLOOR(1, 1);
|
|
COPYFLOOR(3, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
|
|
COPYFLOOR(1, 0);
|
|
COPYFLOOR(2, 1);
|
|
COPYFLOOR(3, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
break;
|
|
}
|
|
//
|
|
// draw the ceiling
|
|
//
|
|
|
|
//return; // remove to show ceilings
|
|
|
|
flatpic=ceilingpic[mapspot];
|
|
#ifdef VALIDATE
|
|
if (flatpic>=numflats)
|
|
MS_Error("RenderTileEnds: Invalid ceilingpic at (%i,%i)", tilex,
|
|
tiley);
|
|
#endif
|
|
flatpic=flattranslation[flatpic];
|
|
#ifdef VALIDATE
|
|
if (flatpic>=numflats)
|
|
MS_Error("RenderTileEnds: Invalid ceiling translation for %i",
|
|
flatlump);
|
|
#endif
|
|
mr_picture=lumpmain[flatlump+flatpic];
|
|
|
|
ceilingbit=CEILINGBIT;
|
|
|
|
polytype=(flags&FL_CEILING)>>FLS_CEILING;
|
|
switch (polytype) {
|
|
case POLY_FLAT:
|
|
mr_deltaheight=vertex[0]->ceilingheight;
|
|
if (mr_deltaheight>0) {
|
|
COPYCEILING(3, 0);
|
|
COPYCEILING(2, 1);
|
|
COPYCEILING(1, 2);
|
|
COPYCEILING(0, 3);
|
|
if (ZClipPolygon(4, mr_deltaheight))
|
|
RenderPolygon(FlatSpan);
|
|
}
|
|
break;
|
|
|
|
case POLY_SLOPE:
|
|
COPYCEILING(3, 0);
|
|
COPYCEILING(2, 1);
|
|
COPYCEILING(1, 2);
|
|
COPYCEILING(0, 3);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(4, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
break;
|
|
|
|
case POLY_ULTOLR:
|
|
COPYCEILING(3, 0);
|
|
COPYCEILING(2, 1);
|
|
COPYCEILING(1, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
|
|
COPYCEILING(3, 0);
|
|
COPYCEILING(1, 1);
|
|
COPYCEILING(0, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
break;
|
|
|
|
case POLY_URTOLL:
|
|
COPYCEILING(3, 0);
|
|
COPYCEILING(2, 1);
|
|
COPYCEILING(0, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
|
|
COPYCEILING(2, 0);
|
|
COPYCEILING(1, 1);
|
|
COPYCEILING(0, 2);
|
|
CalcPlaneEquation();
|
|
if (ZClipPolygon(3, MINZ))
|
|
RenderPolygon(SlopeSpan);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//===============================================================
|
|
|
|
/* */
|
|
/*==================== */
|
|
/*= */
|
|
/*= FindBackVertex */
|
|
/*= */
|
|
/*==================== */
|
|
/* */
|
|
|
|
void FindBackVertex(void)
|
|
{
|
|
int v;
|
|
fixed_t greatestz;
|
|
|
|
//
|
|
// transform the view tile and find the vertex with the greatest Z
|
|
//
|
|
vertex[0]=TransformVertex(viewtilex, viewtiley);
|
|
vertex[1]=TransformVertex(viewtilex+1, viewtiley);
|
|
vertex[2]=TransformVertex(viewtilex+1, viewtiley+1);
|
|
vertex[3]=TransformVertex(viewtilex, viewtiley+1);
|
|
|
|
backvertex=0;
|
|
greatestz=vertex[0]->tz;
|
|
|
|
for (v=1; v<4; v++)
|
|
if (vertex[v]->tz>greatestz) {
|
|
backvertex=v;
|
|
greatestz=vertex[v]->tz;
|
|
}
|
|
}
|