blob: b3b807d7062407d39b154ff1780507be4fb80cdb [file] [log] [blame]
/*
* "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 file has been modified from Ken Silverman's original release
*/
/* SUPERBUILD define is in engine.h ... */
#define ENGINE
#include "platform.h"
#include "build.h"
#include "engine.h"
#include "tiles.h"
int32_t stereowidth = 23040, stereopixelwidth = 28, ostereopixelwidth = -1;
int32_t stereomode = 0, visualpage, activepage, whiteband, blackband;
uint8_t oa1, o3c2, ortca, ortcb, overtbits, laststereoint;
#include "display.h"
#define MAXCLIPNUM 512
#define MAXPERMS 512
#define MAXTILEFILES 256
#define MAXYSAVES ((MAXXDIM*MAXSPRITES)>>7)
#define MAXNODESPERLINE 42 /* Warning: This depends on MAXYSAVES & MAXYDIM! */
#define MAXWALLSB 2048
#define MAXCLIPDIST 1024
/* used to be static. --ryan. */
uint8_t moustat = 0;
int32_t transarea = 0, beforedrawrooms = 1;
/* used to be static. --ryan. */
int32_t oxdimen = -1, oviewingrange = -1, oxyaspect = -1;
/* used to be static. --ryan. */
int32_t curbrightness = 0;
/* Textured Map variables */
static uint8_t globalpolytype;
static short *dotp1[MAXYDIM], *dotp2[MAXYDIM];
static char tempbuf[MAXWALLS];
int32_t ebpbak, espbak;
int32_t slopalookup[16384];
/*
* !!! used to be static. If we ever put the original setgamemode() back, this
* !!! can be made static again. --ryan.
*/
uint8_t permanentlock = 255;
int32_t mapversion;
uint8_t picsiz[MAXTILES], tilefilenum[MAXTILES];
int32_t lastageclock;
int32_t tilefileoffs[MAXTILES];
int32_t artsize = 0, cachesize = 0;
static short radarang[1280], radarang2[MAXXDIM+1];
static uint16_t sqrtable[4096], shlookup[4096+256];
uint8_t pow2char[8] = {1,2,4,8,16,32,64,-128};
int32_t pow2long[32] =
{
1L,2L,4L,8L,
16L,32L,64L,128L,
256L,512L,1024L,2048L,
4096L,8192L,16384L,32768L,
65536L,131072L,262144L,524288L,
1048576L,2097152L,4194304L,8388608L,
16777216L,33554432L,67108864L,134217728L,
268435456L,536870912L,1073741824L,2147483647L,
};
int32_t reciptable[2048], fpuasm;
char kensmessage[128];
uint8_t britable[16][64];
uint8_t textfont[1024], smalltextfont[1024];
enum vector_index_e {VEC_X=0,VEC_Y=1};
enum screenSpaceCoo_index_e {VEC_COL=0,VEC_DIST=1};
typedef int32_t vector_t[2];
typedef int32_t coo2D_t[2];
// This is the structure emitted for each wall that is potentially visible.
// A stack of those is populated when the sectors are scanned.
typedef struct pvWall_s{
vector_t cameraSpaceCoo[2]; //Camera space coordinates of the wall endpoints. Access with vector_index_e.
int16_t sectorId; //The index of the sector this wall belongs to in the map database.
int16_t worldWallId; //The index of the wall in the map database.
coo2D_t screenSpaceCoo[2]; //Screen space coordinate of the wall endpoints. Access with screenSpaceCoo_index_e.
} pvWall_t;
// Potentially Visible walls are stored in this stack.
pvWall_t pvWalls[MAXWALLSB];
//xb1 and xb2 seems to be storing the column of the wall endpoint
//yb1 and yb2 store the Y distance from the camera.
//static int32_t xb1[MAXWALLSB], yb1[MAXWALLSB], xb2[MAXWALLSB], yb2[MAXWALLSB];
/*
//rx1,rx2,ry1,ry2 stores the cameraspace wall endpoints coordinates.
static int32_t rx1[MAXWALLSB], ry1[MAXWALLSB], rx2[MAXWALLSB], ry2[MAXWALLSB];
static short thesector[MAXWALLSB], thewall[MAXWALLSB];
*/
// bunchWallsList contains the list of walls in a bunch.
static short bunchWallsList[MAXWALLSB];
static short bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB];
static short smost[MAXYSAVES], smostcnt;
static short smoststart[MAXWALLSB];
static uint8_t smostwalltype[MAXWALLSB];
static int32_t smostwall[MAXWALLSB], smostwallcnt = -1L;
static short maskwall[MAXWALLSB], maskwallcnt;
static int32_t spritesx[MAXSPRITESONSCREEN];
static int32_t spritesy[MAXSPRITESONSCREEN+1];
static int32_t spritesz[MAXSPRITESONSCREEN];
static spritetype *tspriteptr[MAXSPRITESONSCREEN];
//FCS: (up-most pixel on column x that can still be drawn to)
short umost[MAXXDIM+1];
//FCS: (down-most pixel +1 on column x that can still be drawn to)
short dmost[MAXXDIM+1];
int16_t bakumost[MAXXDIM+1], bakdmost[MAXXDIM+1];
short uplc[MAXXDIM+1], dplc[MAXXDIM+1];
static int16_t uwall[MAXXDIM+1], dwall[MAXXDIM+1];
static int32_t swplc[MAXXDIM+1], lplc[MAXXDIM+1];
static int32_t swall[MAXXDIM+1], lwall[MAXXDIM+4];
int32_t xdimen = -1, xdimenrecip, halfxdimen, xdimenscale, xdimscale;
int32_t wx1, wy1, wx2, wy2, ydimen;
int32_t viewoffset;
static int32_t rxi[8], ryi[8], rzi[8], rxi2[8], ryi2[8], rzi2[8];
static int32_t xsi[8], ysi[8];
/* used to be static. --ryan. */
int32_t *horizlookup=0, *horizlookup2=0, horizycent;
int32_t globalposx, globalposy, globalposz, globalhoriz;
int16_t globalang, globalcursectnum;
int32_t globalpal, cosglobalang, singlobalang;
int32_t cosviewingrangeglobalang, sinviewingrangeglobalang;
uint8_t *globalpalwritten;
int32_t globaluclip, globaldclip, globvis = 0;
int32_t globalvisibility, globalhisibility, globalpisibility, globalcisibility;
uint8_t globparaceilclip, globparaflorclip;
int32_t xyaspect, viewingrangerecip;
int32_t asm1, asm4;
intptr_t asm2, asm3;
int32_t vplce[4], vince[4];
intptr_t bufplce[4];
uint8_t* palookupoffse[4];
uint8_t globalxshift, globalyshift;
int32_t globalxpanning, globalypanning, globalshade;
int16_t globalpicnum, globalshiftval;
int32_t globalzd, globalyscale, globalorientation;
uint8_t* globalbufplc;
int32_t globalx1, globaly1, globalx2, globaly2, globalx3, globaly3, globalzx;
int32_t globalx, globaly, globalz;
//FCS:
// Those two variables are using during portal flooding:
// sectorBorder is the stack and sectorbordercnt is the stack counter.
// There is no really point to have this on the heap. That would have been better on the stack.
//static short sectorborder[256], sectorbordercnt;
//FCS: Moved this on the stack
static uint8_t tablesloaded = 0;
int32_t pageoffset, ydim16, qsetmode = 0;
int32_t startposx, startposy, startposz;
int16_t startang, startsectnum;
int16_t pointhighlight, linehighlight, highlightcnt;
static int32_t lastx[MAXYDIM];
uint8_t paletteloaded = 0;
#define FASTPALGRIDSIZ 8
static int32_t rdist[129], gdist[129], bdist[129];
static uint8_t colhere[((FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2))>>3];
static uint8_t colhead[(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)];
static int32_t colnext[256];
static uint8_t coldist[8] = {0,1,2,3,4,3,2,1};
static int32_t colscan[27];
static int16_t clipnum, hitwalls[4];
int32_t hitscangoalx = (1<<29)-1, hitscangoaly = (1<<29)-1;
typedef struct {
int32_t x1, y1, x2, y2;
} linetype;
static linetype clipit[MAXCLIPNUM];
static short clipsectorlist[MAXCLIPNUM], clipsectnum;
static short clipobjectval[MAXCLIPNUM];
typedef struct
{
int32_t sx, sy, z;
short a, picnum;
int8_t dashade;
uint8_t dapalnum, dastat, pagesleft;
int32_t cx1, cy1, cx2, cy2;
} permfifotype;
static permfifotype permfifo[MAXPERMS];
static int32_t permhead = 0, permtail = 0;
//FCS: Num walls to potentially render.
short numscans ;
short numbunches;
//FCS: Number of colums to draw. ALWAYS set to the screen dimension width.
short numhits;
short editstatus = 0;
short searchit;
int32_t searchx = -1, searchy; /* search input */
short searchsector, searchwall, searchstat; /* search output */
int32_t numtilefiles, artfil = -1, artfilnum, artfilplc;
static uint8_t inpreparemirror = 0;
static int32_t mirrorsx1, mirrorsy1, mirrorsx2, mirrorsy2;
int32_t totalclocklock;
uint16_t mapCRC;
#include "draw.h"
static __inline int32_t nsqrtasm(uint32_t param)
{
uint16_t *shlookup_a = (uint16_t*)shlookup;
uint16_t *sqrtable_a = (uint16_t*)sqrtable;
uint16_t cx;
if (param & 0xff000000)
cx = shlookup_a[(param>>24)+4096];
else
cx = shlookup_a[param>>12];
param = param >> (cx&0xff);
param = ((param&0xffff0000)|sqrtable_a[param]);
param = param >> ((cx&0xff00)>>8);
return param;
}
static __inline int32_t krecipasm(int32_t i)
{ // Ken did this
float f = (float)i;
i = *(int32_t *)&f;
return((reciptable[(i>>12)&2047]>>(((i-0x3f800000)>>23)&31))^(i>>31));
}
static __inline int32_t getclipmask(int32_t a, int32_t b, int32_t c, int32_t d)
{ // Ken did this
d = ((a<0)*8) + ((b<0)*4) + ((c<0)*2) + (d<0);
return(((d<<4)^0xf0)|d);
}
//
// krecip
//
int32_t krecip(int32_t num)
{
return(krecipasm(num));
}
uint16_t _swap16(uint16_t D)
{
return((D<<8)|(D>>8));
}
unsigned int _swap32(unsigned int D)
{
return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
}
/*
FCS:
Scan through sectors using portals (a portal is wall with a nextsector attribute >= 0).
Flood is prevented if a portal does not face the POV.
*/
static void scansector (short sectnum)
{
walltype *wal, *wal2;
spritetype *spr;
int32_t xs, ys, x1, y1, x2, y2, xp1, yp1, xp2=0, yp2=0, tempint;
short z, zz, startwall, endwall, numscansbefore, scanfirst, bunchfrst;
short nextsectnum;
//The stack storing sectors to visit.
short sectorsToVisit[256], numSectorsToVisit;
if (sectnum < 0)
return;
if (automapping)
show2dsector[sectnum>>3] |= pow2char[sectnum&7];
sectorsToVisit[0] = sectnum;
numSectorsToVisit = 1;
do
{
sectnum = sectorsToVisit[--numSectorsToVisit];
//Add every script in the current sector as potentially visible.
for(z=headspritesect[sectnum]; z>=0; z=nextspritesect[z])
{
spr = &sprite[z];
if ((((spr->cstat&0x8000) == 0) || (showinvisibility)) &&
(spr->xrepeat > 0) && (spr->yrepeat > 0) &&
(spritesortcnt < MAXSPRITESONSCREEN))
{
xs = spr->x-globalposx;
ys = spr->y-globalposy;
if ((spr->cstat&48) || (xs*cosglobalang+ys*singlobalang > 0))
{
copybufbyte(spr,&tsprite[spritesortcnt],sizeof(spritetype));
tsprite[spritesortcnt++].owner = z;
}
}
}
//Mark the current sector bit as "visited" in the bitvector
visitedSectors[sectnum>>3] |= pow2char[sectnum&7];
bunchfrst = numbunches;
numscansbefore = numscans;
startwall = sector[sectnum].wallptr;
endwall = startwall + sector[sectnum].wallnum;
scanfirst = numscans;
for(z=startwall,wal=&wall[z]; z<endwall; z++,wal++)
{
nextsectnum = wal->nextsector;
wal2 = &wall[wal->point2];
// In camera space the center is the player.
// Tranform the 2 Wall endpoints (x,y) from worldspace to camera space.
// After that we have two vectors starting from the camera and going to the endpoints (x1,y1) and (x2,y2).
x1 = wal->x-globalposx;
y1 = wal->y-globalposy;
x2 = wal2->x-globalposx;
y2 = wal2->y-globalposy;
// If this is a portal...
if ((nextsectnum >= 0) && ((wal->cstat&32) == 0))
//If this portal has not been visited yet.
if ((visitedSectors[nextsectnum>>3]&pow2char[nextsectnum&7]) == 0)
{
//Cross product -> Z component
tempint = x1*y2-x2*y1;
// Using cross product, determine if the portal is facing us or not.
// If it is: Add it to the stack and bump the stack counter.
// This line is equivalent to tempint < 0x40000
if (((uint32_t)tempint+262144) < 524288) // ??? What is this test ?? How acute the angle is ?
{
//(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1) is the squared length of the wall
// ??? What is this test ?? How acute the angle is ?
if (mulscale5(tempint,tempint) <= (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
sectorsToVisit[numSectorsToVisit++] = nextsectnum;
}
}
// Rotate the wall endpoints vectors according to the player orientation.
// This is a regular rotation matrix using [29.3] fixed point.
if ((z == startwall) || (wall[z-1].point2 != z))
{
//If this is the first endpoint of the bunch, rotate: This is a standard cos sin 2D rotation matrix projection
xp1 = dmulscale6(y1,cosglobalang,-x1,singlobalang);
yp1 = dmulscale6(x1,cosviewingrangeglobalang,y1,sinviewingrangeglobalang);
}
else
{
//If this is NOT the first endpoint, Save the coordinate for next loop.
xp1 = xp2;
yp1 = yp2;
}
// Rotate: This is a standard cos sin 2D rotation matrix projection
xp2 = dmulscale6(y2,cosglobalang,-x2,singlobalang);
yp2 = dmulscale6(x2,cosviewingrangeglobalang,y2,sinviewingrangeglobalang);
// Equivalent of a near plane clipping ?
if ((yp1 < 256) && (yp2 < 256)) goto skipitaddwall;
/* If wall's NOT facing you */
if (dmulscale32(xp1,yp2,-xp2,yp1) >= 0) goto skipitaddwall;
// The wall is still not eligible for rendition: Let's do some more Frustrum culling !!
if (xp1 >= -yp1){
if ((xp1 > yp1) || (yp1 == 0))
goto skipitaddwall;
//Project the point onto screen and see in which column it belongs.
pvWalls[numscans].screenSpaceCoo[0][VEC_COL] = halfxdimen + scale(xp1,halfxdimen,yp1);
if (xp1 >= 0)
pvWalls[numscans].screenSpaceCoo[0][VEC_COL]++; /* Fix for SIGNED divide */
if (pvWalls[numscans].screenSpaceCoo[0][VEC_COL] >= xdimen)
pvWalls[numscans].screenSpaceCoo[0][VEC_COL] = xdimen-1;
pvWalls[numscans].screenSpaceCoo[0][VEC_DIST] = yp1;
}
else{
if (xp2 < -yp2)
goto skipitaddwall;
pvWalls[numscans].screenSpaceCoo[0][VEC_COL] = 0;
tempint = yp1-yp2+xp1-xp2;
if (tempint == 0)
goto skipitaddwall;
pvWalls[numscans].screenSpaceCoo[0][VEC_DIST] = yp1 + scale(yp2-yp1,xp1+yp1,tempint);
}
if (pvWalls[numscans].screenSpaceCoo[0][VEC_DIST] < 256)
goto skipitaddwall;
if (xp2 <= yp2){
if ((xp2 < -yp2) || (yp2 == 0)) goto skipitaddwall;
pvWalls[numscans].screenSpaceCoo[1][VEC_COL] = halfxdimen + scale(xp2,halfxdimen,yp2) - 1;
if (xp2 >= 0) pvWalls[numscans].screenSpaceCoo[1][VEC_COL]++; /* Fix for SIGNED divide */
if (pvWalls[numscans].screenSpaceCoo[1][VEC_COL] >= xdimen) pvWalls[numscans].screenSpaceCoo[1][VEC_COL] = xdimen-1;
pvWalls[numscans].screenSpaceCoo[1][VEC_DIST] = yp2;
}
else{
if (xp1 > yp1) goto skipitaddwall;
pvWalls[numscans].screenSpaceCoo[1][VEC_COL] = xdimen-1;
tempint = xp2-xp1+yp1-yp2;
if (tempint == 0) goto skipitaddwall;
pvWalls[numscans].screenSpaceCoo[1][VEC_DIST] = yp1 + scale(yp2-yp1,yp1-xp1,tempint);
}
if ((pvWalls[numscans].screenSpaceCoo[1][VEC_DIST] < 256) || (pvWalls[numscans].screenSpaceCoo[0][VEC_COL] > pvWalls[numscans].screenSpaceCoo[1][VEC_COL])) goto skipitaddwall;
// Made it all the way!
// Time to add this wall information to the stack of wall potentially visible.
pvWalls[numscans].sectorId = sectnum;
pvWalls[numscans].worldWallId = z;
//Save the camera space wall endpoints coordinate (camera origin at player location + rotated according to player orientation).
pvWalls[numscans].cameraSpaceCoo[0][VEC_X] = xp1;
pvWalls[numscans].cameraSpaceCoo[0][VEC_Y] = yp1;
pvWalls[numscans].cameraSpaceCoo[1][VEC_X] = xp2;
pvWalls[numscans].cameraSpaceCoo[1][VEC_Y] = yp2;
bunchWallsList[numscans] = numscans+1;
numscans++;
skipitaddwall:
if ((wall[z].point2 < z) && (scanfirst < numscans))
{
bunchWallsList[numscans-1] = scanfirst;
scanfirst = numscans;
}
}
//FCS: TODO rename this p2[] to bunchList[] or something like that. This name is an abomination
// DONE, p2 is now called "bunchWallsList".
//Break down the list of walls for this sector into bunchs. Since a bunch is a
// continuously visible list of wall: A sector can generate many bunches.
for(z=numscansbefore; z<numscans; z++)
{
if ((wall[pvWalls[z].worldWallId].point2 !=
pvWalls[bunchWallsList[z]].worldWallId) || (pvWalls[z].screenSpaceCoo[1][VEC_COL] >= pvWalls[bunchWallsList[z]].screenSpaceCoo[0][VEC_COL]))
{
// Create an entry in the bunch list
bunchfirst[numbunches++] = bunchWallsList[z];
//Mark the end of the bunch wall list.
bunchWallsList[z] = -1;
}
}
//For each bunch, find the last wall and cache it in bunchlast.
for(z=bunchfrst; z<numbunches; z++)
{
for(zz=bunchfirst[z]; bunchWallsList[zz]>=0; zz=bunchWallsList[zz]);
bunchlast[z] = zz;
}
} while (numSectorsToVisit > 0);
// do this until the stack of sectors to visit if empty.
}
/*
FCS:
Goal : ????
param 1: Z is the wallID in the list of potentially visible walls.
param 2: Only used to lookup the xrepeat attribute of the wall.
*/
static void prepwall(int32_t z, walltype *wal)
{
int32_t i, l=0, ol=0, splc, sinc, x, topinc, top, botinc, bot, walxrepeat;
vector_t* wallCoo = pvWalls[z].cameraSpaceCoo;
walxrepeat = (wal->xrepeat<<3);
/* lwall calculation */
i = pvWalls[z].screenSpaceCoo[0][VEC_COL]-halfxdimen;
//Let's use some of the camera space wall coordinate now.
topinc = -(wallCoo[0][VEC_Y]>>2);
botinc = ((wallCoo[1][VEC_Y]-wallCoo[0][VEC_Y])>>8);
top = mulscale5(wallCoo[0][VEC_X],xdimen)+mulscale2(topinc,i);
bot = mulscale11(wallCoo[0][VEC_X]-wallCoo[1][VEC_X],xdimen)+mulscale2(botinc,i);
splc = mulscale19(wallCoo[0][VEC_Y],xdimscale);
sinc = mulscale16(wallCoo[1][VEC_Y]-wallCoo[0][VEC_Y],xdimscale);
//X screenspce column of point Z.
x = pvWalls[z].screenSpaceCoo[0][VEC_COL];
if (bot != 0)
{
l = divscale12(top,bot);
swall[x] = mulscale21(l,sinc)+splc;
l *= walxrepeat;
lwall[x] = (l>>18);
}
//If the wall is less than 4 column wide.
while (x+4 <= pvWalls[z].screenSpaceCoo[1][VEC_COL])
{
top += topinc;
bot += botinc;
if (bot != 0)
{
ol = l;
l = divscale12(top,bot);
swall[x+4] = mulscale21(l,sinc)+splc;
l *= walxrepeat;
lwall[x+4] = (l>>18);
}
i = ((ol+l)>>1);
lwall[x+2] = (i>>18);
lwall[x+1] = ((ol+i)>>19);
lwall[x+3] = ((l+i)>>19);
swall[x+2] = ((swall[x]+swall[x+4])>>1);
swall[x+1] = ((swall[x]+swall[x+2])>>1);
swall[x+3] = ((swall[x+4]+swall[x+2])>>1);
x += 4;
}
//If the wall is less than 2 columns wide.
if (x+2 <= pvWalls[z].screenSpaceCoo[1][VEC_COL])
{
top += (topinc>>1);
bot += (botinc>>1);
if (bot != 0)
{
ol = l;
l = divscale12(top,bot);
swall[x+2] = mulscale21(l,sinc)+splc;
l *= walxrepeat;
lwall[x+2] = (l>>18);
}
lwall[x+1] = ((l+ol)>>19);
swall[x+1] = ((swall[x]+swall[x+2])>>1);
x += 2;
}
//The wall is 1 column wide.
if (x+1 <= pvWalls[z].screenSpaceCoo[1][VEC_COL])
{
bot += (botinc>>2);
if (bot != 0)
{
l = divscale12(top+(topinc>>2),bot);
swall[x+1] = mulscale21(l,sinc)+splc;
lwall[x+1] = mulscale18(l,walxrepeat);
}
}
if (lwall[pvWalls[z].screenSpaceCoo[0][VEC_COL]] < 0)
lwall[pvWalls[z].screenSpaceCoo[0][VEC_COL]] = 0;
if ((lwall[pvWalls[z].screenSpaceCoo[1][VEC_COL]] >= walxrepeat) && (walxrepeat))
lwall[pvWalls[z].screenSpaceCoo[1][VEC_COL]] = walxrepeat-1;
if (wal->cstat&8)
{
walxrepeat--;
for(x=pvWalls[z].screenSpaceCoo[0][VEC_COL]; x<=pvWalls[z].screenSpaceCoo[1][VEC_COL]; x++)
lwall[x] = walxrepeat-lwall[x];
}
}
static int32_t getpalookup(int32_t davis, int32_t dashade)
{
return(min(max(dashade+(davis>>8),0),numpalookups-1));
}
static void hline (int32_t xr, int32_t yp)
{
int32_t xl, r, s;
xl = lastx[yp];
if (xl > xr)
return;
r = horizlookup2[yp-globalhoriz+horizycent];
asm1 = globalx1*r;
asm2 = globaly2*r;
s = (getpalookup(mulscale16(r,globvis),globalshade)<<8);
hlineasm4(xr-xl,s,globalx2*r+globalypanning,globaly1*r+globalxpanning,ylookup[yp]+xr+frameoffset);
}
static void slowhline (int32_t xr, int32_t yp)
{
int32_t xl, r;
xl = lastx[yp];
if (xl > xr) return;
r = horizlookup2[yp-globalhoriz+horizycent];
asm1 = globalx1*r;
asm2 = globaly2*r;
asm3 = (int32_t)globalpalwritten + (getpalookup(mulscale16(r,globvis),globalshade)<<8);
if (!(globalorientation&256))
{
mhline(globalbufplc,globaly1*r+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L,
globalx2*r+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset);
return;
}
thline(globalbufplc,globaly1*r+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L,globalx2*r+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset);
transarea += (xr-xl);
}
/* renders non-parallaxed ceilings. --ryan. */
static void ceilscan (int32_t x1, int32_t x2, int32_t sectnum)
{
int32_t i, j, ox, oy, x, y1, y2, twall, bwall;
sectortype *sec;
sec = &sector[sectnum];
if (palookup[sec->ceilingpal] != globalpalwritten)
globalpalwritten = palookup[sec->ceilingpal];
globalzd = sec->ceilingz-globalposz;
if (globalzd > 0)
return;
globalpicnum = sec->ceilingpicnum;
if ((uint32_t)globalpicnum >= (uint32_t)MAXTILES)
globalpicnum = 0;
setgotpic(globalpicnum);
//Check the tile dimension are valid.
if ((tiles[globalpicnum].dim.width <= 0) ||
(tiles[globalpicnum].dim.height <= 0))
return;
if (tiles[globalpicnum].animFlags&192)
globalpicnum += animateoffs(globalpicnum);
TILE_MakeAvailable(globalpicnum);
globalbufplc = tiles[globalpicnum].data;
globalshade = (int32_t)sec->ceilingshade;
globvis = globalcisibility;
if (sec->visibility != 0)
globvis = mulscale4(globvis,(int32_t)((uint8_t )(sec->visibility+16)));
globalorientation = (int32_t)sec->ceilingstat;
if ((globalorientation&64) == 0){
globalx1 = singlobalang;
globalx2 = singlobalang;
globaly1 = cosglobalang;
globaly2 = cosglobalang;
globalxpanning = (globalposx<<20);
globalypanning = -(globalposy<<20);
}
else{
j = sec->wallptr;
ox = wall[wall[j].point2].x - wall[j].x;
oy = wall[wall[j].point2].y - wall[j].y;
i = nsqrtasm(ox*ox+oy*oy);
if (i == 0)
i = 1024;
else
i = 1048576/i;
globalx1 = mulscale10(dmulscale10(ox,singlobalang,-oy,cosglobalang),i);
globaly1 = mulscale10(dmulscale10(ox,cosglobalang,oy,singlobalang),i);
globalx2 = -globalx1;
globaly2 = -globaly1;
ox = ((wall[j].x-globalposx)<<6);
oy = ((wall[j].y-globalposy)<<6);
i = dmulscale14(oy,cosglobalang,-ox,singlobalang);
j = dmulscale14(ox,cosglobalang,oy,singlobalang);
ox = i;
oy = j;
globalxpanning = globalx1*ox - globaly1*oy;
globalypanning = globaly2*ox + globalx2*oy;
}
globalx2 = mulscale16(globalx2,viewingrangerecip);
globaly1 = mulscale16(globaly1,viewingrangerecip);
globalxshift = (8-(picsiz[globalpicnum]&15));
globalyshift = (8-(picsiz[globalpicnum]>>4));
if (globalorientation&8) {
globalxshift++;
globalyshift++;
}
if ((globalorientation&0x4) > 0){
i = globalxpanning;
globalxpanning = globalypanning;
globalypanning = i;
i = globalx2;
globalx2 = -globaly1;
globaly1 = -i;
i = globalx1;
globalx1 = globaly2;
globaly2 = i;
}
if ((globalorientation&0x10) > 0){
globalx1 = -globalx1;
globaly1 = -globaly1;
globalxpanning = -globalxpanning;
}
if ((globalorientation&0x20) > 0){
globalx2 = -globalx2;
globaly2 = -globaly2;
globalypanning = -globalypanning;
}
globalx1 <<= globalxshift;
globaly1 <<= globalxshift;
globalx2 <<= globalyshift;
globaly2 <<= globalyshift;
globalxpanning <<= globalxshift;
globalypanning <<= globalyshift;
globalxpanning += (((int32_t)sec->ceilingxpanning)<<24);
globalypanning += (((int32_t)sec->ceilingypanning)<<24);
globaly1 = (-globalx1-globaly1)*halfxdimen;
globalx2 = (globalx2-globaly2)*halfxdimen;
sethlinesizes(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4,globalbufplc);
globalx2 += globaly2*(x1-1);
globaly1 += globalx1*(x1-1);
globalx1 = mulscale16(globalx1,globalzd);
globalx2 = mulscale16(globalx2,globalzd);
globaly1 = mulscale16(globaly1,globalzd);
globaly2 = mulscale16(globaly2,globalzd);
globvis = klabs(mulscale10(globvis,globalzd));
if (!(globalorientation&0x180))
{
y1 = umost[x1];
y2 = y1;
for(x=x1; x<=x2; x++)
{
twall = umost[x]-1;
bwall = min(uplc[x],dmost[x]);
if (twall < bwall-1)
{
if (twall >= y2)
{
while (y1 < y2-1) hline(x-1,++y1);
y1 = twall;
}
else
{
while (y1 < twall)
hline(x-1,++y1);
while (y1 > twall)
lastx[y1--] = x;
}
while (y2 > bwall)
hline(x-1,--y2);
while (y2 < bwall)
lastx[y2++] = x;
}
else
{
while (y1 < y2-1)
hline(x-1,++y1);
if (x == x2) {
globalx2 += globaly2;
globaly1 += globalx1;
break;
}
y1 = umost[x+1];
y2 = y1;
}
globalx2 += globaly2;
globaly1 += globalx1;
}
while (y1 < y2-1) hline(x2,++y1);
faketimerhandler();
return;
}
switch(globalorientation&0x180)
{
case 128:
msethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
break;
case 256:
settrans(TRANS_NORMAL);
tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
break;
case 384:
settrans(TRANS_REVERSE);
tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
break;
}
y1 = umost[x1];
y2 = y1;
for(x=x1; x<=x2; x++)
{
twall = umost[x]-1;
bwall = min(uplc[x],dmost[x]);
if (twall < bwall-1)
{
if (twall >= y2)
{
while (y1 < y2-1) slowhline(x-1,++y1);
y1 = twall;
}
else
{
while (y1 < twall) slowhline(x-1,++y1);
while (y1 > twall) lastx[y1--] = x;
}
while (y2 > bwall) slowhline(x-1,--y2);
while (y2 < bwall) lastx[y2++] = x;
}
else
{
while (y1 < y2-1) slowhline(x-1,++y1);
if (x == x2) {
globalx2 += globaly2;
globaly1 += globalx1;
break;
}
y1 = umost[x+1];
y2 = y1;
}
globalx2 += globaly2;
globaly1 += globalx1;
}
while (y1 < y2-1) slowhline(x2,++y1);
faketimerhandler();
}
/* renders non-parallaxed floors. --ryan. */
static void florscan (int32_t x1, int32_t x2, int32_t sectnum)
{
int32_t i, j, ox, oy, x, y1, y2, twall, bwall;
sectortype *sec;
//Retrieve the sector object
sec = &sector[sectnum];
//Retrieve the floor palette.
if (palookup[sec->floorpal] != globalpalwritten)
globalpalwritten = palookup[sec->floorpal];
globalzd = globalposz-sec->floorz;
//We are UNDER the floor: Do NOT render anything.
if (globalzd > 0)
return;
//Retrive the floor texture.
globalpicnum = sec->floorpicnum;
if ((uint32_t)globalpicnum >= (uint32_t)MAXTILES)
globalpicnum = 0;
//Lock the floor texture
setgotpic(globalpicnum);
//This tile has unvalid dimensions ( negative)
if ((tiles[globalpicnum].dim.width <= 0) ||
(tiles[globalpicnum].dim.height <= 0))
return;
//If this is an animated texture: Animate it.
if (tiles[globalpicnum].animFlags&192)
globalpicnum += animateoffs(globalpicnum);
//If the texture is not in RAM: Load it !!
TILE_MakeAvailable(globalpicnum);
//Check where is the texture in RAM
globalbufplc = tiles[globalpicnum].data;
//Retrieve the shade of the sector (illumination level).
globalshade = (int32_t)sec->floorshade;
globvis = globalcisibility;
if (sec->visibility != 0)
globvis = mulscale4(globvis,(int32_t)((uint8_t)(sec->visibility+16)));
globalorientation = (int32_t)sec->floorstat;
if ((globalorientation&64) == 0)
{
globalx1 = singlobalang;
globalx2 = singlobalang;
globaly1 = cosglobalang;
globaly2 = cosglobalang;
globalxpanning = (globalposx<<20);
globalypanning = -(globalposy<<20);
}
else
{
j = sec->wallptr;
ox = wall[wall[j].point2].x - wall[j].x;
oy = wall[wall[j].point2].y - wall[j].y;
i = nsqrtasm(ox*ox+oy*oy);
if (i == 0)
i = 1024;
else
i = 1048576/i;
globalx1 = mulscale10(dmulscale10(ox,singlobalang,-oy,cosglobalang),i);
globaly1 = mulscale10(dmulscale10(ox,cosglobalang,oy,singlobalang),i);
globalx2 = -globalx1;
globaly2 = -globaly1;
ox = ((wall[j].x-globalposx)<<6);
oy = ((wall[j].y-globalposy)<<6);
i = dmulscale14(oy,cosglobalang,-ox,singlobalang);
j = dmulscale14(ox,cosglobalang,oy,singlobalang);
ox = i;
oy = j;
globalxpanning = globalx1*ox - globaly1*oy;
globalypanning = globaly2*ox + globalx2*oy;
}
globalx2 = mulscale16(globalx2,viewingrangerecip);
globaly1 = mulscale16(globaly1,viewingrangerecip);
globalxshift = (8-(picsiz[globalpicnum]&15));
globalyshift = (8-(picsiz[globalpicnum]>>4));
if (globalorientation&8) {
globalxshift++;
globalyshift++;
}
if ((globalorientation&0x4) > 0)
{
i = globalxpanning;
globalxpanning = globalypanning;
globalypanning = i;
i = globalx2;
globalx2 = -globaly1;
globaly1 = -i;
i = globalx1;
globalx1 = globaly2;
globaly2 = i;
}
if ((globalorientation&0x10) > 0){
globalx1 = -globalx1;
globaly1 = -globaly1;
globalxpanning = -globalxpanning;
}
if ((globalorientation&0x20) > 0){
globalx2 = -globalx2;
globaly2 = -globaly2;
globalypanning = -globalypanning;
}
globalx1 <<= globalxshift;
globaly1 <<= globalxshift;
globalx2 <<= globalyshift;
globaly2 <<= globalyshift;
globalxpanning <<= globalxshift;
globalypanning <<= globalyshift;
globalxpanning += (((int32_t)sec->floorxpanning)<<24);
globalypanning += (((int32_t)sec->floorypanning)<<24);
globaly1 = (-globalx1-globaly1)*halfxdimen;
globalx2 = (globalx2-globaly2)*halfxdimen;
//Setup the drawing routine paramters
sethlinesizes(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4,globalbufplc);
globalx2 += globaly2*(x1-1);
globaly1 += globalx1*(x1-1);
globalx1 = mulscale16(globalx1,globalzd);
globalx2 = mulscale16(globalx2,globalzd);
globaly1 = mulscale16(globaly1,globalzd);
globaly2 = mulscale16(globaly2,globalzd);
globvis = klabs(mulscale10(globvis,globalzd));
if (!(globalorientation&0x180))
{
y1 = max(dplc[x1],umost[x1]);
y2 = y1;
for(x=x1; x<=x2; x++)
{
twall = max(dplc[x],umost[x])-1;
bwall = dmost[x];
if (twall < bwall-1)
{
if (twall >= y2)
{
while (y1 < y2-1)
hline(x-1,++y1);
y1 = twall;
}
else
{
while (y1 < twall)
hline(x-1,++y1);
while (y1 > twall)
lastx[y1--] = x;
}
while (y2 > bwall)
hline(x-1,--y2);
while (y2 < bwall)
lastx[y2++] = x;
}
else
{
while (y1 < y2-1) hline(x-1,++y1);
if (x == x2) {
globalx2 += globaly2;
globaly1 += globalx1;
break;
}
y1 = max(dplc[x+1],umost[x+1]);
y2 = y1;
}
globalx2 += globaly2;
globaly1 += globalx1;
}
while (y1 < y2-1)
hline(x2,++y1);
faketimerhandler();
return;
}
switch(globalorientation&0x180)
{
case 128:
msethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
break;
case 256:
settrans(TRANS_NORMAL);
tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
break;
case 384:
settrans(TRANS_REVERSE);
tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
break;
}
y1 = max(dplc[x1],umost[x1]);
y2 = y1;
for(x=x1; x<=x2; x++)
{
twall = max(dplc[x],umost[x])-1;
bwall = dmost[x];
if (twall < bwall-1)
{
if (twall >= y2)
{
while (y1 < y2-1) slowhline(x-1,++y1);
y1 = twall;
}
else
{
while (y1 < twall)
slowhline(x-1,++y1);
while (y1 > twall)
lastx[y1--] = x;
}
while (y2 > bwall)
slowhline(x-1,--y2);
while (y2 < bwall)
lastx[y2++] = x;
}
else
{
while (y1 < y2-1)
slowhline(x-1,++y1);
if (x == x2) {
globalx2 += globaly2;
globaly1 += globalx1;
break;
}
y1 = max(dplc[x+1],umost[x+1]);
y2 = y1;
}
globalx2 += globaly2;
globaly1 += globalx1;
}
while (y1 < y2-1)
slowhline(x2,++y1);
faketimerhandler();
}
/*
* renders walls and parallaxed skies/floors. Look at parascan() for the
* higher level of parallaxing.
*
* x1 == offset of leftmost pixel of wall. 0 is left of surface.
* x2 == offset of rightmost pixel of wall. 0 is left of surface.
*
* apparently, walls are always vertical; there are sloping functions
* (!!!) er...elsewhere. Only the sides need be vertical, as the top and
* bottom of the polygon will need to be angled as the camera perspective
* shifts (user spins in a circle, etc.)
*
* uwal is an array of the upper most pixels, and dwal are the lower most.
* This must be a list, as the top and bottom of the polygon are not
* necessarily horizontal lines.
*
* So, the screen coordinate of the top left of a wall is specified by
* uwal[x1], the bottom left by dwal[x1], the top right by uwal[x2], and
* the bottom right by dwal[x2]. Every physical point on the edge of the
* wall in between is specified by traversing those arrays, one pixel per
* element.
*
* --ryan.
*/
static void wallscan(int32_t x1, int32_t x2,
int16_t *uwal, int16_t *dwal,
int32_t *swal, int32_t *lwal)
{
int32_t x, xnice, ynice;
intptr_t i;
uint8_t* fpalookup;
int32_t y1ve[4], y2ve[4], u4, d4, z, tileWidth, tsizy;
uint8_t bad;
tileWidth = tiles[globalpicnum].dim.width;
tsizy = tiles[globalpicnum].dim.height;
setgotpic(globalpicnum);
if ((tileWidth <= 0) || (tsizy <= 0))
return;
if ((uwal[x1] > ydimen) && (uwal[x2] > ydimen))
return;
if ((dwal[x1] < 0) && (dwal[x2] < 0))
return;
TILE_MakeAvailable(globalpicnum);
xnice = (pow2long[picsiz[globalpicnum]&15] == tileWidth);
if (xnice)
tileWidth--;
ynice = (pow2long[picsiz[globalpicnum]>>4] == tsizy);
if (ynice)
tsizy = (picsiz[globalpicnum]>>4);
fpalookup = palookup[globalpal];
setupvlineasm(globalshiftval);
//Starting on the left column of the wall, check the occlusion arrays.
x = x1;
while ((umost[x] > dmost[x]) && (x <= x2))
x++;
for(; (x<=x2)&&((x+frameoffset-(uint8_t*)NULL)&3); x++)
{
y1ve[0] = max(uwal[x],umost[x]);
y2ve[0] = min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0])
continue;
palookupoffse[0] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x],globvis),globalshade)<<8);
bufplce[0] = lwal[x] + globalxpanning;
if (bufplce[0] >= tileWidth)
{
if (xnice == 0)
bufplce[0] %= tileWidth;
else
bufplce[0] &= tileWidth;
}
if (ynice == 0)
bufplce[0] *= tsizy;
else
bufplce[0] <<= tsizy;
vince[0] = swal[x]*globalyscale;
vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);
vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+tiles[globalpicnum].data,x+frameoffset+ylookup[y1ve[0]]);
}
for(; x<=x2-3; x+=4)
{
bad = 0;
for(z=3; z>=0; z--)
{
y1ve[z] = max(uwal[x+z],umost[x+z]);
y2ve[z] = min(dwal[x+z],dmost[x+z])-1;
if (y2ve[z] < y1ve[z])
{
bad += pow2char[z];
continue;
}
i = lwal[x+z] + globalxpanning;
if (i >= tileWidth) {
if (xnice == 0) i %= tileWidth;
else i &= tileWidth;
}
if (ynice == 0)
i *= tsizy;
else
i <<= tsizy;
bufplce[z] = tiles[globalpicnum].data+i;
vince[z] = swal[x+z]*globalyscale;
vplce[z] = globalzd + vince[z]*(y1ve[z]-globalhoriz+1);
}
if (bad == 15)
continue;
palookupoffse[0] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x],globvis),globalshade)<<8);
palookupoffse[3] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x+3],globvis),globalshade)<<8);
if ((palookupoffse[0] == palookupoffse[3]) && ((bad&0x9) == 0))
{
palookupoffse[1] = palookupoffse[0];
palookupoffse[2] = palookupoffse[0];
}
else
{
palookupoffse[1] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x+1],globvis),globalshade)<<8);
palookupoffse[2] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x+2],globvis),globalshade)<<8);
}
u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3]));
d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3]));
if ((bad != 0) || (u4 >= d4))
{
if (!(bad&1))
prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+x+frameoffset+0);
if (!(bad&2))
prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+x+frameoffset+1);
if (!(bad&4))
prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+x+frameoffset+2);
if (!(bad&8))
prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+x+frameoffset+3);
continue;
}
if (u4 > y1ve[0])
vplce[0] =prevlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+x+frameoffset+0);
if (u4 > y1ve[1])
vplce[1] = prevlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+x+frameoffset+1);
if (u4 > y1ve[2])
vplce[2] = prevlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+x+frameoffset+2);
if (u4 > y1ve[3])
vplce[3] = prevlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+x+frameoffset+3);
if (d4 >= u4)
vlineasm4(d4-u4+1,ylookup[u4]+x+frameoffset);
i = x+frameoffset+ylookup[d4+1];
if (y2ve[0] > d4)
prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0);
if (y2ve[1] > d4)
prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1);
if (y2ve[2] > d4)
prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2);
if (y2ve[3] > d4)
prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3);
}
for(; x<=x2; x++)
{
y1ve[0] = max(uwal[x],umost[x]);
y2ve[0] = min(dwal[x],dmost[x]);
if (y2ve[0] <= y1ve[0])
continue;
palookupoffse[0] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x],globvis),globalshade)<<8);
bufplce[0] = lwal[x] + globalxpanning;
if (bufplce[0] >= tileWidth) {
if (xnice == 0)
bufplce[0] %= tileWidth;
else
bufplce[0] &= tileWidth;
}
if (ynice == 0) bufplce[0]
*= tsizy;
else
bufplce[0] <<= tsizy;
vince[0] = swal[x]*globalyscale;
vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);
vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+tiles[globalpicnum].data,x+frameoffset+ylookup[y1ve[0]]);
}
faketimerhandler();
}
/* this renders masking sprites. See wallscan(). --ryan. */
static void maskwallscan(int32_t x1, int32_t x2,
short *uwal, short *dwal,
int32_t *swal, int32_t *lwal)
{
int32_t x, startx, xnice, ynice;
intptr_t i;
uint8_t* fpalookup;
int32_t y1ve[4], y2ve[4], u4, d4, dax, z, tileWidth, tileHeight;
uint8_t* p;
uint8_t bad;
tileWidth = tiles[globalpicnum].dim.width;
tileHeight = tiles[globalpicnum].dim.height;
setgotpic(globalpicnum);
if ((tileWidth <= 0) || (tileHeight <= 0))
return;
if ((uwal[x1] > ydimen) && (uwal[x2] > ydimen))
return;
if ((dwal[x1] < 0) && (dwal[x2] < 0))
return;
TILE_MakeAvailable(globalpicnum);
startx = x1;
xnice = (pow2long[picsiz[globalpicnum]&15] == tileWidth);
if (xnice)
tileWidth = (tileWidth-1);
ynice = (pow2long[picsiz[globalpicnum]>>4] == tileHeight);
if (ynice)
tileHeight = (picsiz[globalpicnum]>>4);
fpalookup = palookup[globalpal];
setupmvlineasm(globalshiftval);
x = startx;
while ((startumost[x+windowx1] > startdmost[x+windowx1]) && (x <= x2)) x++;
p = x+frameoffset;
for(; (x<=x2)&&((p-(uint8_t*)NULL)&3); x++,p++)
{
y1ve[0] = max(uwal[x],startumost[x+windowx1]-windowy1);
y2ve[0] = min(dwal[x],startdmost[x+windowx1]-windowy1);
if (y2ve[0] <= y1ve[0]) continue;
palookupoffse[0] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x],globvis),globalshade)<<8);
bufplce[0] = lwal[x] + globalxpanning;
if (bufplce[0] >= tileWidth) {
if (xnice == 0) bufplce[0] %= tileWidth;
else bufplce[0] &= tileWidth;
}
if (ynice == 0)
bufplce[0] *= tileHeight;
else
bufplce[0] <<= tileHeight;
vince[0] = swal[x]*globalyscale;
vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);
mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+tiles[globalpicnum].data,p+ylookup[y1ve[0]]);
}
for(; x<=x2-3; x+=4,p+=4)
{
bad = 0;
for(z=3,dax=x+3; z>=0; z--,dax--)
{
y1ve[z] = max(uwal[dax],startumost[dax+windowx1]-windowy1);
y2ve[z] = min(dwal[dax],startdmost[dax+windowx1]-windowy1)-1;
if (y2ve[z] < y1ve[z]) {
bad += pow2char[z];
continue;
}
i = lwal[dax] + globalxpanning;
if (i >= tileWidth) {
if (xnice == 0) i %= tileWidth;
else i &= tileWidth;
}
if (ynice == 0)
i *= tileHeight;
else
i <<= tileHeight;
bufplce[z] = tiles[globalpicnum].data+i;
vince[z] = swal[dax]*globalyscale;
vplce[z] = globalzd + vince[z]*(y1ve[z]-globalhoriz+1);
}
if (bad == 15) continue;
palookupoffse[0] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x],globvis),globalshade)<<8);
palookupoffse[3] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x+3],globvis),globalshade)<<8);
if ((palookupoffse[0] == palookupoffse[3]) && ((bad&0x9) == 0))
{
palookupoffse[1] = palookupoffse[0];
palookupoffse[2] = palookupoffse[0];
}
else
{
palookupoffse[1] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x+1],globvis),globalshade)<<8);
palookupoffse[2] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x+2],globvis),globalshade)<<8);
}
u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3]));
d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3]));
if ((bad > 0) || (u4 >= d4))
{
if (!(bad&1)) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0);
if (!(bad&2)) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1);
if (!(bad&4)) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2);
if (!(bad&8)) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3);
continue;
}
if (u4 > y1ve[0]) vplce[0] = mvlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0);
if (u4 > y1ve[1]) vplce[1] = mvlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1);
if (u4 > y1ve[2]) vplce[2] = mvlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2);
if (u4 > y1ve[3]) vplce[3] = mvlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3);
if (d4 >= u4) mvlineasm4(d4-u4+1,ylookup[u4]+p);
i = p+ylookup[d4+1];
if (y2ve[0] > d4) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0);
if (y2ve[1] > d4) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1);
if (y2ve[2] > d4) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2);
if (y2ve[3] > d4) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3);
}
for(; x<=x2; x++,p++)
{
y1ve[0] = max(uwal[x],startumost[x+windowx1]-windowy1);
y2ve[0] = min(dwal[x],startdmost[x+windowx1]-windowy1);
if (y2ve[0] <= y1ve[0]) continue;
palookupoffse[0] = fpalookup+(getpalookup((int32_t)mulscale16(swal[x],globvis),globalshade)<<8);
bufplce[0] = lwal[x] + globalxpanning;
if (bufplce[0] >= tileWidth) {
if (xnice == 0) bufplce[0] %= tileWidth;
else bufplce[0] &= tileWidth;
}
if (ynice == 0)
bufplce[0] *= tileHeight;
else
bufplce[0] <<= tileHeight;
vince[0] = swal[x]*globalyscale;
vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);
mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+tiles[globalpicnum].data,p+ylookup[y1ve[0]]);
}
faketimerhandler();
}
/* renders parallaxed skies/floors --ryan. */
static void parascan(int32_t dax1, int32_t dax2, int32_t sectnum,uint8_t dastat, int32_t bunch)
{
sectortype *sec;
int32_t j, k, l, m, n, x, z, wallnum, nextsectnum, globalhorizbak;
short *topptr, *botptr;
sectnum = pvWalls[bunchfirst[bunch]].sectorId;
sec = &sector[sectnum];
globalhorizbak = globalhoriz;
if (parallaxyscale != 65536)
globalhoriz = mulscale16(globalhoriz-(ydimen>>1),parallaxyscale) + (ydimen>>1);
globvis = globalpisibility;
/* globalorientation = 0L; */
if (sec->visibility != 0) globvis = mulscale4(globvis,(int32_t)((uint8_t )(sec->visibility+16)));
if (dastat == 0)
{
globalpal = sec->ceilingpal;
globalpicnum = sec->ceilingpicnum;
globalshade = (int32_t)sec->ceilingshade;
globalxpanning = (int32_t)sec->ceilingxpanning;
globalypanning = (int32_t)sec->ceilingypanning;
topptr = umost;
botptr = uplc;
}
else
{
globalpal = sec->floorpal;
globalpicnum = sec->floorpicnum;
globalshade = (int32_t)sec->floorshade;
globalxpanning = (int32_t)sec->floorxpanning;
globalypanning = (int32_t)sec->floorypanning;
topptr = dplc;
botptr = dmost;
}
if ((uint32_t)globalpicnum >= (uint32_t)MAXTILES) globalpicnum = 0;
if (tiles[globalpicnum].animFlags&192)
globalpicnum += animateoffs(globalpicnum);
globalshiftval = (picsiz[globalpicnum]>>4);
if (pow2long[globalshiftval] != tiles[globalpicnum].dim.height)
globalshiftval++;
globalshiftval = 32-globalshiftval;
globalzd = (((tiles[globalpicnum].dim.height>>1)+parallaxyoffs)<<globalshiftval)+(globalypanning<<24);
globalyscale = (8<<(globalshiftval-19));
/*if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd;*/
k = 11 - (picsiz[globalpicnum]&15) - pskybits;
x = -1;
for(z=bunchfirst[bunch]; z>=0; z=bunchWallsList[z])
{
wallnum = pvWalls[z].worldWallId;
nextsectnum = wall[wallnum].nextsector;
if (dastat == 0) j = sector[nextsectnum].ceilingstat;
else j = sector[nextsectnum].floorstat;
if ((nextsectnum < 0) || (wall[wallnum].cstat&32) || ((j&1) == 0))
{
if (x == -1) x = pvWalls[z].screenSpaceCoo[0][VEC_COL];
if (parallaxtype == 0)
{
n = mulscale16(xdimenrecip,viewingrange);
for(j=pvWalls[z].screenSpaceCoo[0][VEC_COL]; j<=pvWalls[z].screenSpaceCoo[1][VEC_COL]; j++)
lplc[j] = (((mulscale23(j-halfxdimen,n)+globalang)&2047)>>k);
}
else
{
for(j=pvWalls[z].screenSpaceCoo[0][VEC_COL]; j<=pvWalls[z].screenSpaceCoo[1][VEC_COL]; j++)
lplc[j] = ((((int32_t)radarang2[j]+globalang)&2047)>>k);
}
if (parallaxtype == 2)
{
n = mulscale16(xdimscale,viewingrange);
for(j=pvWalls[z].screenSpaceCoo[0][VEC_COL]; j<=pvWalls[z].screenSpaceCoo[1][VEC_COL]; j++)
swplc[j] = mulscale14(sintable[((int32_t)radarang2[j]+512)&2047],n);
}
else
clearbuf(&swplc[pvWalls[z].screenSpaceCoo[0][VEC_COL]],pvWalls[z].screenSpaceCoo[1][VEC_COL]-pvWalls[z].screenSpaceCoo[0][VEC_COL]+1,mulscale16(xdimscale,viewingrange));
}
else if (x >= 0)
{
l = globalpicnum;
m = (picsiz[globalpicnum]&15);
globalpicnum = l+pskyoff[lplc[x]>>m];
if (((lplc[x]^lplc[pvWalls[z].screenSpaceCoo[0][VEC_COL]-1])>>m) == 0)
wallscan(x,pvWalls[z].screenSpaceCoo[0][VEC_COL]-1,topptr,botptr,swplc,lplc);
else
{
j = x;
while (x < pvWalls[z].screenSpaceCoo[0][VEC_COL])
{
n = l+pskyoff[lplc[x]>>m];
if (n != globalpicnum)
{
wallscan(j,x-1,topptr,botptr,swplc,lplc);
j = x;
globalpicnum = n;
}
x++;
}
if (j < x)
wallscan(j,x-1,topptr,botptr,swplc,lplc);
}
globalpicnum = l;
x = -1;
}
}
if (x >= 0)
{
l = globalpicnum;
m = (picsiz[globalpicnum]&15);
globalpicnum = l+pskyoff[lplc[x]>>m];
if (((lplc[x]^lplc[pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL]])>>m) == 0)
wallscan(x,pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL],topptr,botptr,swplc,lplc);
else
{
j = x;
while (x <= pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL])
{
n = l+pskyoff[lplc[x]>>m];
if (n != globalpicnum)
{
wallscan(j,x-1,topptr,botptr,swplc,lplc);
j = x;
globalpicnum = n;
}
x++;
}
if (j <= x)
wallscan(j,x,topptr,botptr,swplc,lplc);
}
globalpicnum = l;
}
globalhoriz = globalhorizbak;
}
#define BITSOFPRECISION 3 /* Don't forget to change this in A.ASM also! */
static void grouscan (int32_t dax1, int32_t dax2, int32_t sectnum, uint8_t dastat)
{
int32_t i, j, l, x, y, dx, dy, wx, wy, y1, y2, daz;
int32_t daslope, dasqr;
int32_t shoffs, shinc, m1, m2, *mptr1, *mptr2, *nptr1, *nptr2;
walltype *wal;
sectortype *sec;
sec = &sector[sectnum];
if (dastat == 0)
{
if (globalposz <= getceilzofslope((short) sectnum,globalposx,globalposy))
return; /* Back-face culling */
globalorientation = sec->ceilingstat;
globalpicnum = sec->ceilingpicnum;
globalshade = sec->ceilingshade;
globalpal = sec->ceilingpal;
daslope = sec->ceilingheinum;
daz = sec->ceilingz;
}
else
{
if (globalposz >= getflorzofslope((short) sectnum,globalposx,globalposy))
return; /* Back-face culling */
globalorientation = sec->floorstat;
globalpicnum = sec->floorpicnum;
globalshade = sec->floorshade;
globalpal = sec->floorpal;
daslope = sec->floorheinum;
daz = sec->floorz;
}
if ((tiles[globalpicnum].animFlags&192) != 0)
globalpicnum += animateoffs(globalpicnum);
setgotpic(globalpicnum);
if ((tiles[globalpicnum].dim.width <= 0) ||
(tiles[globalpicnum].dim.height <= 0))
return;
TILE_MakeAvailable(globalpicnum);
wal = &wall[sec->wallptr];
wx = wall[wal->point2].x - wal->x;
wy = wall[wal->point2].y - wal->y;
dasqr = krecipasm(nsqrtasm(wx*wx+wy*wy));
i = mulscale21(daslope,dasqr);
wx *= i;
wy *= i;
globalx = -mulscale19(singlobalang,xdimenrecip);
globaly = mulscale19(cosglobalang,xdimenrecip);
globalx1 = (globalposx<<8);
globaly1 = -(globalposy<<8);
i = (dax1-halfxdimen)*xdimenrecip;
globalx2 = mulscale16(cosglobalang<<4,viewingrangerecip) - mulscale27(singlobalang,i);
globaly2 = mulscale16(singlobalang<<4,viewingrangerecip) + mulscale27(cosglobalang,i);
globalzd = (xdimscale<<9);
globalzx = -dmulscale17(wx,globaly2,-wy,globalx2) + mulscale10(1-globalhoriz,globalzd);
globalz = -dmulscale25(wx,globaly,-wy,globalx);
if (globalorientation&64) /* Relative alignment */
{
dx = mulscale14(wall[wal->point2].x-wal->x,dasqr);
dy = mulscale14(wall[wal->point2].y-wal->y,dasqr);
i = nsqrtasm(daslope*daslope+16777216);
x = globalx;
y = globaly;
globalx = dmulscale16(x,dx,y,dy);
globaly = mulscale12(dmulscale16(-y,dx,x,dy),i);
x = ((wal->x-globalposx)<<8);
y = ((wal->y-globalposy)<<8);
globalx1 = dmulscale16(-x,dx,-y,dy);
globaly1 = mulscale12(dmulscale16(-y,dx,x,dy),i);
x = globalx2;
y = globaly2;
globalx2 = dmulscale16(x,dx,y,dy);
globaly2 = mulscale12(dmulscale16(-y,dx,x,dy),i);
}
if (globalorientation&0x4)
{
i = globalx;
globalx = -globaly;
globaly = -i;
i = globalx1;
globalx1 = globaly1;
globaly1 = i;
i = globalx2;
globalx2 = -globaly2;
globaly2 = -i;
}
if (globalorientation&0x10) {
globalx1 = -globalx1, globalx2 = -globalx2, globalx = -globalx;
}
if (globalorientation&0x20) {
globaly1 = -globaly1, globaly2 = -globaly2, globaly = -globaly;
}
daz = dmulscale9(wx,globalposy-wal->y,-wy,globalposx-wal->x) + ((daz-globalposz)<<8);
globalx2 = mulscale20(globalx2,daz);
globalx = mulscale28(globalx,daz);
globaly2 = mulscale20(globaly2,-daz);
globaly = mulscale28(globaly,-daz);
i = 8-(picsiz[globalpicnum]&15);
j = 8-(picsiz[globalpicnum]>>4);
if (globalorientation&8) {
i++;
j++;
}
globalx1 <<= (i+12);
globalx2 <<= i;
globalx <<= i;
globaly1 <<= (j+12);
globaly2 <<= j;
globaly <<= j;
if (dastat == 0)
{
globalx1 += (((int32_t)sec->ceilingxpanning)<<24);
globaly1 += (((int32_t)sec->ceilingypanning)<<24);
}
else
{
globalx1 += (((int32_t)sec->floorxpanning)<<24);
globaly1 += (((int32_t)sec->floorypanning)<<24);
}
asm1 = -(globalzd>>(16-BITSOFPRECISION));
globvis = globalvisibility;
if (sec->visibility != 0) globvis = mulscale4(globvis,(int32_t)((uint8_t )(sec->visibility+16)));
globvis = mulscale13(globvis,daz);
globvis = mulscale16(globvis,xdimscale);
j =(int32_t) FP_OFF(palookup[globalpal]);
setupslopevlin(((int32_t)(picsiz[globalpicnum]&15))+(((int32_t)(picsiz[globalpicnum]>>4))<<8),tiles[globalpicnum].data,-ylookup[1]);
l = (globalzd>>16);
shinc = mulscale16(globalz,xdimenscale);
if (shinc > 0)
shoffs = (4<<15);
else
shoffs = ((16380-ydimen)<<15); // JBF: was 2044 16380
if (dastat == 0) y1 = umost[dax1];
else y1 = max(umost[dax1],dplc[dax1]);
m1 = mulscale16(y1,globalzd) + (globalzx>>6);
/* Avoid visibility overflow by crossing horizon */
if (globalzd > 0) m1 += (globalzd>>16);
else m1 -= (globalzd>>16);
m2 = m1+l;
mptr1 = (int32_t *)&slopalookup[y1+(shoffs>>15)];
mptr2 = mptr1+1;
for(x=dax1; x<=dax2; x++)
{
if (dastat == 0) {
y1 = umost[x];
y2 = min(dmost[x],uplc[x])-1;
}
else {
y1 = max(umost[x],dplc[x]);
y2 = dmost[x]-1;
}
if (y1 <= y2)
{
nptr1 = (int32_t *)&slopalookup[y1+(shoffs>>15)];
nptr2 = (int32_t *)&slopalookup[y2+(shoffs>>15)];
while (nptr1 <= mptr1)
{
*mptr1-- = j + (getpalookup((int32_t)mulscale24(krecipasm(m1),globvis),globalshade)<<8);
m1 -= l;
}
while (nptr2 >= mptr2)
{
*mptr2++ = j + (getpalookup((int32_t)mulscale24(krecipasm(m2),globvis),globalshade)<<8);
m2 += l;
}
globalx3 = (globalx2>>10);
globaly3 = (globaly2>>10);
asm3 = mulscale16(y2,globalzd) + (globalzx>>6);
slopevlin(ylookup[y2]+x+frameoffset,krecipasm(asm3>>3),(int32_t)nptr2,y2-y1+1,globalx1,globaly1);
if ((x&15) == 0) faketimerhandler();
}
globalx2 += globalx;
globaly2 += globaly;
globalzx += globalz;
shoffs += shinc;
}
}
static int owallmost(short *mostbuf, int32_t w, int32_t z)
{
int32_t bad, inty, xcross, y, yinc;
int32_t s1, s2, s3, s4, ix1, ix2, iy1, iy2, t;
z <<= 7;
s1 = mulscale20(globaluclip,pvWalls[w].screenSpaceCoo[0][VEC_DIST]);
s2 = mulscale20(globaluclip,pvWalls[w].screenSpaceCoo[1][VEC_DIST]);
s3 = mulscale20(globaldclip,pvWalls[w].screenSpaceCoo[0][VEC_DIST]);
s4 = mulscale20(globaldclip,pvWalls[w].screenSpaceCoo[1][VEC_DIST]);
bad = (z<s1)+((z<s2)<<1)+((z>s3)<<2)+((z>s4)<<3);
ix1 = pvWalls[w].screenSpaceCoo[0][VEC_COL];
iy1 = pvWalls[w].screenSpaceCoo[0][VEC_DIST];
ix2 = pvWalls[w].screenSpaceCoo[1][VEC_COL];
iy2 = pvWalls[w].screenSpaceCoo[1][VEC_DIST];
if ((bad&3) == 3)
{
clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),0L);
return(bad);
}
if ((bad&12) == 12)
{
clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
return(bad);
}
if (bad&3)
{
t = divscale30(z-s1,s2-s1);
inty = pvWalls[w].screenSpaceCoo[0][VEC_DIST] + mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST]-pvWalls[w].screenSpaceCoo[0][VEC_DIST],t);
xcross = pvWalls[w].screenSpaceCoo[0][VEC_COL] + scale(mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST],t),pvWalls[w].screenSpaceCoo[1][VEC_COL]-pvWalls[w].screenSpaceCoo[0][VEC_COL],inty);
if ((bad&3) == 2)
{
if (pvWalls[w].screenSpaceCoo[0][VEC_COL] <= xcross) {
iy2 = inty;
ix2 = xcross;
}
clearbufbyte(&mostbuf[xcross+1],(pvWalls[w].screenSpaceCoo[1][VEC_COL]-xcross)*sizeof(mostbuf[0]),0L);
}
else
{
if (xcross <= pvWalls[w].screenSpaceCoo[1][VEC_COL]) {
iy1 = inty;
ix1 = xcross;
}
clearbufbyte(&mostbuf[pvWalls[w].screenSpaceCoo[0][VEC_COL]],(xcross-pvWalls[w].screenSpaceCoo[0][VEC_COL]+1)*sizeof(mostbuf[0]),0L);
}
}
if (bad&12)
{
t = divscale30(z-s3,s4-s3);
inty = pvWalls[w].screenSpaceCoo[0][VEC_DIST] + mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST]-pvWalls[w].screenSpaceCoo[0][VEC_DIST],t);
xcross = pvWalls[w].screenSpaceCoo[0][VEC_COL] + scale(mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST],t),pvWalls[w].screenSpaceCoo[1][VEC_COL]-pvWalls[w].screenSpaceCoo[0][VEC_COL],inty);
if ((bad&12) == 8)
{
if (pvWalls[w].screenSpaceCoo[0][VEC_COL] <= xcross) {
iy2 = inty;
ix2 = xcross;
}
clearbufbyte(&mostbuf[xcross+1],(pvWalls[w].screenSpaceCoo[1][VEC_COL]-xcross)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
}
else
{
if (xcross <= pvWalls[w].screenSpaceCoo[1][VEC_COL]) {
iy1 = inty;
ix1 = xcross;
}
clearbufbyte(&mostbuf[pvWalls[w].screenSpaceCoo[0][VEC_COL]],(xcross-pvWalls[w].screenSpaceCoo[0][VEC_COL]+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
}
}
y = (scale(z,xdimenscale,iy1)<<4);
yinc = ((scale(z,xdimenscale,iy2)<<4)-y) / (ix2-ix1+1);
qinterpolatedown16short((int32_t *)&mostbuf[ix1],ix2-ix1+1,y+(globalhoriz<<16),yinc);
if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
if (mostbuf[ix1] > ydimen) mostbuf[ix1] = ydimen;
if (mostbuf[ix2] < 0) mostbuf[ix2] = 0;
if (mostbuf[ix2] > ydimen) mostbuf[ix2] = ydimen;
return(bad);
}
static int wallmost(short *mostbuf, int32_t w, int32_t sectnum, uint8_t dastat)
{
int32_t bad, i, j, t, y, z, inty, intz, xcross, yinc, fw;
int32_t x1, y1, z1, x2, y2, z2, xv, yv, dx, dy, dasqr, oz1, oz2;
int32_t s1, s2, s3, s4, ix1, ix2, iy1, iy2;
if (dastat == 0){
z = sector[sectnum].ceilingz-globalposz;
if ((sector[sectnum].ceilingstat&2) == 0)
return(owallmost(mostbuf,w,z));
}
else{
z = sector[sectnum].floorz-globalposz;
if ((sector[sectnum].floorstat&2) == 0)
return(owallmost(mostbuf,w,z));
}
i = pvWalls[w].worldWallId;
if (i == sector[sectnum].wallptr)
return(owallmost(mostbuf,w,z));
x1 = wall[i].x;
x2 = wall[wall[i].point2].x-x1;
y1 = wall[i].y;
y2 = wall[wall[i].point2].y-y1;
fw = sector[sectnum].wallptr;
i = wall[fw].point2;
dx = wall[i].x-wall[fw].x;
dy = wall[i].y-wall[fw].y;
dasqr = krecipasm(nsqrtasm(dx*dx+dy*dy));
if (pvWalls[w].screenSpaceCoo[0][VEC_COL] == 0){
xv = cosglobalang+sinviewingrangeglobalang;
yv = singlobalang-cosviewingrangeglobalang;
}
else{
xv = x1-globalposx;
yv = y1-globalposy;
}
i = xv*(y1-globalposy)-yv*(x1-globalposx);
j = yv*x2-xv*y2;
if (klabs(j) > klabs(i>>3))
i = divscale28(i,j);
if (dastat == 0){
t = mulscale15(sector[sectnum].ceilingheinum,dasqr);
z1 = sector[sectnum].ceilingz;
}
else{
t = mulscale15(sector[sectnum].floorheinum,dasqr);
z1 = sector[sectnum].floorz;
}
z1 = dmulscale24(dx*t,mulscale20(y2,i)+((y1-wall[fw].y)<<8),-dy*t,mulscale20(x2,i)+((x1-wall[fw].x)<<8))+((z1-globalposz)<<7);
if (pvWalls[w].screenSpaceCoo[1][VEC_COL] == xdimen-1){
xv = cosglobalang-sinviewingrangeglobalang;
yv = singlobalang+cosviewingrangeglobalang;
}
else{
xv = (x2+x1)-globalposx;
yv = (y2+y1)-globalposy;
}
i = xv*(y1-globalposy)-yv*(x1-globalposx);
j = yv*x2-xv*y2;
if (klabs(j) > klabs(i>>3))
i = divscale28(i,j);
if (dastat == 0){
t = mulscale15(sector[sectnum].ceilingheinum,dasqr);
z2 = sector[sectnum].ceilingz;
}
else{
t = mulscale15(sector[sectnum].floorheinum,dasqr);
z2 = sector[sectnum].floorz;
}
z2 = dmulscale24(dx*t,mulscale20(y2,i)+((y1-wall[fw].y)<<8),-dy*t,mulscale20(x2,i)+((x1-wall[fw].x)<<8))+((z2-globalposz)<<7);
s1 = mulscale20(globaluclip,pvWalls[w].screenSpaceCoo[0][VEC_DIST]);
s2 = mulscale20(globaluclip,pvWalls[w].screenSpaceCoo[1][VEC_DIST]);
s3 = mulscale20(globaldclip,pvWalls[w].screenSpaceCoo[0][VEC_DIST]);
s4 = mulscale20(globaldclip,pvWalls[w].screenSpaceCoo[1][VEC_DIST]);
bad = (z1<s1)+((z2<s2)<<1)+((z1>s3)<<2)+((z2>s4)<<3);
ix1 = pvWalls[w].screenSpaceCoo[0][VEC_COL];
ix2 = pvWalls[w].screenSpaceCoo[1][VEC_COL];
iy1 = pvWalls[w].screenSpaceCoo[0][VEC_DIST];
iy2 = pvWalls[w].screenSpaceCoo[1][VEC_DIST];
oz1 = z1;
oz2 = z2;
if ((bad&3) == 3){
clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),0L);
return(bad);
}
if ((bad&12) == 12){
clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
return(bad);
}
if (bad&3){
/* inty = intz / (globaluclip>>16) */
t = divscale30(oz1-s1,s2-s1+oz1-oz2);
inty = pvWalls[w].screenSpaceCoo[0][VEC_DIST] + mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST]-pvWalls[w].screenSpaceCoo[0][VEC_DIST],t);
intz = oz1 + mulscale30(oz2-oz1,t);
xcross = pvWalls[w].screenSpaceCoo[0][VEC_COL] + scale(mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST],t),pvWalls[w].screenSpaceCoo[1][VEC_COL]-pvWalls[w].screenSpaceCoo[0][VEC_COL],inty);
if ((bad&3) == 2){
if (pvWalls[w].screenSpaceCoo[0][VEC_COL] <= xcross){
z2 = intz;
iy2 = inty;
ix2 = xcross;
}
clearbufbyte(&mostbuf[xcross+1],(pvWalls[w].screenSpaceCoo[1][VEC_COL]-xcross)*sizeof(mostbuf[0]),0L);
}
else{
if (xcross <= pvWalls[w].screenSpaceCoo[1][VEC_COL]) {
z1 = intz;
iy1 = inty;
ix1 = xcross;
}
clearbufbyte(&mostbuf[pvWalls[w].screenSpaceCoo[0][VEC_COL]],(xcross-pvWalls[w].screenSpaceCoo[0][VEC_COL]+1)*sizeof(mostbuf[0]),0L);
}
}
if (bad&12){
/* inty = intz / (globaldclip>>16) */
t = divscale30(oz1-s3,s4-s3+oz1-oz2);
inty = pvWalls[w].screenSpaceCoo[0][VEC_DIST] + mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST]-pvWalls[w].screenSpaceCoo[0][VEC_DIST],t);
intz = oz1 + mulscale30(oz2-oz1,t);
xcross = pvWalls[w].screenSpaceCoo[0][VEC_COL] + scale(mulscale30(pvWalls[w].screenSpaceCoo[1][VEC_DIST],t),pvWalls[w].screenSpaceCoo[1][VEC_COL]-pvWalls[w].screenSpaceCoo[0][VEC_COL],inty);
if ((bad&12) == 8){
if (pvWalls[w].screenSpaceCoo[0][VEC_COL] <= xcross) {
z2 = intz;
iy2 = inty;
ix2 = xcross;
}
clearbufbyte(&mostbuf[xcross+1],(pvWalls[w].screenSpaceCoo[1][VEC_COL]-xcross)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
}
else{
if (xcross <= pvWalls[w].screenSpaceCoo[1][VEC_COL]) {
z1 = intz;
iy1 = inty;
ix1 = xcross;
}
clearbufbyte(&mostbuf[pvWalls[w].screenSpaceCoo[0][VEC_COL]],(xcross-pvWalls[w].screenSpaceCoo[0][VEC_COL]+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
}
}
y = (scale(z1,xdimenscale,iy1)<<4);
yinc = ((scale(z2,xdimenscale,iy2)<<4)-y) / (ix2-ix1+1);
qinterpolatedown16short((int32_t *)&mostbuf[ix1],ix2-ix1+1,y+(globalhoriz<<16),yinc);
if (mostbuf[ix1] < 0)
mostbuf[ix1] = 0;
if (mostbuf[ix1] > ydimen)
mostbuf[ix1] = ydimen;
if (mostbuf[ix2] < 0)
mostbuf[ix2] = 0;
if (mostbuf[ix2] > ydimen)
mostbuf[ix2] = ydimen;
return(bad);
}
static void drawalls(int32_t bunch)
{
sectortype *sec, *nextsec;
walltype *wal;
int32_t i, x, x1, x2, cz[5], fz[5];
int32_t z, wallnum, sectnum, nextsectnum;
int32_t startsmostwallcnt, startsmostcnt, gotswall;
uint8_t andwstat1, andwstat2;
z = bunchfirst[bunch];
sectnum = pvWalls[z].sectorId;
sec = &sector[sectnum];
andwstat1 = 0xff;
andwstat2 = 0xff;
for(; z>=0; z=bunchWallsList[z]){ /* uplc/dplc calculation */
andwstat1 &= wallmost(uplc,z,sectnum,(uint8_t )0);
andwstat2 &= wallmost(dplc,z,sectnum,(uint8_t )1);
}
/* draw ceilings */
if ((andwstat1&3) != 3){
if ((sec->ceilingstat&3) == 2)
grouscan(pvWalls[bunchfirst[bunch]].screenSpaceCoo[0][VEC_COL],pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL],sectnum,0);
else if ((sec->ceilingstat&1) == 0)
ceilscan(pvWalls[bunchfirst[bunch]].screenSpaceCoo[0][VEC_COL],pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL],sectnum);
else
parascan(pvWalls[bunchfirst[bunch]].screenSpaceCoo[0][VEC_COL],pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL],sectnum,0,bunch);
}
/* draw floors */
if ((andwstat2&12) != 12){
if ((sec->floorstat&3) == 2)
grouscan(pvWalls[bunchfirst[bunch]].screenSpaceCoo[0][VEC_COL],pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL],sectnum,1);
else if ((sec->floorstat&1) == 0)
florscan(pvWalls[bunchfirst[bunch]].screenSpaceCoo[0][VEC_COL],pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL],sectnum);
else
parascan(pvWalls[bunchfirst[bunch]].screenSpaceCoo[0][VEC_COL],pvWalls[bunchlast[bunch]].screenSpaceCoo[1][VEC_COL],sectnum,1,bunch);
}
/* DRAW WALLS SECTION! */
for(z=bunchfirst[bunch]; z>=0; z=bunchWallsList[z]){
x1 = pvWalls[z].screenSpaceCoo[0][VEC_COL];
x2 = pvWalls[z].screenSpaceCoo[1][VEC_COL];
if (umost[x2] >= dmost[x2])
{
for(x=x1; x<x2; x++)
if (umost[x] < dmost[x])
break;
if (x >= x2)
{
smostwall[smostwallcnt] = z;
smostwalltype[smostwallcnt] = 0;
smostwallcnt++;
continue;
}
}
wallnum = pvWalls[z].worldWallId;
wal = &wall[wallnum];
nextsectnum = wal->nextsector;
nextsec = &sector[nextsectnum];
gotswall = 0;
startsmostwallcnt = smostwallcnt;
startsmostcnt = smostcnt;
if ((searchit == 2) && (searchx >= x1) && (searchx <= x2))
{
if (searchy <= uplc[searchx]){ /* ceiling */
searchsector = sectnum;
searchwall = wallnum;
searchstat = 1;
searchit = 1;
}
else if (searchy >= dplc[searchx]){ /* floor */
searchsector = sectnum;
searchwall = wallnum;
searchstat = 2;
searchit = 1;
}
}
if (nextsectnum >= 0){
getzsofslope((short)sectnum,wal->x,wal->y,&cz[0],&fz[0]);
getzsofslope((short)sectnum,wall[wal->point2].x,wall[wal->point2].y,&cz[1],&fz[1]);
getzsofslope((short)nextsectnum,wal->x,wal->y,&cz[2],&fz[2]);
getzsofslope((short)nextsectnum,wall[wal->point2].x,wall[wal->point2].y,&cz[3],&fz[3]);
getzsofslope((short)nextsectnum,globalposx,globalposy,&cz[4],&fz[4]);
if ((wal->cstat&48) == 16)
maskwall[maskwallcnt++] = z;
if (((sec->ceilingstat&1) == 0) || ((nextsec->ceilingstat&1) == 0)){
if ((cz[2] <= cz[0]) && (cz[3] <= cz[1])){
if (globparaceilclip)
for(x=x1; x<=x2; x++)
if (uplc[x] > umost[x])
if (umost[x] <= dmost[x]){
umost[x] = uplc[x];
if (umost[x] > dmost[x]) numhits--;
}
}
else{
wallmost(dwall,z,nextsectnum,(uint8_t )0);
if ((cz[2] > fz[0]) || (cz[3] > fz[1]))
for(i=x1; i<=x2; i++) if (dwall[i] > dplc[i]) dwall[i] = dplc[i];
if ((searchit == 2) && (searchx >= x1) && (searchx <= x2))
if (searchy <= dwall[searchx]) /* wall */{
searchsector = sectnum;
searchwall = wallnum;
searchstat = 0;
searchit = 1;
}
globalorientation = (int32_t)wal->cstat;
globalpicnum = wal->picnum;
if ((uint32_t)globalpicnum >= (uint32_t)MAXTILES) globalpicnum = 0;
globalxpanning = (int32_t)wal->xpanning;
globalypanning = (int32_t)wal->ypanning;
globalshiftval = (picsiz[globalpicnum]>>4);
if (pow2long[globalshiftval] != tiles[globalpicnum].dim.height) globalshiftval++;
globalshiftval = 32-globalshiftval;
//Animated
if (tiles[globalpicnum].animFlags&192)
globalpicnum += animateoffs(globalpicnum);
globalshade = (int32_t)wal->shade;
globvis = globalvisibility;
if (sec->visibility != 0) globvis = mulscale4(globvis,(int32_t)((uint8_t )(sec->visibility+16)));
globalpal = (int32_t)wal->pal;
globalyscale = (wal->yrepeat<<(globalshiftval-19));
if ((globalorientation&4) == 0)
globalzd = (((globalposz-nextsec->ceilingz)*globalyscale)<<8);
else
globalzd = (((globalposz-sec->ceilingz)*globalyscale)<<8);
globalzd += (globalypanning<<24);
if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd;