rockbox/apps/plugins/sdl/progs/wolf3d/wl_dir3dspr.c
Franklin Wei 3f59fc8b77 Wolfenstein 3-D!
This is a port of Wolf4SDL, which is derived from the original id
software source release. The port runs on top of the SDL plugin
runtime and is loaded as an overlay.

Licensing of the game code is not an issue, as discussed below
(essentially, the Debian project treats Wolf4SDL as GPLv2, with an
email from John Carmack backing it up):

  http://forums.rockbox.org/index.php?topic=52872

Included is a copy of MAME's Yamaha OPL sound chip emulator
(fmopl_gpl.c).  This file was not part of the original Wolf4SDL source
(which includes a non-GPL'd version), but was rather rebased from from
a later MAME source which had been relicensed to GPLv2.

Change-Id: I64c2ba035e0be7e2f49252f40640641416613439
2019-07-09 11:20:55 -04:00

230 lines
6.5 KiB
C

#include "version.h"
#ifdef USE_DIR3DSPR
#include "wl_def.h"
#include "wl_shade.h"
// Define directional 3d sprites in wl_act1.cpp (there are two examples)
// Make sure you have according entries in ScanInfoPlane in wl_game.cpp.
void Scale3DShaper(int x1, int x2, int shapenum, uint32_t flags, fixed ny1, fixed ny2,
fixed nx1, fixed nx2, byte *vbuf, unsigned vbufPitch)
{
t_compshape *shape;
unsigned scale1,starty,endy;
word *cmdptr;
byte *line;
byte *vmem;
int dx,len,i,newstart,ycnt,pixheight,screndy,upperedge,scrstarty;
unsigned j;
fixed height,dheight,height1,height2;
int xpos[TEXTURESIZE+1];
int slinex;
fixed dxx=(ny2-ny1)<<8,dzz=(nx2-nx1)<<8;
fixed dxa=0,dza=0;
byte col;
shape = (t_compshape *) PM_GetSprite(shapenum);
len=shape->rightpix-shape->leftpix+1;
if(!len) return;
ny1+=dxx>>9;
nx1+=dzz>>9;
dxa=-(dxx>>1),dza=-(dzz>>1);
dxx>>=TEXTURESHIFT,dzz>>=TEXTURESHIFT;
dxa+=shape->leftpix*dxx,dza+=shape->leftpix*dzz;
xpos[0]=(int)((ny1+(dxa>>8))*scale/(nx1+(dza>>8))+centerx);
height1 = heightnumerator/((nx1+(dza>>8))>>8);
height=(((fixed)height1)<<12)+2048;
for(i=1;i<=len;i++)
{
dxa+=dxx,dza+=dzz;
xpos[i]=(int)((ny1+(dxa>>8))*scale/(nx1+(dza>>8))+centerx);
if(xpos[i-1]>viewwidth) break;
}
len=i-1;
dx = xpos[len] - xpos[0];
if(!dx) return;
height2 = heightnumerator/((nx1+(dza>>8))>>8);
dheight=(((fixed)height2-(fixed)height1)<<12)/(fixed)dx;
cmdptr = (word *) shape->dataofs;
i=0;
if(x2>viewwidth) x2=viewwidth;
for(i=0;i<len;i++)
{
for(slinex=xpos[i];slinex<xpos[i+1] && slinex<x2;slinex++)
{
height+=dheight;
if(slinex<0) continue;
scale1=(unsigned)(height>>15);
if(wallheight[slinex]<(height>>12) && scale1 /*&& scale1<=maxscale*/)
{
#ifdef USE_SHADING
byte *curshades;
if(flags & FL_FULLBRIGHT)
curshades = shadetable[0];
else
curshades = shadetable[GetShade(scale1<<3)];
#endif
pixheight=scale1*SPRITESCALEFACTOR;
upperedge=viewheight/2-scale1;
line=(byte *)shape + cmdptr[i];
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+slinex;
else vmem=vbuf+screndy*vbufPitch+slinex;
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++;
}
}
}
}
}
}
}
}
void Scale3DShape(byte *vbuf, unsigned vbufPitch, statobj_t *ob)
{
fixed nx1,nx2,ny1,ny2;
int viewx1,viewx2;
fixed diradd;
fixed playx = viewx;
fixed playy = viewy;
//
// the following values for "diradd" aren't optimized yet
// if you have problems with sprites being visible through wall edges
// where they shouldn't, you can try to adjust these values and SIZEADD
//
#define SIZEADD 1024
switch(ob->flags & FL_DIR_POS_MASK)
{
case FL_DIR_POS_FW: diradd=0x7ff0+0x8000; break;
case FL_DIR_POS_BW: diradd=-0x7ff0+0x8000; break;
case FL_DIR_POS_MID: diradd=0x8000; break;
default:
Quit("Unknown directional 3d sprite position (shapenum = %i)", ob->shapenum);
}
if(ob->flags & FL_DIR_VERT_FLAG) // vertical dir 3d sprite
{
fixed gy1,gy2,gx,gyt1,gyt2,gxt;
//
// translate point to view centered coordinates
//
gy1 = (((long)ob->tiley) << TILESHIFT)+0x8000-playy-0x8000L-SIZEADD;
gy2 = gy1+0x10000L+2*SIZEADD;
gx = (((long)ob->tilex) << TILESHIFT)+diradd-playx;
//
// calculate newx
//
gxt = FixedMul(gx,viewcos);
gyt1 = FixedMul(gy1,viewsin);
gyt2 = FixedMul(gy2,viewsin);
nx1 = gxt-gyt1;
nx2 = gxt-gyt2;
//
// calculate newy
//
gxt = FixedMul(gx,viewsin);
gyt1 = FixedMul(gy1,viewcos);
gyt2 = FixedMul(gy2,viewcos);
ny1 = gyt1+gxt;
ny2 = gyt2+gxt;
}
else // horizontal dir 3d sprite
{
fixed gx1,gx2,gy,gxt1,gxt2,gyt;
//
// translate point to view centered coordinates
//
gx1 = (((long)ob->tilex) << TILESHIFT)+0x8000-playx-0x8000L-SIZEADD;
gx2 = gx1+0x10000L+2*SIZEADD;
gy = (((long)ob->tiley) << TILESHIFT)+diradd-playy;
//
// calculate newx
//
gxt1 = FixedMul(gx1,viewcos);
gxt2 = FixedMul(gx2,viewcos);
gyt = FixedMul(gy,viewsin);
nx1 = gxt1-gyt;
nx2 = gxt2-gyt;
//
// calculate newy
//
gxt1 = FixedMul(gx1,viewsin);
gxt2 = FixedMul(gx2,viewsin);
gyt = FixedMul(gy,viewcos);
ny1 = gyt+gxt1;
ny2 = gyt+gxt2;
}
if(nx1 < 0 || nx2 < 0) return; // TODO: Clip on viewplane
//
// calculate perspective ratio
//
if(nx1>=0 && nx1<=1792) nx1=1792;
if(nx1<0 && nx1>=-1792) nx1=-1792;
if(nx2>=0 && nx2<=1792) nx2=1792;
if(nx2<0 && nx2>=-1792) nx2=-1792;
viewx1=(int)(centerx+ny1*scale/nx1);
viewx2=(int)(centerx+ny2*scale/nx2);
if(viewx2 < viewx1)
{
Scale3DShaper(viewx2,viewx1,ob->shapenum,ob->flags,ny2,ny1,nx2,nx1,vbuf,vbufPitch);
}
else
{
Scale3DShaper(viewx1,viewx2,ob->shapenum,ob->flags,ny1,ny2,nx1,nx2,vbuf,vbufPitch);
}
}
#endif