2021-01-30 13:31:40 +01:00
|
|
|
// WL_DRAW.C
|
|
|
|
|
|
|
|
#include "wl_def.h"
|
2021-07-29 22:23:49 +02:00
|
|
|
#include <cstdio>
|
2021-01-30 13:31:40 +01:00
|
|
|
#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 (nx<MINDIST) // too close, don't overflow the divide
|
|
|
|
{
|
|
|
|
ob->viewheight = 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<<TILESHIFT)+0x8000-viewx;
|
|
|
|
gy = ((int32_t)ty<<TILESHIFT)+0x8000-viewy;
|
|
|
|
|
|
|
|
//
|
|
|
|
// calculate newx
|
|
|
|
//
|
|
|
|
gxt = FixedMul(gx,viewcos);
|
|
|
|
gyt = FixedMul(gy,viewsin);
|
|
|
|
nx = gxt-gyt-0x2000; // 0x2000 is size of object
|
|
|
|
|
|
|
|
//
|
|
|
|
// calculate newy
|
|
|
|
//
|
|
|
|
gxt = FixedMul(gx,viewsin);
|
|
|
|
gyt = FixedMul(gy,viewcos);
|
|
|
|
ny = gyt+gxt;
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// calculate height / perspective ratio
|
|
|
|
//
|
|
|
|
if (nx<MINDIST) // too close, don't overflow the divide
|
|
|
|
*dispheight = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*dispx = (short)(centerx + ny*scale/nx);
|
|
|
|
*dispheight = (short)(heightnumerator/(nx>>8));
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// see if it should be grabbed
|
|
|
|
//
|
|
|
|
if (nx<TILEGLOBAL && ny>-TILEGLOBAL/2 && ny<TILEGLOBAL/2)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
=
|
|
|
|
= CalcHeight
|
|
|
|
=
|
|
|
|
= Calculates the height of xintercept,yintercept from viewx,viewy
|
|
|
|
=
|
|
|
|
====================
|
|
|
|
*/
|
|
|
|
|
|
|
|
int CalcHeight()
|
|
|
|
{
|
|
|
|
fixed z = FixedMul(xintercept - viewx, viewcos)
|
|
|
|
- FixedMul(yintercept - viewy, viewsin);
|
|
|
|
if(z < MINDIST) z = MINDIST;
|
|
|
|
int height = heightnumerator / (z >> 8);
|
|
|
|
if(height < min_wallheight) min_wallheight = height;
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
=
|
|
|
|
= ScalePost
|
|
|
|
=
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
|
|
|
|
byte *postsource;
|
|
|
|
int postx;
|
|
|
|
int postwidth;
|
|
|
|
|
|
|
|
void ScalePost()
|
|
|
|
{
|
|
|
|
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<rpix)
|
|
|
|
{
|
|
|
|
if(wallheight[lpix]<=(int)height)
|
|
|
|
{
|
|
|
|
line=cline;
|
|
|
|
while((endy = READWORD(line)) != 0)
|
|
|
|
{
|
|
|
|
endy >>= 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<endy;j++)
|
|
|
|
{
|
|
|
|
scrstarty=screndy;
|
|
|
|
ycnt+=pixheight;
|
|
|
|
screndy=(ycnt>>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<screndy)
|
|
|
|
{
|
|
|
|
*vmem=col;
|
|
|
|
vmem+=vbufPitch;
|
|
|
|
scrstarty++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lpix++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimpleScaleShape (int xcenter, int shapenum, unsigned height)
|
|
|
|
{
|
|
|
|
t_compshape *shape;
|
|
|
|
unsigned scale,pixheight;
|
|
|
|
unsigned starty,endy;
|
|
|
|
word *cmdptr;
|
|
|
|
byte *cline;
|
|
|
|
byte *line;
|
|
|
|
int actx,i,upperedge;
|
|
|
|
short newstart;
|
|
|
|
int scrstarty,screndy,lpix,rpix,pixcnt,ycnt;
|
|
|
|
unsigned j;
|
|
|
|
byte col;
|
|
|
|
byte *vmem;
|
|
|
|
|
|
|
|
shape = (t_compshape *) PM_GetSprite(shapenum);
|
|
|
|
|
|
|
|
scale=height>>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<rpix)
|
|
|
|
{
|
|
|
|
line=cline;
|
|
|
|
while((endy = READWORD(line)) != 0)
|
|
|
|
{
|
|
|
|
endy >>= 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<endy;j++)
|
|
|
|
{
|
|
|
|
scrstarty=screndy;
|
|
|
|
ycnt+=pixheight;
|
|
|
|
screndy=(ycnt>>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(scrstarty<screndy)
|
|
|
|
{
|
|
|
|
*vmem=col;
|
|
|
|
vmem+=vbufPitch;
|
|
|
|
scrstarty++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lpix++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=====================
|
|
|
|
=
|
|
|
|
= DrawScaleds
|
|
|
|
=
|
|
|
|
= Draws all objects that are visable
|
|
|
|
=
|
|
|
|
=====================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MAXVISABLE 250
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
short viewx,
|
|
|
|
viewheight,
|
|
|
|
shapenum;
|
|
|
|
short flags; // this must be changed to uint32_t, when you
|
|
|
|
// you need more than 16-flags for drawing
|
|
|
|
#ifdef USE_DIR3DSPR
|
|
|
|
statobj_t *transsprite;
|
|
|
|
#endif
|
|
|
|
} visobj_t;
|
|
|
|
|
|
|
|
visobj_t vislist[MAXVISABLE];
|
|
|
|
visobj_t *visptr,*visstep,*farthest;
|
|
|
|
|
|
|
|
void DrawScaleds (void)
|
|
|
|
{
|
|
|
|
int i,least,numvisable,height;
|
|
|
|
byte *tilespot,*visspot;
|
|
|
|
unsigned spotloc;
|
|
|
|
|
|
|
|
statobj_t *statptr;
|
|
|
|
objtype *obj;
|
|
|
|
|
|
|
|
visptr = &vislist[0];
|
|
|
|
|
|
|
|
//
|
|
|
|
// place static objects
|
|
|
|
//
|
|
|
|
for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++)
|
|
|
|
{
|
|
|
|
if ((visptr->shapenum = 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<<mapshift)+obj->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; i<numvisable; i++)
|
|
|
|
{
|
|
|
|
least = 32000;
|
|
|
|
for (visstep=&vislist[0] ; visstep<visptr ; visstep++)
|
|
|
|
{
|
|
|
|
height = visstep->viewheight;
|
|
|
|
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
|
|
|
|
|
2021-07-29 22:23:49 +02:00
|
|
|
uint32_t curtime = uSDL_GetTicks();
|
2021-01-30 13:31:40 +01:00
|
|
|
tics = (curtime * 7) / 100 - lasttimecount;
|
|
|
|
if(!tics)
|
|
|
|
{
|
|
|
|
// wait until end of current tic
|
2021-07-29 22:23:49 +02:00
|
|
|
uSDL_Delay(((lasttimecount + 1) * 100) / 7 - curtime);
|
2021-01-30 13:31:40 +01:00
|
|
|
tics = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lasttimecount += tics;
|
|
|
|
|
|
|
|
if (tics>MAXTICS)
|
|
|
|
tics = MAXTICS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void AsmRefresh()
|
|
|
|
{
|
|
|
|
int32_t xstep,ystep;
|
|
|
|
longword xpartial,ypartial;
|
|
|
|
boolean playerInPushwallBackTile = tilemap[focaltx][focalty] == 64;
|
|
|
|
|
|
|
|
for(pixx=0;pixx<viewwidth;pixx++)
|
|
|
|
{
|
|
|
|
short angl=midangle+pixelangle[pixx];
|
|
|
|
if(angl<0) angl+=FINEANGLES;
|
|
|
|
if(angl>=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<<mapshift)+((uint32_t)yintercept>>16));
|
|
|
|
xintercept=FixedMul(xstep,ypartial)+viewx;
|
|
|
|
ytile=focalty+ytilestep;
|
|
|
|
yspot=(word)((((uint32_t)xintercept>>16)<<mapshift)+ytile);
|
|
|
|
texdelta=0;
|
|
|
|
|
|
|
|
// Special treatment when player is in back tile of pushwall
|
|
|
|
if(playerInPushwallBackTile)
|
|
|
|
{
|
|
|
|
if( pwalldir == di_east && xtilestep == 1
|
|
|
|
|| pwalldir == di_west && xtilestep == -1)
|
|
|
|
{
|
|
|
|
int32_t yintbuf = yintercept - ((ystep * (64 - pwallpos)) >> 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, xtile=mapwidth-1;
|
|
|
|
else xtile=(short) (xintercept >> TILESHIFT);
|
|
|
|
if(yintercept<0) yintercept=0, ytile=0;
|
|
|
|
else if(yintercept>=(mapheight<<TILESHIFT)) yintercept=mapheight<<TILESHIFT, ytile=mapheight-1;
|
|
|
|
yspot=0xffff;
|
|
|
|
tilehit=0;
|
|
|
|
HitHorizBorder();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(xspot>=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<doorposition[tilehit&0x7f])
|
|
|
|
goto passvert;
|
|
|
|
yintercept=yintbuf;
|
|
|
|
xintercept=(xtile<<TILESHIFT)|0x8000;
|
|
|
|
ytile = (short) (yintercept >> 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)+TILEGLOBAL-(pwallposinv<<10);
|
|
|
|
yintercept=yintbuf;
|
|
|
|
ytile = (short) (yintercept >> TILESHIFT);
|
|
|
|
tilehit=pwalltile;
|
|
|
|
HitVertWall();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
yintbuf=yintercept+((ystep*pwallposinv)>>6);
|
|
|
|
if((yintbuf>>16)!=(yintercept>>16))
|
|
|
|
goto passvert;
|
|
|
|
|
|
|
|
xintercept=(xtile<<TILESHIFT)-(pwallposinv<<10);
|
|
|
|
yintercept=yintbuf;
|
|
|
|
ytile = (short) (yintercept >> 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;
|
|
|
|
ytile = (short) (yintercept >> TILESHIFT);
|
|
|
|
tilehit=pwalltile;
|
|
|
|
HitVertWall();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(((uint32_t)yintercept>>16)==pwally && xtile==pwallx)
|
|
|
|
{
|
|
|
|
texdelta = -(pwallposi<<10);
|
|
|
|
xintercept=xtile<<TILESHIFT;
|
|
|
|
ytile = (short) (yintercept >> 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;
|
|
|
|
ytile = (short) (yintercept >> TILESHIFT);
|
|
|
|
HitVertWall();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
passvert:
|
|
|
|
*((byte *)spotvis+xspot)=1;
|
|
|
|
xtile+=xtilestep;
|
|
|
|
yintercept+=ystep;
|
|
|
|
xspot=(word)((xtile<<mapshift)+((uint32_t)yintercept>>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, ytile=mapheight-1;
|
|
|
|
else ytile=(short) (yintercept >> TILESHIFT);
|
|
|
|
if(xintercept<0) xintercept=0, xtile=0;
|
|
|
|
else if(xintercept>=(mapwidth<<TILESHIFT)) xintercept=mapwidth<<TILESHIFT, xtile=mapwidth-1;
|
|
|
|
xspot=0xffff;
|
|
|
|
tilehit=0;
|
|
|
|
HitVertBorder();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(yspot>=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<doorposition[tilehit&0x7f])
|
|
|
|
goto passhoriz;
|
|
|
|
xintercept=xintbuf;
|
|
|
|
yintercept=(ytile<<TILESHIFT)+0x8000;
|
|
|
|
xtile = (short) (xintercept >> 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)+TILEGLOBAL-(pwallposinv<<10);
|
|
|
|
xintercept=xintbuf;
|
|
|
|
xtile = (short) (xintercept >> TILESHIFT);
|
|
|
|
tilehit=pwalltile;
|
|
|
|
HitHorizWall();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xintbuf=xintercept+((xstep*pwallposinv)>>6);
|
|
|
|
if((xintbuf>>16)!=(xintercept>>16))
|
|
|
|
goto passhoriz;
|
|
|
|
|
|
|
|
yintercept=(ytile<<TILESHIFT)-(pwallposinv<<10);
|
|
|
|
xintercept=xintbuf;
|
|
|
|
xtile = (short) (xintercept >> 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;
|
|
|
|
xtile = (short) (xintercept >> TILESHIFT);
|
|
|
|
tilehit=pwalltile;
|
|
|
|
HitHorizWall();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(((uint32_t)xintercept>>16)==pwallx && ytile==pwally)
|
|
|
|
{
|
|
|
|
texdelta = -(pwallposi<<10);
|
|
|
|
yintercept=ytile<<TILESHIFT;
|
|
|
|
xtile = (short) (xintercept >> 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;
|
|
|
|
xtile = (short) (xintercept >> TILESHIFT);
|
|
|
|
HitHorizWall();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
passhoriz:
|
|
|
|
*((byte *)spotvis+yspot)=1;
|
|
|
|
ytile+=ytilestep;
|
|
|
|
xintercept+=xstep;
|
|
|
|
yspot=(word)((((uint32_t)xintercept>>16)<<mapshift)+ytile);
|
|
|
|
}
|
|
|
|
while(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
=
|
|
|
|
= WallRefresh
|
|
|
|
=
|
|
|
|
====================
|
|
|
|
*/
|
|
|
|
|
|
|
|
void WallRefresh (void)
|
|
|
|
{
|
|
|
|
xpartialdown = viewx&(TILEGLOBAL-1);
|
|
|
|
xpartialup = TILEGLOBAL-xpartialdown;
|
|
|
|
ypartialdown = viewy&(TILEGLOBAL-1);
|
|
|
|
ypartialup = TILEGLOBAL-ypartialdown;
|
|
|
|
|
|
|
|
min_wallheight = viewheight;
|
|
|
|
lastside = -1; // the first pixel is on a new wall
|
|
|
|
AsmRefresh ();
|
|
|
|
ScalePost (); // no more optimization on last post
|
|
|
|
}
|
|
|
|
|
|
|
|
void CalcViewVariables()
|
|
|
|
{
|
|
|
|
viewangle = player->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);
|
|
|
|
if(vbuf == NULL) return;
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|