greed/CODE/R_PLANE.C
2014-12-12 00:00:00 +00:00

428 lines
13 KiB
C

/***************************************************************************/
/* */
/* */
/* Raven 3D Engine */
/* Copyright (C) 1996 by Softdisk Publishing */
/* */
/* Original Design: */
/* John Carmack of id Software */
/* */
/* Enhancements by: */
/* Robert Morgan of Channel 7............................Main Engine Code */
/* Todd Lewis of Softdisk Publishing......Tools,Utilities,Special Effects */
/* John Bianca of Softdisk Publishing..............Low-level Optimization */
/* Carlos Hasan..........................................Music/Sound Code */
/* */
/* */
/***************************************************************************/
#include <MATH.H>
#include <STRING.H>
#include "d_global.h"
#include "d_disk.h"
#include "r_refdef.h"
/**** VARIABLES ****/
int mr_y, mr_x1, mr_x2; // used by mapplane to calculate texture end
int mr_shadow; // special lighting effect
int mr_light;
fixed_t mr_deltaheight;
int flatpic;
boolean transparent, ceilingbit;
// vertexes for drawable polygon
int numvertex;
int vertexy[5];
int vertexx[5];
int spantype;
// vertexes in need of Z clipping
clippoint_t vertexpt[5];
// 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;
/**** FUNCTIONS ****/
void FlatSpan(void)
/* used for flat floors and ceilings, coordinates must be pre clipped
mr_deltaheight is planeheight - viewheight, with height values increased
mr_picture and mr_deltaheight are set once per polygon */
{
fixed_t pointz; // row's distance to view plane
span_t *span_p;
unsigned span;
pointz=FIXEDDIV(mr_deltaheight,yslope[mr_y+MAXSCROLL]);
if (pointz>MAXZ) return;
// post the span in the draw list
span=(pointz<<ZTOFRAC)&ZMASK;
spansx[numspans]=mr_x1;
span|=numspans;
spantags[numspans]=span;
span_p=&spans[numspans];
span_p->spantype=spantype;
span_p->picture=mr_picture;
span_p->x2=mr_x2;
span_p->y=mr_y;
span_p->shadow=mr_shadow;
span_p->light=mr_light;
numspans++;
#ifdef VALIDATE
if (numspans>=MAXSPANS) MS_Error("MAXSPANS exceeded, FlatSpan (%i>=%i)",numspans,MAXSPANS);
#endif
}
void SlopeSpan(void)
/* used for sloping floors and ceilings
planeA, planeB, planeC, planeD must be precalculated
mr_picture is set once per polygon */
{
fixed_t pointz, pointz2; // row's distance to view plane
fixed_t partial, denom;
span_t *span_p;
unsigned span;
// calculate the Z values for each end of the span
partial=FIXEDMUL(planeB,yslope[mr_y+MAXSCROLL])+planeC;
denom=FIXEDMUL(planeA,xslope[mr_x1])+partial;
if (denom<8000) return;
pointz=FIXEDDIV(planeD,denom);
if (pointz>MAXZ) return;
denom=FIXEDMUL(planeA,xslope[mr_x2])+partial;
if (denom<8000) return;
pointz2=FIXEDDIV(planeD,denom);
if (pointz2>MAXZ) return;
// post the span in the draw list
span=(pointz<<ZTOFRAC)&ZMASK;
spansx[numspans]=mr_x1;
span|=numspans;
spantags[numspans]=span;
span_p=&spans[numspans];
span_p->spantype=spantype;
span_p->picture=mr_picture;
span_p->x2=mr_x2;
span_p->y=mr_y;
span_p->yh=pointz2;
span_p->shadow=mr_shadow;
span_p->light=mr_light;
numspans++;
#ifdef VALIDATE
if (numspans>=MAXSPANS) MS_Error("MAXSPANS exceeded, SlopeSpan (%i>=%i)",numspans,MAXSPANS);
#endif
}
void RenderPolygon(void (*spanfunction)(void))
/* 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, use 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) */
{
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
mr_y=vertexy[rightvertex];
leftvertex=rightvertex;
if (mr_y>=scrollmax) 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<=scrollmin)
{
leftfrac+=leftstep * (stopy-mr_y);
rightfrac+=rightstep * (stopy-mr_y);
mr_y=stopy;
continue;
}
if (mr_y<scrollmin)
{
leftfrac+=leftstep * (scrollmin-mr_y);
rightfrac+=rightstep * (scrollmin-mr_y);
mr_y=scrollmin;
}
if (stopy>scrollmax) stopy=scrollmax;
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 slope
leftfrac+=leftstep;
rightfrac+=rightstep;
}
} while (rightvertex!=leftvertex && mr_y!=scrollmax);
}
void CalcPlaneEquation(void)
/* Calculates planeA, planeB, planeC, planeD
planeD is actually -planeD
for vertexpt[0-2] */
{
fixed_t x1, y1, z1;
fixed_t x2, y2, z2;
// 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);
}
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) minz=MINZ; // less than this will cause problems
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);
if (ceilingbit && vertexy[numvertex]>640) return false;
numvertex++;
}
if (p1->tz>=minz)
{
vertexx[numvertex]=p1->px;
vertexy[numvertex]=p1->py;
if (ceilingbit && vertexy[numvertex]>640) return false;
numvertex++;
}
}
if (!numvertex) return false;
return true;
}
void RenderTileEnds(void)
/* draw floor and ceiling for tile */
{
int flags, polytype;
xcliph++;
flags=mapflags[mapspot];
// draw the floor
flatpic=floorpic[mapspot];
mr_shadow=mapeffects[mapspot];
if (mr_shadow==1) mr_shadow=(int)(colormaps+(wallglow<<8));
else if (mr_shadow==2) mr_shadow=(int)(colormaps+(wallflicker1<<8));
else if (mr_shadow==3) mr_shadow=(int)(colormaps+(wallflicker2<<8));
else if (mr_shadow==4) mr_shadow=(int)(colormaps+(wallflicker3<<8));
else if (mr_shadow>=5 && mr_shadow<=8)
{
if (wallcycle==mr_shadow-5) mr_shadow=(int)colormaps;
else mr_shadow=0;
}
mr_light=maplight;
flatpic=flattranslation[flatpic];
mr_picture=lumpmain[flatlump+flatpic];
polytype=(flags&FL_FLOOR)>>FLS_FLOOR;
ceilingbit=false;
switch (polytype)
{
case POLY_FLAT:
spantype=sp_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:
spantype=sp_slope;
COPYFLOOR(0, 0);
COPYFLOOR(1, 1);
COPYFLOOR(2, 2);
COPYFLOOR(3, 3);
CalcPlaneEquation();
if (ZClipPolygon(4,(fixed_t)MINZ)) RenderPolygon(SlopeSpan);
break;
case POLY_ULTOLR:
spantype=sp_slope;
COPYFLOOR(0, 0);
COPYFLOOR(1, 1);
COPYFLOOR(2, 2);
CalcPlaneEquation();
if (ZClipPolygon(3,(fixed_t)MINZ)) RenderPolygon(SlopeSpan);
COPYFLOOR(2, 0);
COPYFLOOR(3, 1);
COPYFLOOR(0, 2);
CalcPlaneEquation();
if (ZClipPolygon(3,(fixed_t)MINZ)) RenderPolygon(SlopeSpan);
break;
case POLY_URTOLL:
spantype=sp_slope;
COPYFLOOR(0, 0);
COPYFLOOR(1, 1);
COPYFLOOR(3, 2);
CalcPlaneEquation();
if (ZClipPolygon(3,(fixed_t)MINZ)) RenderPolygon(SlopeSpan);
COPYFLOOR(1, 0);
COPYFLOOR(2, 1);
COPYFLOOR(3, 2);
CalcPlaneEquation();
if (ZClipPolygon(3,(fixed_t)MINZ)) RenderPolygon(SlopeSpan);
break;
}
// draw the ceiling
ceilingbit=true;
flatpic=ceilingpic[mapspot];
if (ceilingflags[mapspot] & F_TRANSPARENT) transparent=true;
else transparent=false;
flatpic=flattranslation[flatpic];
mr_picture=lumpmain[flatlump+flatpic];
polytype=(flags&FL_CEILING)>>FLS_CEILING;
switch (polytype)
{
case POLY_FLAT:
if (flatpic==63) spantype=sp_sky;
else if (transparent) spantype=sp_flatsky;
else spantype=sp_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:
if (flatpic==63) spantype=sp_sky;
else if (transparent) spantype=sp_slopesky;
else spantype=sp_slope;
COPYCEILING(3, 0);
COPYCEILING(2, 1);
COPYCEILING(1, 2);
COPYCEILING(0, 3);
CalcPlaneEquation();
if (ZClipPolygon(4, MINZ)) RenderPolygon(SlopeSpan);
break;
case POLY_ULTOLR:
if (flatpic==63) spantype=sp_sky;
else if (transparent) spantype=sp_slopesky;
else spantype=sp_slope;
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:
if (flatpic==63) spantype=sp_sky;
else if (transparent) spantype=sp_slopesky;
else spantype=sp_slope;
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;
}
}