// WL_DRAW.C #include "wl_def.h" #pragma hdrstop #include "wl_cloudsky.h" #include "wl_atmos.h" #include "wl_shade.h" /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ // the door is the last picture before the sprites #define DOORWALL (PMSpriteStart-8) #define ACTORSIZE 0x4000 /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ static byte *vbuf = NULL; unsigned vbufPitch = 0; int32_t lasttimecount; int32_t frameon; boolean fpscounter; int fps_frames=0, fps_time=0, fps=0; int *wallheight; int min_wallheight; // // math tables // short *pixelangle; int32_t finetangent[FINEANGLES/4]; fixed sintable[ANGLES+ANGLES/4]; fixed *costable = sintable+(ANGLES/4); // // refresh variables // fixed viewx,viewy; // the focal point short viewangle; fixed viewsin,viewcos; void TransformActor (objtype *ob); void BuildTables (void); void ClearScreen (void); int CalcRotate (objtype *ob); void DrawScaleds (void); void CalcTics (void); void ThreeDRefresh (void); // // wall optimization variables // int lastside; // true for vertical int32_t lastintercept; int lasttilehit; int lasttexture; // // ray tracing variables // short focaltx,focalty,viewtx,viewty; longword xpartialup,xpartialdown,ypartialup,ypartialdown; short midangle,angle; word tilehit; int pixx; short xtile,ytile; short xtilestep,ytilestep; int32_t xintercept,yintercept; word xstep,ystep; word xspot,yspot; int texdelta; word horizwall[MAXWALLTILES],vertwall[MAXWALLTILES]; /* ============================================================================ 3 - D DEFINITIONS ============================================================================ */ /* ======================== = = TransformActor = = Takes paramaters: = gx,gy : globalx/globaly of point = = globals: = viewx,viewy : point of view = viewcos,viewsin : sin/cos of viewangle = scale : conversion from global value to screen value = = sets: = screenx,transx,transy,screenheight: projected edge location and size = ======================== */ // // transform actor // void TransformActor (objtype *ob) { fixed gx,gy,gxt,gyt,nx,ny; // // translate point to view centered coordinates // gx = ob->x-viewx; gy = ob->y-viewy; // // calculate newx // gxt = FixedMul(gx,viewcos); gyt = FixedMul(gy,viewsin); nx = gxt-gyt-ACTORSIZE; // fudge the shape forward a bit, because // the midpoint could put parts of the shape // into an adjacent wall // // calculate newy // gxt = FixedMul(gx,viewsin); gyt = FixedMul(gy,viewcos); ny = gyt+gxt; // // calculate perspective ratio // ob->transx = nx; ob->transy = ny; if (nxviewheight = 0; return; } ob->viewx = (word)(centerx + ny*scale/nx); // // calculate height (heightnumerator/(nx>>8)) // ob->viewheight = (word)(heightnumerator/(nx>>8)); } //========================================================================== /* ======================== = = TransformTile = = Takes paramaters: = tx,ty : tile the object is centered in = = globals: = viewx,viewy : point of view = viewcos,viewsin : sin/cos of viewangle = scale : conversion from global value to screen value = = sets: = screenx,transx,transy,screenheight: projected edge location and size = = Returns true if the tile is withing getting distance = ======================== */ boolean TransformTile (int tx, int ty, short *dispx, short *dispheight) { fixed gx,gy,gxt,gyt,nx,ny; // // translate point to view centered coordinates // gx = ((int32_t)tx<>8)); } // // see if it should be grabbed // if (nx-TILEGLOBAL/2 && ny> 8); if(height < min_wallheight) min_wallheight = height; return height; } //========================================================================== /* =================== = = ScalePost = =================== */ byte *postsource; int postx; int postwidth; void ScalePost(void) { int ywcount, yoffs, yw, yd, yendoffs; byte col; #ifdef USE_SHADING byte *curshades = shadetable[GetShade(wallheight[postx])]; #endif ywcount = yd = wallheight[postx] >> 3; if(yd <= 0) yd = 100; yoffs = (viewheight / 2 - ywcount) * vbufPitch; if(yoffs < 0) yoffs = 0; yoffs += postx; yendoffs = viewheight / 2 + ywcount - 1; yw=TEXTURESIZE-1; while(yendoffs >= viewheight) { ywcount -= TEXTURESIZE/2; while(ywcount <= 0) { ywcount += yd; yw--; } yendoffs--; } if(yw < 0) return; #ifdef USE_SHADING col = curshades[postsource[yw]]; #else col = postsource[yw]; #endif yendoffs = yendoffs * vbufPitch + postx; while(yoffs <= yendoffs) { vbuf[yendoffs] = col; ywcount -= TEXTURESIZE/2; if(ywcount <= 0) { do { ywcount += yd; yw--; } while(ywcount <= 0); if(yw < 0) break; #ifdef USE_SHADING col = curshades[postsource[yw]]; #else col = postsource[yw]; #endif } yendoffs -= vbufPitch; } } void GlobalScalePost(byte *vidbuf, unsigned pitch) { vbuf = vidbuf; vbufPitch = pitch; ScalePost(); } /* ==================== = = HitVertWall = = tilehit bit 7 is 0, because it's not a door tile = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic = ==================== */ void HitVertWall (void) { int wallpic; int texture; texture = ((yintercept+texdelta)>>TEXTUREFROMFIXEDSHIFT)&TEXTUREMASK; if (xtilestep == -1) { texture = TEXTUREMASK-texture; xintercept += TILEGLOBAL; } if(lastside==1 && lastintercept==xtile && lasttilehit==tilehit && !(lasttilehit & 0x40)) { if((pixx&3) && texture == lasttexture) { ScalePost(); postx = pixx; wallheight[pixx] = wallheight[pixx-1]; return; } ScalePost(); wallheight[pixx] = CalcHeight(); postsource+=texture-lasttexture; postwidth=1; postx=pixx; lasttexture=texture; return; } if(lastside!=-1) ScalePost(); lastside=1; lastintercept=xtile; lasttilehit=tilehit; lasttexture=texture; wallheight[pixx] = CalcHeight(); postx = pixx; postwidth = 1; if (tilehit & 0x40) { // check for adjacent doors ytile = (short)(yintercept>>TILESHIFT); if ( tilemap[xtile-xtilestep][ytile]&0x80 ) wallpic = DOORWALL+3; else wallpic = vertwall[tilehit & ~0x40]; } else wallpic = vertwall[tilehit]; postsource = PM_GetTexture(wallpic) + texture; } /* ==================== = = HitHorizWall = = tilehit bit 7 is 0, because it's not a door tile = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic = ==================== */ void HitHorizWall (void) { int wallpic; int texture; texture = ((xintercept+texdelta)>>TEXTUREFROMFIXEDSHIFT)&TEXTUREMASK; if (ytilestep == -1) yintercept += TILEGLOBAL; else texture = TEXTUREMASK-texture; if(lastside==0 && lastintercept==ytile && lasttilehit==tilehit && !(lasttilehit & 0x40)) { if((pixx&3) && texture == lasttexture) { ScalePost(); postx=pixx; wallheight[pixx] = wallheight[pixx-1]; return; } ScalePost(); wallheight[pixx] = CalcHeight(); postsource+=texture-lasttexture; postwidth=1; postx=pixx; lasttexture=texture; return; } if(lastside!=-1) ScalePost(); lastside=0; lastintercept=ytile; lasttilehit=tilehit; lasttexture=texture; wallheight[pixx] = CalcHeight(); postx = pixx; postwidth = 1; if (tilehit & 0x40) { // check for adjacent doors xtile = (short)(xintercept>>TILESHIFT); if ( tilemap[xtile][ytile-ytilestep]&0x80) wallpic = DOORWALL+2; else wallpic = horizwall[tilehit & ~0x40]; } else wallpic = horizwall[tilehit]; postsource = PM_GetTexture(wallpic) + texture; } //========================================================================== /* ==================== = = HitHorizDoor = ==================== */ void HitHorizDoor (void) { int doorpage; int doornum; int texture; doornum = tilehit&0x7f; texture = ((xintercept-doorposition[doornum])>>TEXTUREFROMFIXEDSHIFT)&TEXTUREMASK; if(lasttilehit==tilehit) { if((pixx&3) && texture == lasttexture) { ScalePost(); postx=pixx; wallheight[pixx] = wallheight[pixx-1]; return; } ScalePost(); wallheight[pixx] = CalcHeight(); postsource+=texture-lasttexture; postwidth=1; postx=pixx; lasttexture=texture; return; } if(lastside!=-1) ScalePost(); lastside=2; lasttilehit=tilehit; lasttexture=texture; wallheight[pixx] = CalcHeight(); postx = pixx; postwidth = 1; switch(doorobjlist[doornum].lock) { case dr_normal: doorpage = DOORWALL; break; case dr_lock1: case dr_lock2: case dr_lock3: case dr_lock4: doorpage = DOORWALL+6; break; case dr_elevator: doorpage = DOORWALL+4; break; } postsource = PM_GetTexture(doorpage) + texture; } //========================================================================== /* ==================== = = HitVertDoor = ==================== */ void HitVertDoor (void) { int doorpage; int doornum; int texture; doornum = tilehit&0x7f; texture = ((yintercept-doorposition[doornum])>>TEXTUREFROMFIXEDSHIFT)&TEXTUREMASK; if(lasttilehit==tilehit) { if((pixx&3) && texture == lasttexture) { ScalePost(); postx=pixx; wallheight[pixx] = wallheight[pixx-1]; return; } ScalePost(); wallheight[pixx] = CalcHeight(); postsource+=texture-lasttexture; postwidth=1; postx=pixx; lasttexture=texture; return; } if(lastside!=-1) ScalePost(); lastside=2; lasttilehit=tilehit; lasttexture=texture; wallheight[pixx] = CalcHeight(); postx = pixx; postwidth = 1; switch(doorobjlist[doornum].lock) { case dr_normal: doorpage = DOORWALL+1; break; case dr_lock1: case dr_lock2: case dr_lock3: case dr_lock4: doorpage = DOORWALL+7; break; case dr_elevator: doorpage = DOORWALL+5; break; } postsource = PM_GetTexture(doorpage) + texture; } //========================================================================== #define HitHorizBorder HitHorizWall #define HitVertBorder HitVertWall //========================================================================== byte vgaCeiling[]= { #ifndef SPEAR 0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0xbf, 0x4e,0x4e,0x4e,0x1d,0x8d,0x4e,0x1d,0x2d,0x1d,0x8d, 0x1d,0x1d,0x1d,0x1d,0x1d,0x2d,0xdd,0x1d,0x1d,0x98, 0x1d,0x9d,0x2d,0xdd,0xdd,0x9d,0x2d,0x4d,0x1d,0xdd, 0x7d,0x1d,0x2d,0x2d,0xdd,0xd7,0x1d,0x1d,0x1d,0x2d, 0x1d,0x1d,0x1d,0x1d,0xdd,0xdd,0x7d,0xdd,0xdd,0xdd #else 0x6f,0x4f,0x1d,0xde,0xdf,0x2e,0x7f,0x9e,0xae,0x7f, 0x1d,0xde,0xdf,0xde,0xdf,0xde,0xe1,0xdc,0x2e,0x1d,0xdc #endif }; /* ===================== = = VGAClearScreen = ===================== */ void VGAClearScreen (void) { byte ceiling=vgaCeiling[gamestate.episode*10+mapon]; int y; byte *ptr = vbuf; #ifdef USE_SHADING for(y = 0; y < viewheight / 2; y++, ptr += vbufPitch) memset(ptr, shadetable[GetShade((viewheight / 2 - y) << 3)][ceiling], viewwidth); for(; y < viewheight; y++, ptr += vbufPitch) memset(ptr, shadetable[GetShade((y - viewheight / 2) << 3)][0x19], viewwidth); #else for(y = 0; y < viewheight / 2; y++, ptr += vbufPitch) memset(ptr, ceiling, viewwidth); for(; y < viewheight; y++, ptr += vbufPitch) memset(ptr, 0x19, viewwidth); #endif } //========================================================================== /* ===================== = = CalcRotate = ===================== */ int CalcRotate (objtype *ob) { int angle, viewangle; // this isn't exactly correct, as it should vary by a trig value, // but it is close enough with only eight rotations viewangle = player->angle + (centerx - ob->viewx)/8; if (ob->obclass == rocketobj || ob->obclass == hrocketobj) angle = (viewangle-180) - ob->angle; else angle = (viewangle-180) - dirangle[ob->dir]; angle+=ANGLES/16; while (angle>=ANGLES) angle-=ANGLES; while (angle<0) angle+=ANGLES; if (ob->state->rotate == 2) // 2 rotation pain frame return 0; // pain with shooting frame bugfix return angle/(ANGLES/8); } void ScaleShape (int xcenter, int shapenum, unsigned height, uint32_t flags) { t_compshape *shape; unsigned scale,pixheight; unsigned starty,endy; word *cmdptr; byte *cline; byte *line; byte *vmem; int actx,i,upperedge; short newstart; int scrstarty,screndy,lpix,rpix,pixcnt,ycnt; unsigned j; byte col; #ifdef USE_SHADING byte *curshades; if(flags & FL_FULLBRIGHT) curshades = shadetable[0]; else curshades = shadetable[GetShade(height)]; #endif shape = (t_compshape *) PM_GetSprite(shapenum); scale=height>>3; // low three bits are fractional if(!scale) return; // too close or far away pixheight=scale*SPRITESCALEFACTOR; actx=xcenter-scale; upperedge=viewheight/2-scale; cmdptr=(word *) shape->dataofs; for(i=shape->leftpix,pixcnt=i*pixheight,rpix=(pixcnt>>6)+actx;i<=shape->rightpix;i++,cmdptr++) { lpix=rpix; if(lpix>=viewwidth) break; pixcnt+=pixheight; rpix=(pixcnt>>6)+actx; if(lpix!=rpix && rpix>0) { if(lpix<0) lpix=0; if(rpix>viewwidth) rpix=viewwidth,i=shape->rightpix+1; cline=(byte *)shape + *cmdptr; while(lpix>= 1; newstart = READWORD(&line); starty = READWORD(&line) >> 1; j=starty; ycnt=j*pixheight; screndy=(ycnt>>6)+upperedge; if(screndy<0) vmem=vbuf+lpix; else vmem=vbuf+screndy*vbufPitch+lpix; for(;j>6)+upperedge; if(scrstarty!=screndy && screndy>0) { #ifdef USE_SHADING col=curshades[((byte *)shape)[newstart+j]]; #else col=((byte *)shape)[newstart+j]; #endif if(scrstarty<0) scrstarty=0; if(screndy>viewheight) screndy=viewheight,j=endy; while(scrstarty>1; pixheight=scale*SPRITESCALEFACTOR; actx=xcenter-scale; upperedge=viewheight/2-scale; cmdptr=shape->dataofs; for(i=shape->leftpix,pixcnt=i*pixheight,rpix=(pixcnt>>6)+actx;i<=shape->rightpix;i++,cmdptr++) { lpix=rpix; if(lpix>=viewwidth) break; pixcnt+=pixheight; rpix=(pixcnt>>6)+actx; if(lpix!=rpix && rpix>0) { if(lpix<0) lpix=0; if(rpix>viewwidth) rpix=viewwidth,i=shape->rightpix+1; cline = (byte *)shape + *cmdptr; while(lpix>= 1; newstart = READWORD(&line); starty = READWORD(&line) >> 1; j=starty; ycnt=j*pixheight; screndy=(ycnt>>6)+upperedge; if(screndy<0) vmem=vbuf+lpix; else vmem=vbuf+screndy*vbufPitch+lpix; for(;j>6)+upperedge; if(scrstarty!=screndy && screndy>0) { col=((byte *)shape)[newstart+j]; if(scrstarty<0) scrstarty=0; if(screndy>viewheight) screndy=viewheight,j=endy; while(scrstartyshapenum = statptr->shapenum) == -1) continue; // object has been deleted if (!*statptr->visspot) continue; // not visable if (TransformTile (statptr->tilex,statptr->tiley, &visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS) { GetBonus (statptr); if(statptr->shapenum == -1) continue; // object has been taken } if (!visptr->viewheight) continue; // to close to the object #ifdef USE_DIR3DSPR if(statptr->flags & FL_DIR_MASK) visptr->transsprite=statptr; else visptr->transsprite=NULL; #endif if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow { visptr->flags = (short) statptr->flags; visptr++; } } // // place active objects // for (obj = player->next;obj;obj=obj->next) { if ((visptr->shapenum = obj->state->shapenum)==0) continue; // no shape spotloc = (obj->tilex<tiley; // optimize: keep in struct? visspot = &spotvis[0][0]+spotloc; tilespot = &tilemap[0][0]+spotloc; // // could be in any of the nine surrounding tiles // if (*visspot || ( *(visspot-1) && !*(tilespot-1) ) || ( *(visspot+1) && !*(tilespot+1) ) || ( *(visspot-65) && !*(tilespot-65) ) || ( *(visspot-64) && !*(tilespot-64) ) || ( *(visspot-63) && !*(tilespot-63) ) || ( *(visspot+65) && !*(tilespot+65) ) || ( *(visspot+64) && !*(tilespot+64) ) || ( *(visspot+63) && !*(tilespot+63) ) ) { obj->active = ac_yes; TransformActor (obj); if (!obj->viewheight) continue; // too close or far away visptr->viewx = obj->viewx; visptr->viewheight = obj->viewheight; if (visptr->shapenum == -1) visptr->shapenum = obj->temp1; // special shape if (obj->state->rotate) visptr->shapenum += CalcRotate (obj); if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow { visptr->flags = (short) obj->flags; #ifdef USE_DIR3DSPR visptr->transsprite = NULL; #endif visptr++; } obj->flags |= FL_VISABLE; } else obj->flags &= ~FL_VISABLE; } // // draw from back to front // numvisable = (int) (visptr-&vislist[0]); if (!numvisable) return; // no visable objects for (i = 0; iviewheight; if (height < least) { least = height; farthest = visstep; } } // // draw farthest // #ifdef USE_DIR3DSPR if(farthest->transsprite) Scale3DShape(vbuf, vbufPitch, farthest->transsprite); else #endif ScaleShape(farthest->viewx, farthest->shapenum, farthest->viewheight, farthest->flags); farthest->viewheight = 32000; } } //========================================================================== /* ============== = = DrawPlayerWeapon = = Draw the player's hands = ============== */ int weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY, SPR_PISTOLREADY, SPR_MACHINEGUNREADY, SPR_CHAINREADY}; void DrawPlayerWeapon (void) { int shapenum; #ifndef SPEAR if (gamestate.victoryflag) { #ifndef APOGEE_1_0 if (player->state == &s_deathcam && (GetTimeCount()&32) ) SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1); #endif return; } #endif if (gamestate.weapon != -1) { shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe; SimpleScaleShape(viewwidth/2,shapenum,viewheight+1); } if (demorecord || demoplayback) SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1); } //========================================================================== /* ===================== = = CalcTics = ===================== */ void CalcTics (void) { // // calculate tics since last refresh for adaptive timing // if (lasttimecount > (int32_t) GetTimeCount()) lasttimecount = GetTimeCount(); // if the game was paused a LONG time uint32_t curtime = SDL_GetTicks(); tics = (curtime * 7) / 100 - lasttimecount; if(!tics) { // wait until end of current tic SDL_Delay(((lasttimecount + 1) * 100) / 7 - curtime); tics = 1; } lasttimecount += tics; if (tics>MAXTICS) tics = MAXTICS; } //========================================================================== void AsmRefresh(void) { int32_t xstep,ystep; longword xpartial,ypartial; boolean playerInPushwallBackTile = tilemap[focaltx][focalty] == 64; for(pixx=0;pixx=3600) angl-=FINEANGLES; if(angl<900) { xtilestep=1; ytilestep=-1; xstep=finetangent[900-1-angl]; ystep=-finetangent[angl]; xpartial=xpartialup; ypartial=ypartialdown; } else if(angl<1800) { xtilestep=-1; ytilestep=-1; xstep=-finetangent[angl-900]; ystep=-finetangent[1800-1-angl]; xpartial=xpartialdown; ypartial=ypartialdown; } else if(angl<2700) { xtilestep=-1; ytilestep=1; xstep=-finetangent[2700-1-angl]; ystep=finetangent[angl-1800]; xpartial=xpartialdown; ypartial=ypartialup; } else if(angl<3600) { xtilestep=1; ytilestep=1; xstep=finetangent[angl-2700]; ystep=finetangent[3600-1-angl]; xpartial=xpartialup; ypartial=ypartialup; } yintercept=FixedMul(ystep,xpartial)+viewy; xtile=focaltx+xtilestep; xspot=(word)((xtile<>16)); xintercept=FixedMul(xstep,ypartial)+viewx; ytile=focalty+ytilestep; yspot=(word)((((uint32_t)xintercept>>16)<> 6); if((yintbuf >> 16) == focalty) // ray hits pushwall back? { if(pwalldir == di_east) xintercept = (focaltx << TILESHIFT) + (pwallpos << 10); else xintercept = (focaltx << TILESHIFT) - TILEGLOBAL + ((64 - pwallpos) << 10); yintercept = yintbuf; ytile = (short) (yintercept >> TILESHIFT); tilehit = pwalltile; HitVertWall(); continue; } } else if(pwalldir == di_south && ytilestep == 1 || pwalldir == di_north && ytilestep == -1) { int32_t xintbuf = xintercept - ((xstep * (64 - pwallpos)) >> 6); if((xintbuf >> 16) == focaltx) // ray hits pushwall back? { xintercept = xintbuf; if(pwalldir == di_south) yintercept = (focalty << TILESHIFT) + (pwallpos << 10); else yintercept = (focalty << TILESHIFT) - TILEGLOBAL + ((64 - pwallpos) << 10); xtile = (short) (xintercept >> TILESHIFT); tilehit = pwalltile; HitHorizWall(); continue; } } } do { if(ytilestep==-1 && (yintercept>>16)<=ytile) goto horizentry; if(ytilestep==1 && (yintercept>>16)>=ytile) goto horizentry; vertentry: if((uint32_t)yintercept>mapheight*65536-1 || (word)xtile>=mapwidth) { if(xtile<0) xintercept=0, xtile=0; else if(xtile>=mapwidth) xintercept=mapwidth<> TILESHIFT); if(yintercept<0) yintercept=0, ytile=0; else if(yintercept>=(mapheight<=maparea) break; tilehit=((byte *)tilemap)[xspot]; if(tilehit) { if(tilehit&0x80) { int32_t yintbuf=yintercept+(ystep>>1); if((yintbuf>>16)!=(yintercept>>16)) goto passvert; if((word)yintbuf> TILESHIFT); HitVertDoor(); } else { if(tilehit==64) { if(pwalldir==di_west || pwalldir==di_east) { int32_t yintbuf; int pwallposnorm; int pwallposinv; if(pwalldir==di_west) { pwallposnorm = 64-pwallpos; pwallposinv = pwallpos; } else { pwallposnorm = pwallpos; pwallposinv = 64-pwallpos; } if(pwalldir == di_east && xtile==pwallx && ((uint32_t)yintercept>>16)==pwally || pwalldir == di_west && !(xtile==pwallx && ((uint32_t)yintercept>>16)==pwally)) { yintbuf=yintercept+((ystep*pwallposnorm)>>6); if((yintbuf>>16)!=(yintercept>>16)) goto passvert; xintercept=(xtile<> TILESHIFT); tilehit=pwalltile; HitVertWall(); } else { yintbuf=yintercept+((ystep*pwallposinv)>>6); if((yintbuf>>16)!=(yintercept>>16)) goto passvert; xintercept=(xtile<> TILESHIFT); tilehit=pwalltile; HitVertWall(); } } else { int pwallposi = pwallpos; if(pwalldir==di_north) pwallposi = 64-pwallpos; if(pwalldir==di_south && (word)yintercept<(pwallposi<<10) || pwalldir==di_north && (word)yintercept>(pwallposi<<10)) { if(((uint32_t)yintercept>>16)==pwally && xtile==pwallx) { if(pwalldir==di_south && (int32_t)((word)yintercept)+ystep<(pwallposi<<10) || pwalldir==di_north && (int32_t)((word)yintercept)+ystep>(pwallposi<<10)) goto passvert; if(pwalldir==di_south) yintercept=(yintercept&0xffff0000)+(pwallposi<<10); else yintercept=(yintercept&0xffff0000)-TILEGLOBAL+(pwallposi<<10); xintercept=xintercept-((xstep*(64-pwallpos))>>6); xtile = (short) (xintercept >> TILESHIFT); tilehit=pwalltile; HitHorizWall(); } else { texdelta = -(pwallposi<<10); xintercept=xtile<> TILESHIFT); tilehit=pwalltile; HitVertWall(); } } else { if(((uint32_t)yintercept>>16)==pwally && xtile==pwallx) { texdelta = -(pwallposi<<10); xintercept=xtile<> TILESHIFT); tilehit=pwalltile; HitVertWall(); } else { if(pwalldir==di_south && (int32_t)((word)yintercept)+ystep>(pwallposi<<10) || pwalldir==di_north && (int32_t)((word)yintercept)+ystep<(pwallposi<<10)) goto passvert; if(pwalldir==di_south) yintercept=(yintercept&0xffff0000)-((64-pwallpos)<<10); else yintercept=(yintercept&0xffff0000)+((64-pwallpos)<<10); xintercept=xintercept-((xstep*pwallpos)>>6); xtile = (short) (xintercept >> TILESHIFT); tilehit=pwalltile; HitHorizWall(); } } } } else { xintercept=xtile<> TILESHIFT); HitVertWall(); } } break; } passvert: *((byte *)spotvis+xspot)=1; xtile+=xtilestep; yintercept+=ystep; xspot=(word)((xtile<>16)); } while(1); continue; do { if(xtilestep==-1 && (xintercept>>16)<=xtile) goto vertentry; if(xtilestep==1 && (xintercept>>16)>=xtile) goto vertentry; horizentry: if((uint32_t)xintercept>mapwidth*65536-1 || (word)ytile>=mapheight) { if(ytile<0) yintercept=0, ytile=0; else if(ytile>=mapheight) yintercept=mapheight<> TILESHIFT); if(xintercept<0) xintercept=0, xtile=0; else if(xintercept>=(mapwidth<=maparea) break; tilehit=((byte *)tilemap)[yspot]; if(tilehit) { if(tilehit&0x80) { int32_t xintbuf=xintercept+(xstep>>1); if((xintbuf>>16)!=(xintercept>>16)) goto passhoriz; if((word)xintbuf> TILESHIFT); HitHorizDoor(); } else { if(tilehit==64) { if(pwalldir==di_north || pwalldir==di_south) { int32_t xintbuf; int pwallposnorm; int pwallposinv; if(pwalldir==di_north) { pwallposnorm = 64-pwallpos; pwallposinv = pwallpos; } else { pwallposnorm = pwallpos; pwallposinv = 64-pwallpos; } if(pwalldir == di_south && ytile==pwally && ((uint32_t)xintercept>>16)==pwallx || pwalldir == di_north && !(ytile==pwally && ((uint32_t)xintercept>>16)==pwallx)) { xintbuf=xintercept+((xstep*pwallposnorm)>>6); if((xintbuf>>16)!=(xintercept>>16)) goto passhoriz; yintercept=(ytile<> TILESHIFT); tilehit=pwalltile; HitHorizWall(); } else { xintbuf=xintercept+((xstep*pwallposinv)>>6); if((xintbuf>>16)!=(xintercept>>16)) goto passhoriz; yintercept=(ytile<> TILESHIFT); tilehit=pwalltile; HitHorizWall(); } } else { int pwallposi = pwallpos; if(pwalldir==di_west) pwallposi = 64-pwallpos; if(pwalldir==di_east && (word)xintercept<(pwallposi<<10) || pwalldir==di_west && (word)xintercept>(pwallposi<<10)) { if(((uint32_t)xintercept>>16)==pwallx && ytile==pwally) { if(pwalldir==di_east && (int32_t)((word)xintercept)+xstep<(pwallposi<<10) || pwalldir==di_west && (int32_t)((word)xintercept)+xstep>(pwallposi<<10)) goto passhoriz; if(pwalldir==di_east) xintercept=(xintercept&0xffff0000)+(pwallposi<<10); else xintercept=(xintercept&0xffff0000)-TILEGLOBAL+(pwallposi<<10); yintercept=yintercept-((ystep*(64-pwallpos))>>6); ytile = (short) (yintercept >> TILESHIFT); tilehit=pwalltile; HitVertWall(); } else { texdelta = -(pwallposi<<10); yintercept=ytile<> TILESHIFT); tilehit=pwalltile; HitHorizWall(); } } else { if(((uint32_t)xintercept>>16)==pwallx && ytile==pwally) { texdelta = -(pwallposi<<10); yintercept=ytile<> TILESHIFT); tilehit=pwalltile; HitHorizWall(); } else { if(pwalldir==di_east && (int32_t)((word)xintercept)+xstep>(pwallposi<<10) || pwalldir==di_west && (int32_t)((word)xintercept)+xstep<(pwallposi<<10)) goto passhoriz; if(pwalldir==di_east) xintercept=(xintercept&0xffff0000)-((64-pwallpos)<<10); else xintercept=(xintercept&0xffff0000)+((64-pwallpos)<<10); yintercept=yintercept-((ystep*pwallpos)>>6); ytile = (short) (yintercept >> TILESHIFT); tilehit=pwalltile; HitVertWall(); } } } } else { yintercept=ytile<> TILESHIFT); HitHorizWall(); } } break; } passhoriz: *((byte *)spotvis+yspot)=1; ytile+=ytilestep; xintercept+=xstep; yspot=(word)((((uint32_t)xintercept>>16)<angle; midangle = viewangle*(FINEANGLES/ANGLES); viewsin = sintable[viewangle]; viewcos = costable[viewangle]; viewx = player->x - FixedMul(focallength,viewcos); viewy = player->y + FixedMul(focallength,viewsin); focaltx = (short)(viewx>>TILESHIFT); focalty = (short)(viewy>>TILESHIFT); viewtx = (short)(player->x >> TILESHIFT); viewty = (short)(player->y >> TILESHIFT); } //========================================================================== /* ======================== = = ThreeDRefresh = ======================== */ void ThreeDRefresh (void) { // // clear out the traced array // memset(spotvis,0,maparea); spotvis[player->tilex][player->tiley] = 1; // Detect all sprites over player fix vbuf = VL_LockSurface(screenBuffer); vbuf+=screenofs; vbufPitch = bufferPitch; CalcViewVariables(); // // follow the walls from there to the right, drawing as we go // VGAClearScreen (); #if defined(USE_FEATUREFLAGS) && defined(USE_STARSKY) if(GetFeatureFlags() & FF_STARSKY) DrawStarSky(vbuf, vbufPitch); #endif WallRefresh (); #if defined(USE_FEATUREFLAGS) && defined(USE_PARALLAX) if(GetFeatureFlags() & FF_PARALLAXSKY) DrawParallax(vbuf, vbufPitch); #endif #if defined(USE_FEATUREFLAGS) && defined(USE_CLOUDSKY) if(GetFeatureFlags() & FF_CLOUDSKY) DrawClouds(vbuf, vbufPitch, min_wallheight); #endif #ifdef USE_FLOORCEILINGTEX DrawFloorAndCeiling(vbuf, vbufPitch, min_wallheight); #endif // // draw all the scaled images // DrawScaleds(); // draw scaled stuff #if defined(USE_FEATUREFLAGS) && defined(USE_RAIN) if(GetFeatureFlags() & FF_RAIN) DrawRain(vbuf, vbufPitch); #endif #if defined(USE_FEATUREFLAGS) && defined(USE_SNOW) if(GetFeatureFlags() & FF_SNOW) DrawSnow(vbuf, vbufPitch); #endif DrawPlayerWeapon (); // draw player's hands if(Keyboard[sc_Tab] && viewsize == 21 && gamestate.weapon != -1) ShowActStatus(); VL_UnlockSurface(screenBuffer); vbuf = NULL; // // show screen and time last cycle // if (fizzlein) { FizzleFade(screenBuffer, 0, 0, screenWidth, screenHeight, 20, false); fizzlein = false; lasttimecount = GetTimeCount(); // don't make a big tic count } else { #ifndef REMDEBUG if (fpscounter) { fontnumber = 0; SETFONTCOLOR(7,127); PrintX=4; PrintY=1; VWB_Bar(0,0,50,10,bordercol); US_PrintSigned(fps); US_Print(" fps"); } #endif SDL_BlitSurface(screenBuffer, NULL, screen, NULL); SDL_Flip(screen); } #ifndef REMDEBUG if (fpscounter) { fps_frames++; fps_time+=tics; if(fps_time>35) { fps_time-=35; fps=fps_frames<<1; fps_frames=0; } } #endif }