/*
Copyright (C) 1994-1995 Apogee Software, Ltd.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
#include "rt_def.h"
#include "watcom.h"
#include <stdio.h>
#include <string.h>

#ifdef DOS
#include <malloc.h>
#include <dos.h>
#include <conio.h>
#endif

#include "modexlib.h"
#include "rt_util.h"
#include "rt_draw.h"
#include "rt_scale.h"
#include "_rt_scal.h"
#include "rt_sc_a.h"
#include "engine.h"
#include "w_wad.h"
#include "z_zone.h"
#include "lumpy.h"
#include "rt_main.h"
#include "rt_ted.h"
#include "rt_vid.h"
#include "rt_view.h"
#include "rt_playr.h"
//MED
#include "memcheck.h"

/*
=============================================================================

                               GLOBALS

=============================================================================
*/

// Draw Column vars

int dc_texturemid;
int dc_iscale;
int dc_invscale;
int sprtopoffset;
int dc_yl;
int dc_yh;
//byte * dc_firstsource;
byte * dc_source;
int centeryclipped;
int transparentlevel=0;

/*
==========================
=
= SetPlayerLightLevel
=
==========================
*/

void SetPlayerLightLevel (void)
{
   int i;
   int lv;
   int intercept;
   int height;

   whereami=23;
	if (MISCVARS->GASON==1)
      {
		shadingtable=greenmap+(MISCVARS->gasindex<<8);
      return;
      }

   if (fulllight || fog)
      {
      shadingtable=colormap+(1<<12);
      return;
      }

   height=PLAYERHEIGHT;

	if (player->angle < FINEANGLES/8 || player->angle > 7*FINEANGLES/8)
      intercept=(player->x>>11)&0x1c;
	else if (player->angle < 3*FINEANGLES/8)
      intercept=(player->y>>11)&0x1c;
	else if (player->angle < 5*FINEANGLES/8)
      intercept=(player->x>>11)&0x1c;
	else
      intercept=(player->y>>11)&0x1c;

   if (lightsource)
      {
      lv=(((LightSourceAt(player->x>>16,player->y>>16)>>intercept)&0xf)>>1);
      i=maxshade-(height>>normalshade)-lv;
      if (i<minshade) i=minshade;
      shadingtable=colormap+(i<<8);
      }
   else
      {
      i=maxshade-(height>>normalshade);
      if (i<minshade) i=minshade;
      shadingtable=colormap+(i<<8);
      }
}



/*
==========================
=
= SetLightLevel
=
==========================
*/

void SetLightLevel (int height)
{
   int i;

   whereami=24;
	if (MISCVARS->GASON==1)
		{
		shadingtable=greenmap+(MISCVARS->gasindex<<8);
      return;
      }

   if (fulllight)
      {
      shadingtable=colormap+(1<<12);
      return;
      }
   if (fog)
      {
      i=((height*200/iGLOBAL_SCREENHEIGHT)>>normalshade)+minshade;
      if (i>maxshade) i=maxshade;
      shadingtable=colormap+(i<<8);
      }
   else
      {
      i=maxshade-(height>>normalshade);
      if (i<minshade) i=minshade;
      shadingtable=colormap+(i<<8);
      }
}

/*
==========================
=
= ScaleTransparentPost
=
==========================
*/
void ScaleTransparentPost (byte * src, byte * buf, int level)
{
   int  offset;
   int  length;
   int  topscreen;
   int  bottomscreen;
   byte * oldlevel;
   byte * seelevel;
#if (DEVELOPMENT == 1)
   boolean found=false;
   int  i;
#endif

   whereami=25;
#if (DEVELOPMENT == 1)
   if ((shadingtable>=colormap) && (shadingtable<=(colormap+(31*256))))
      {
      found=true;
      }
   else if ((shadingtable>=redmap) && (shadingtable<=(redmap+(31*256))))
      {
      found=true;
      }
   else
      {
      for (i=0;i<MAXPLAYERCOLORS;i++)
         {
         if ((shadingtable>=playermaps[i]) || (shadingtable<=(playermaps[i]+(31*256))))
            found=true;
         }
      }
   if (found==false)
      {
      Error ("Shadingtable out of range\n");
      }
   if ((level<0) || (level>=64))
      {
      Error ("translucent level out of range\n");
      }
#endif

   seelevel=colormap+(((level+64)>>2)<<8);
   oldlevel=shadingtable;
   offset=*(src++);
   for (;offset!=255;)
      {
      length=*(src++);
      topscreen = sprtopoffset + (dc_invscale*offset);
      bottomscreen = topscreen + (dc_invscale*length);
      dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
      dc_yh = ((bottomscreen-1)>>SFRACBITS);
      if (dc_yh >= viewheight)
         dc_yh = viewheight-1;
      if (dc_yl < 0)
         dc_yl = 0;
      if ((*src)==254)
         {
         shadingtable=seelevel;
         if (dc_yl <= dc_yh)
            R_TransColumn (buf);
         src++;
         offset=*(src++);
         shadingtable=oldlevel;
         }
      else
         {
         if (dc_yl <= dc_yh)
            {
            dc_source=src-offset;
            R_DrawColumn (buf);
            }
         src+=length;
         offset=*(src++);
         }
      }

   whereami=-2;
}


void ScaleMaskedPost (byte * src, byte * buf)
{
   int  offset;
   int  length;
   int  topscreen;
   int  bottomscreen;

   whereami=26;
   offset=*(src++);
   for (;offset!=255;)
      {
      length=*(src++);
      topscreen = sprtopoffset + (dc_invscale*offset);
      bottomscreen = topscreen + (dc_invscale*length);
      dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
      dc_yh = ((bottomscreen-1)>>SFRACBITS);
      if (dc_yh >= viewheight)
         dc_yh = viewheight-1;
      if (dc_yl < 0)
         dc_yl = 0;
      if (dc_yl <= dc_yh)
         {
         dc_source=src-offset;
         R_DrawColumn (buf);
#if (DEVELOPMENT == 1)
//         if (dc_firstsource<src)
//            SoftError("dc_firstsource=%p src=%p\n",dc_firstsource,src);
#endif
         }
      src+=length;
      offset=*(src++);
      }
}

void ScaleClippedPost (byte * src, byte * buf)
{
   int  offset;
   int  length;
   int  topscreen;
   int  bottomscreen;

   whereami=27;
   offset=*(src++);
   for (;offset!=255;)
      {
      length=*(src++);
      topscreen = sprtopoffset + (dc_invscale*offset);
      bottomscreen = topscreen + (dc_invscale*length);
      dc_yl = (topscreen+SFRACUNIT-1)>>SFRACBITS;
      dc_yh = ((bottomscreen-1)>>SFRACBITS);
      if (dc_yh >= viewheight)
         dc_yh = viewheight-1;
      if (dc_yl < 0)
         dc_yl = 0;
      if (dc_yl <= dc_yh)
         {
         dc_source=src-offset;
         R_DrawClippedColumn (buf);
         }
      src+=length;
      offset=*(src++);
      }
}

void ScaleSolidMaskedPost (int color, byte * src, byte * buf)
{
   int  offset;
   int  length;
   int  topscreen;
   int  bottomscreen;

   whereami=28;
   offset=*(src++);
   for (;offset!=255;)
      {
      length=*(src++);
      topscreen = sprtopoffset + (dc_invscale*offset);
      bottomscreen = topscreen + (dc_invscale*length);
      dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
      dc_yh = ((bottomscreen-1)>>SFRACBITS);
      if (dc_yh >= viewheight)
         dc_yh = viewheight-1;
      if (dc_yl < 0)
         dc_yl = 0;
      if (dc_yl <= dc_yh)
         {
         dc_source=src-offset;
         R_DrawSolidColumn (color, buf);
         }
      src+=length;
      offset=*(src++);
      }

}


void ScaleTransparentClippedPost (byte * src, byte * buf, int level)
{
   int  offset;
   int  length;
   int  topscreen;
   int  bottomscreen;
   byte * oldlevel;
   byte * seelevel;

   whereami=29;

   seelevel=colormap+(((level+64)>>2)<<8);
   oldlevel=shadingtable;
   offset=*(src++);
   for (;offset!=255;)
      {
      length=*(src++);
      topscreen = sprtopoffset + (dc_invscale*offset);
      bottomscreen = topscreen + (dc_invscale*length);
      dc_yl = (topscreen+SFRACUNIT)>>SFRACBITS;
      dc_yh = ((bottomscreen-1)>>SFRACBITS);
      if (dc_yh >= viewheight)
         dc_yh = viewheight-1;
      if (dc_yl < 0)
         dc_yl = 0;
      if ((*src)==254)
         {
         shadingtable=seelevel;
         if (dc_yl <= dc_yh)
            R_TransColumn (buf);
         src++;
         offset=*(src++);
         shadingtable=oldlevel;
         }
      else
         {
         if (dc_yl <= dc_yh)
            {
            dc_source=src-offset;
            R_DrawClippedColumn (buf);
            }
         src+=length;
         offset=*(src++);
         }
      }

}


void ScaleMaskedWidePost (byte * src, byte * buf, int x, int width)
{
#ifdef DOS
   int  ofs;
   int  msk;

   whereami=30;
   buf+=x>>2;
   ofs=((x&3)<<3)+(x&3)+width-1;
   VGAMAPMASK(*((byte *)mapmasks1+ofs));
   ScaleMaskedPost(src,buf);
   msk=(byte)*((byte *)mapmasks2+ofs);
   if (msk==0)
      return;
   buf++;
   VGAMAPMASK(msk);
   ScaleMaskedPost(src,buf);
   msk=(byte)*((byte *)mapmasks3+ofs);
   if (msk==0)
      return;
   buf++;
   VGAMAPMASK(msk);
   ScaleMaskedPost(src,buf);
#else
	buf += x;
	
	while (width--) {
		ScaleMaskedPost(src,buf);
		buf++;
	}
#endif
}

void ScaleClippedWidePost (byte * src, byte * buf, int x, int width)
{
#ifdef DOS
   int  ofs;
   int  msk;

   whereami=31;
   buf+=x>>2;
   ofs=((x&3)<<3)+(x&3)+width-1;
   VGAMAPMASK(*((byte *)mapmasks1+ofs));
   ScaleClippedPost(src,buf);
   msk=(byte)*((byte *)mapmasks2+ofs);
   if (msk==0)
      return;
	buf++;
   VGAMAPMASK(msk);
   ScaleClippedPost(src,buf);
   msk=(byte)*((byte *)mapmasks3+ofs);
   if (msk==0)
      return;
   buf++;
   VGAMAPMASK(msk);
   ScaleClippedPost(src,buf);
#else
	buf += x;
	
	while (width--) {
		ScaleClippedPost(src,buf);
		buf++;
	}
#endif
}


/*
=======================
=
= ScaleShape
=
=======================
*/

void ScaleShape (visobj_t * sprite)
{
   byte *shape;
   int      frac;
   patch_t *p;
   int      x1,x2;
   int      tx;
   int      size;
   int      plane;

   whereami=32;
   shape=W_CacheLumpNum(sprite->shapenum,PU_CACHE, Cvt_patch_t, 1);
   p=(patch_t *)shape;
   size=p->origsize>>7;
//   sprite->viewheight<<=1;
   dc_invscale=sprite->viewheight<<((10-HEIGHTFRACTION)-size);
   tx=-p->leftoffset;
   sprite->viewx=(sprite->viewx<<SFRACBITS)-(sprite->viewheight<<(SFRACBITS-HEIGHTFRACTION-1))+(SFRACUNIT>>1);
//
// calculate edges of the shape
//
        x1 = (sprite->viewx+(tx*dc_invscale))>>SFRACBITS;
        if (x1 >= viewwidth)
           {
           return;               // off the right side
			  }
        tx+=p->width;
        x2 = ((sprite->viewx+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
        if (x2 < 0)
           {
           return;         // off the left side
           }

// dc_iscale=(1<<(16+6+HEIGHTFRACTION+size))/sprite->viewheight;
   dc_iscale=0xffffffffu/(unsigned)dc_invscale;
   dc_texturemid=(((sprite->h1<<size) + p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
   sprtopoffset=centeryfrac -  FixedMul(dc_texturemid,dc_invscale);
   shadingtable=sprite->colormap;

   if (x1<0)
      {
      frac=dc_iscale*(-x1);
      x1=0;
      }
   else
      frac=0;
   x2 = x2 >= viewwidth ? viewwidth-1 : x2;

   if (sprite->viewheight>((1<<(HEIGHTFRACTION+6))<<size))
      {
      int      texturecolumn;
      int      lastcolumn;
      int      startx;
      int      width;

      width=1;
      startx=0;
      lastcolumn=-1;
      for (; x1<=x2 ; x1++, frac += dc_iscale)
        {
         if (posts[x1].wallheight>sprite->viewheight)
            {
            if (lastcolumn>=0)
               {
               ScaleMaskedWidePost(((p->collumnofs[lastcolumn])+shape),(byte *)bufferofs,startx,width);
               width=1;
               lastcolumn=-1;
               }
            continue;
				}
                texturecolumn = frac>>SFRACBITS;
         if ((texturecolumn==lastcolumn)&&(width<9))
            {
            width++;
            continue;
            }
         else
            {
            if (lastcolumn>=0)
               {
               ScaleMaskedWidePost(((p->collumnofs[lastcolumn])+shape),(byte *)bufferofs,startx,width);
               width=1;
               startx=x1;
               lastcolumn=texturecolumn;
               }
            else
               {
               startx=x1;
               lastcolumn=texturecolumn;
               }
            }
         }
      if (lastcolumn!=-1)
         ScaleMaskedWidePost(((p->collumnofs[lastcolumn])+shape),(byte *)bufferofs,startx,width);
      }
   else
      {
      byte * b;
      int    startfrac;
      int    startx;

      startx=x1;
      startfrac=frac;
      if (doublestep>1)
         {
#ifdef DOS
         for (plane=startx;plane<startx+4;plane+=2,startfrac+=(dc_iscale<<1))
#endif
            {
            frac=startfrac;
//   VGAWRITEMAP(plane&3);
#ifdef DOS
            for (x1=plane;x1<=x2;x1+=4, frac += (dc_iscale<<2))
#else
            for (x1=startx;x1<=x2;x1+=2, frac += (dc_iscale<<1))
#endif
               {
               if (
                   (posts[x1].wallheight>sprite->viewheight) &&
                   (posts[x1+1].wallheight>sprite->viewheight)
                  )
                  continue;
               if (x1==viewwidth-1)
                  ScaleMaskedWidePost(((p->collumnofs[frac>>SFRACBITS])+shape),(byte *)bufferofs,x1,1);
               else
                  ScaleMaskedWidePost(((p->collumnofs[frac>>SFRACBITS])+shape),(byte *)bufferofs,x1,2);
               }
            }
         }
      else
         {
#ifdef DOS
         for (plane=startx;plane<startx+4;plane++,startfrac+=dc_iscale)
#endif
            {
            frac=startfrac;

#ifdef DOS
            b=(byte *)bufferofs+(plane>>2);
            VGAWRITEMAP(plane&3);
#else
            b=(byte *)bufferofs+startx;
#endif

#ifdef DOS
            for (x1=plane;x1<=x2;x1+=4, frac += (dc_iscale<<2),b++)
#else
            for (x1=startx;x1<=x2;x1++, frac += dc_iscale,b++)
#endif
               {
               if (posts[x1].wallheight>sprite->viewheight)
                  continue;
               ScaleMaskedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
               }
            }
         }
      }
}


/*
=======================
=
= ScaleTranparentShape
=
=======================
*/

void ScaleTransparentShape (visobj_t * sprite)
{
   byte *shape;
   int      frac;
   transpatch_t *p;
   int      x1,x2;
   int      tx;
   int      size;
   byte * b;
   int    startfrac;
   int    startx;
   int    plane;

   whereami=33;
   shape=W_CacheLumpNum(sprite->shapenum,PU_CACHE, Cvt_transpatch_t, 1);
   p=(transpatch_t *)shape;
   size=p->origsize>>7;
   dc_invscale=sprite->viewheight<<((10-HEIGHTFRACTION)-size);
   tx=-p->leftoffset;
   sprite->viewx=(sprite->viewx<<SFRACBITS)-(sprite->viewheight<<(SFRACBITS-HEIGHTFRACTION-1));
//
// calculate edges of the shape
//
        x1 = (sprite->viewx+(tx*dc_invscale))>>SFRACBITS;
        if (x1 >= viewwidth)
           {
           return;               // off the right side
           }
        tx+=p->width;
        x2 = ((sprite->viewx+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
        if (x2 < 0)
           {
           return;         // off the left side
			  }

//   dc_iscale=(1<<(16+6+HEIGHTFRACTION+size))/sprite->viewheight;
   dc_iscale=0xffffffffu/(unsigned)dc_invscale;
   dc_texturemid=(((sprite->h1<<size)+p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
   sprtopoffset=centeryfrac - FixedMul(dc_texturemid,dc_invscale);
   shadingtable=sprite->colormap;

   if (x1<0)
      {
      frac=dc_iscale*(-x1);
      x1=0;
      }
   else
      frac=0;
   x2 = x2 >= viewwidth ? viewwidth-1 : x2;

#if 0
   for (; x1<=x2 ; x1++, frac += dc_iscale)
      {
      if (posts[x1].wallheight>sprite->viewheight)
         continue;
      VGAWRITEMAP(x1&3);
      VGAREADMAP(x1&3);
      ScaleTransparentPost(((p->collumnofs[frac>>SFRACBITS])+shape),(byte *)bufferofs+(x1>>2),sprite->h2);
      }
#endif
   startx=x1;
   startfrac=frac;

#ifdef DOS
   for (plane=startx;plane<startx+4;plane++,startfrac+=dc_iscale)
#endif

      {
      frac=startfrac;

#ifdef DOS
      b=(byte *)bufferofs+(plane>>2);
      VGAWRITEMAP(plane&3);
      VGAREADMAP(plane&3);
#else
     b=(byte *)bufferofs+startx;
#endif

#ifdef DOS
      for (x1=plane;x1<=x2;x1+=4, frac += (dc_iscale<<2),b++)
#else
      for (x1=startx;x1<=x2;x1++, frac += dc_iscale,b++)
#endif
         {
         if (posts[x1].wallheight>sprite->viewheight)
            continue;
         ScaleTransparentPost(((p->collumnofs[frac>>SFRACBITS])+shape),b,sprite->h2);
         }
      }
}

/*
=======================
=
= ScaleSolidShape
=
=======================
*/

void ScaleSolidShape (visobj_t * sprite)
{
   byte *shape;
   int      frac;
   patch_t *p;
   int      x1,x2;
   int      tx;
   int      size;
   int      plane;
	byte * b;
   int    startfrac;
   int    startx;

   whereami=34;
   shape=W_CacheLumpNum(sprite->shapenum,PU_CACHE, Cvt_patch_t, 1);
   p=(patch_t *)shape;
   size=p->origsize>>7;
   dc_invscale=sprite->viewheight<<((10-HEIGHTFRACTION)-size);
   tx=-p->leftoffset;
   sprite->viewx=(sprite->viewx<<SFRACBITS)-(sprite->viewheight<<(SFRACBITS-HEIGHTFRACTION-1))+(SFRACUNIT>>1);
//
// calculate edges of the shape
//
        x1 = (sprite->viewx+(tx*dc_invscale))>>SFRACBITS;
        if (x1 >= viewwidth)
           {
           return;               // off the right side
           }
        tx+=p->width;
        x2 = ((sprite->viewx+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
        if (x2 < 0)
           {
           return;         // off the left side
           }

//   dc_iscale=(1<<(16+6+HEIGHTFRACTION+size))/sprite->viewheight;
   dc_iscale=0xffffffffu/(unsigned)dc_invscale;
   dc_texturemid=(((sprite->h1<<size)+p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
   sprtopoffset=centeryfrac - FixedMul(dc_texturemid,dc_invscale);
   shadingtable=sprite->colormap;

   if (x1<0)
      {
      frac=dc_iscale*(-x1);
      x1=0;
      }
   else
      frac=0;
   x2 = x2 >= viewwidth ? viewwidth-1 : x2;

   startx=x1;
   startfrac=frac;

#ifdef DOS
   for (plane=startx;plane<startx+4;plane++,startfrac+=dc_iscale)
#endif
   
      {
		frac=startfrac;

#ifdef DOS
      b=(byte *)bufferofs+(plane>>2);
      VGAWRITEMAP(plane&3);
#else
      b=(byte *)bufferofs+startx;
#endif

#ifdef DOS
      for (x1=plane;x1<=x2;x1+=4, frac += (dc_iscale<<2),b++)
#else
      for (x1=startx;x1<=x2;x1++, frac += dc_iscale,b++)
#endif
         {
         if (posts[x1].wallheight>sprite->viewheight)
            continue;
         ScaleSolidMaskedPost(sprite->h2,((p->collumnofs[frac>>SFRACBITS])+shape),b);
         }
      }
}


/*
=======================
=
= ScaleWeapon
=
=======================
*/

void ScaleWeapon (int xoff, int y, int shapenum)
{
	byte *shape;
	int      frac;
	int      h;
	patch_t *p;
	int      x1,x2;
	int      tx;
	int      xcent;
	byte * b;
	int    startfrac;
	int    startx;
   int    plane;

   whereami=35;
   SetPlayerLightLevel();
   shape=W_CacheLumpNum(shapenum,PU_CACHE, Cvt_patch_t, 1);
   p=(patch_t *)shape;
   h=((p->origsize*weaponscale)>>17);
   centeryclipped=(viewheight-h)+FixedMul(y,weaponscale);
   xcent=centerx+FixedMul(xoff,weaponscale);
   dc_invscale=(h<<17)/p->origsize;

	tx=-p->leftoffset;
	xcent=(xcent<<SFRACBITS)-(h<<SFRACBITS);
//
// calculate edges of the shape
//
		  x1 = (xcent+(tx*dc_invscale))>>SFRACBITS;
		  if (x1 >= viewwidth)
					 return;               // off the right side
        tx+=p->width;
        x2 = ((xcent+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
        if (x2 < 0)
                return;         // off the left side

   dc_iscale=0xffffffffu/(unsigned)dc_invscale;
   dc_texturemid=(((p->origsize>>1)+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>2);
   sprtopoffset=(centeryclipped<<16) - FixedMul(dc_texturemid,dc_invscale);

//
// store information in a vissprite
//
   if (x1<0)
		{
      frac=dc_iscale*(-x1);
      x1=0;
      }
   else
      frac=0;

   x2 = x2 >= viewwidth ? viewwidth-1 : x2;

	startx=x1;
	startfrac=frac;

#ifdef DOS
   for (plane=startx;plane<startx+4;plane++,startfrac+=dc_iscale)
#endif
      {
      frac=startfrac;
#ifdef DOS
      b=(byte *)bufferofs+(plane>>2);
#else
      b=(byte *)bufferofs+startx;
#endif
      VGAWRITEMAP(plane&3);
#ifdef DOS
      for (x1=plane; x1<=x2 ; x1+=4, frac += dc_iscale<<2,b++)
#else
      for (x1=startx; x1<=x2 ; x1++, frac += dc_iscale,b++)
#endif
         ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
      }
}




/*
=======================
=
= DrawUnScaledSprite
=
=======================
*/

void DrawUnScaledSprite (int x, int y, int shapenum, int shade)
{
   byte *shape;
   int      frac;
   patch_t *p;
   int      x1,x2;
   int      tx;
   int      xcent;
   byte * b;
   int    startfrac;
   int    startx;
	int    plane;
        
   whereami=36;
   shadingtable=colormap+(shade<<8);
   centeryclipped=y;
   xcent=x;
   shape=W_CacheLumpNum(shapenum,PU_CACHE, Cvt_patch_t, 1);
   p=(patch_t *)shape;
	dc_invscale=0x10000;

   tx=-p->leftoffset;
   xcent-=p->origsize>>1;
//
// calculate edges of the shape
//
		  x1 = xcent+tx;
		  if (x1 >= viewwidth)
					 return;               // off the right side
		  tx+=p->width;
		  x2 = xcent+tx - 1;
		  if (x2 < 0)
					 return;         // off the left side

	dc_iscale=0x10000;
   dc_texturemid=(((p->height>>1)+p->topoffset)<<SFRACBITS);//+(SFRACUNIT>>1);
	sprtopoffset=(centeryclipped<<16) - dc_texturemid;

//
// store information in a vissprite
//
   if (x1<0)
      {
      frac=dc_iscale*(-x1);
      x1=0;
      }
   else
      frac = 0;

   x2 = x2 >= viewwidth ? viewwidth-1 : x2;

   startx=x1;
   startfrac=frac;

#ifdef DOS
   for (plane=startx;plane<startx+4;plane++,startfrac+=dc_iscale)
#endif

		{
		frac=startfrac;

#ifdef DOS
		b=(byte *)bufferofs+(plane>>2);
      VGAWRITEMAP(plane&3);
#else
                b=(byte *)bufferofs+startx;
#endif

#ifdef DOS
		for (x1=plane; x1<=x2 ; x1+=4, frac += dc_iscale<<2,b++)
#else
		for (x1=startx; x1<=x2 ; x1++, frac += dc_iscale,b++)
#endif
			ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
		}
}


/*
=======================
=
= DrawScreenSprite
=
=======================
*/

void DrawScreenSprite (int x, int y, int shapenum)
{
   whereami=37;
	ScaleWeapon (x-160, y-200, shapenum);
}

/*
=======================
=
= DrawPositionedScaledSprite
=
=======================
*/

void DrawPositionedScaledSprite (int x, int y, int shapenum, int height, int type)
{
	byte *shape;
	int      frac;
	patch_t *p;
	transpatch_t *tp;
	int      x1,x2;
	int      tx;
	int      xcent;
	byte * b;
	int    startfrac;
	int    startx;
	int    plane;
	int    size;

   whereami=38;
   shadingtable=colormap+(1<<12);
	centeryclipped=y;
	xcent=x;
	shape=W_CacheLumpNum(shapenum,PU_CACHE, Cvt_patch_t, 1); // was transpatch, fixed
	p=(patch_t *)shape;
	tp=(transpatch_t *)shape;

	size=p->origsize>>7;
	dc_invscale=height<<(10-size);

	tx=-p->leftoffset;
	xcent=(xcent<<SFRACBITS)-(height<<(SFRACBITS-1));

//
// calculate edges of the shape
//
		  x1 = (xcent+(tx*dc_invscale))>>SFRACBITS;
		  if (x1 >= viewwidth)
					 return;               // off the right side
		  tx+=p->width;
		  x2 = ((xcent+(tx*dc_invscale)) >>SFRACBITS) - 1 ;
		  if (x2 < 0)
					 return;         // off the left side

   dc_iscale=0xffffffffu/(unsigned)dc_invscale;
//   dc_iscale=(1<<(16+6+size))/height;
   dc_texturemid=(((32<<size)+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
   sprtopoffset=(centeryclipped<<16) - FixedMul(dc_texturemid,dc_invscale);

//
// store information in a vissprite
//
   if (x1<0)
      {
      frac=dc_iscale*(-x1);
      x1=0;
      }
   else
      frac=0;

   x2 = x2 >= viewwidth ? viewwidth-1 : x2;

	startx=x1;
   startfrac=frac;

#ifdef DOS
   for (plane=startx;plane<startx+4;plane++,startfrac+=dc_iscale)
#endif

      {
      frac=startfrac;

#ifdef DOS
      b=(byte *)bufferofs+(plane>>2);
      VGAWRITEMAP(plane&3);
      VGAREADMAP(plane&3);
#else
      b=(byte *)bufferofs+startx;
#endif

#ifdef DOS
      for (x1=plane; x1<=x2 ; x1+=4, frac += dc_iscale<<2,b++)
#else
      for (x1=startx; x1<=x2 ; x1++, frac += dc_iscale,b++)
#endif
         if (type==0)
            ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
         else
				ScaleTransparentClippedPost(((tp->collumnofs[frac>>SFRACBITS])+shape),b,transparentlevel);
		}
}


/*
=================
=
= DrawScreenSizedSprite
=
=================
*/
extern int G_gmasklump;
void DrawScreenSizedSprite (int lump)
{
	//draws gasmask among other things zxcv
   byte *shape,*src;
   int      frac;
   patch_t *p;
   int      x1,x2;
   int      tx;
//   int      plane;
   byte * b;
   int    startfrac;

   int  offset;
   int  length;
   int  topscreen;
   int  bottomscreen;
   byte  *cnt,*Ycnt;

  // SetTextMode (  );
   whereami=39;
   shadingtable=colormap+(1<<12);
   shape=W_CacheLumpNum(lump,PU_CACHE, Cvt_patch_t, 1);
   p=(patch_t *)shape;
   dc_invscale=(viewwidth<<16)/p->origsize;
   tx=-p->leftoffset;
   centeryclipped=viewheight>>1;
   //centeryclipped=(viewheight>>1)+43;
//
// calculate edges of the shape
//
        x1 = (tx*dc_invscale)>>SFRACBITS;
        if (x1 >= viewwidth)
           {
           return;               // off the right side
			  }
        tx+=p->width;
        x2 = ((tx*dc_invscale) >>SFRACBITS) - 1 ;
        if (x2 < 0)
           {
           return;         // off the left side
           }

   dc_iscale=0xffffffffu/(unsigned)dc_invscale;
   dc_texturemid=(((p->origsize>>1) + p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
   sprtopoffset=(centeryclipped<<16) -  FixedMul(dc_texturemid,dc_invscale);

   x2 = (viewwidth-1);

   startfrac=0;

      {
      frac=startfrac;
      b=(byte *)bufferofs;

	  /////////////  BNA PATCH //////////////////////////////////////////////////////////
	     //gmasklump=W_GetNumForName("p_gmask"); //=783
	     //perhaps I should have painted the mask in a seperate buffer
	     //and streched it and copyet it back, but that would demand
	     //a new buffer (size=800x600) and slowed the game down so ?

		 // if its the gasmask, paint black patches at hires
		 if ((lump == G_gmasklump)&&(iGLOBAL_SCREENWIDTH>320)) { 
			src = ((p->collumnofs[frac>>SFRACBITS])+shape);
			offset=*(src++);
			length=*(src++);
			topscreen = sprtopoffset + (dc_invscale*offset);
			bottomscreen = topscreen + (dc_invscale*length);
			dc_yl = (topscreen+SFRACUNIT-1)>>SFRACBITS;//=41  viewheight=584
			dc_yh = ((bottomscreen-1)>>SFRACBITS);//=540      viewwidth =800
			//paint upper black patch in gasmask
			for (cnt=b;cnt<b+viewwidth;cnt++){
				for (Ycnt=cnt;Ycnt<cnt+(dc_yl*iGLOBAL_SCREENWIDTH);Ycnt+=iGLOBAL_SCREENWIDTH){
				 *Ycnt = 36;
				}
			}
			//paint lower black patch in gasmask
			for (cnt=b+(dc_yh*iGLOBAL_SCREENWIDTH);cnt<b+(dc_yh*iGLOBAL_SCREENWIDTH)+viewwidth;cnt++){
				for (Ycnt=cnt;Ycnt<b+(viewheight*iGLOBAL_SCREENWIDTH);Ycnt+=iGLOBAL_SCREENWIDTH){
				 *Ycnt = 36;
				}
			}
		 }
      ///////////////////////////////////////////////////////////////////////////////////
      for (x1=0;x1<=x2;x1++, frac += dc_iscale,b++)

         {
             ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
         }
      }
}

#if 0
   byte *shape;
   int      frac;
   patch_t *p;
   int      x1,x2;
   int      tx;
   int      xdc_invscale;
   int      xdc_iscale;
   byte *   buf;
   byte *   b;
   int      plane;
   int      startx,startfrac;

   whereami=39;
   SetPlayerLightLevel();
   buf=(byte *)bufferofs;
   shape=W_CacheLumpNum(lump,PU_CACHE);
   p=(patch_t *)shape;
   dc_invscale=(viewheight<<16)/200;
	xdc_invscale=(viewwidth<<16)/320;

   tx=-p->leftoffset;
   centeryclipped=viewheight>>1;
//
// calculate edges of the shape
//
        x1 = (tx*xdc_invscale)>>SFRACBITS;
        if (x1 >= viewwidth)
                return;               // off the right side
        tx+=p->width;
        x2 = ((tx*xdc_invscale)>>SFRACBITS) - 1 ;
		  if (x2 < 0)
                return;         // off the left side

   dc_iscale=(200*65536)/viewheight;
   xdc_iscale=(320*65536)/viewwidth;
   dc_texturemid=(((p->height>>1)+p->topoffset)<<SFRACBITS)+(SFRACUNIT>>1);
   sprtopoffset=(centeryclipped<<16) - FixedMul(dc_texturemid,dc_invscale);

//
// store information in a vissprite
//
   if (x1<0)
      {
      frac=xdc_iscale*(-x1);
      x1=0;
      }
   else
      frac=0;
        x2 = x2 >= viewwidth ? viewwidth-1 : x2;

   startx=x1;
   startfrac=frac;
   for (plane=startx;plane<startx+4;plane++,startfrac+=xdc_iscale)
      {
      frac=startfrac;
      b=(byte *)bufferofs+(plane>>2);
      VGAWRITEMAP(plane&3);
      for (x1=plane; x1<=x2 ; x1+=4, frac += xdc_iscale<<2,b++)
         ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b);
      }
}
#endif



//******************************************************************************
//
// DrawNormalPost
//
//******************************************************************************

void DrawNormalPost (byte * src, byte * buf)
{
   int  offset;
   int  length;
   int  s;

   whereami=40;

   while (1)
      {
      offset=*(src++);
      if (offset==0xff)
         return;
      else
         {
            length=*(src++);
            for (s=0;s<length;s++) {
                // Spaced out a little for tracking a bug. Should be equivalent.
                byte *saddr = src+s;
                byte *daddr = buf + ylookup[offset + s];
                byte val = *saddr;
                *daddr = val;
//                *(buf+ylookup[offset+s])=*(src+s);
            }
            src+=length;
         }
      }
}



//******************************************************************************
//
// DrawNormalSprite
//
//******************************************************************************

void DrawNormalSprite (int x, int y, int shapenum)
{
   byte *buffer;
   int cnt;
   byte *shape;
   patch_t *p;
   int plane;
   byte * b;
   int startx;

   whereami=41;

   shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_patch_t, 1);
   p = (patch_t *)shape;

   if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>iGLOBAL_SCREENWIDTH))
      Error ("DrawNormalSprite: x is out of range x=%d\n",x-p->leftoffset+p->width);
   if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>iGLOBAL_SCREENHEIGHT))
      Error ("DrawNormalSprite: y is out of range y=%d\n",y-p->topoffset+p->height);

   startx=x-p->leftoffset;
   buffer = (byte*)bufferofs+ylookup[y-p->topoffset];

#ifdef DOS
   for (plane=startx;plane<startx+4;plane++)
#endif
      {
#ifdef DOS
      b=buffer+(plane>>2);
      VGAWRITEMAP(plane&3);
#else
      b=buffer+startx; 
#endif
     
#ifdef DOS 
      for (cnt = plane-startx; cnt < p->width; cnt+=4,b++)
#else
      for (cnt = 0; cnt < p->width; cnt++,b++)
#endif
         DrawNormalPost ((byte *)(p->collumnofs[cnt]+shape), b);
      }
}

#ifndef DOS

void R_DrawColumn (byte * buf)
{
	// This is *NOT* 100% correct - DDOI
	int count;
	int frac, fracstep;
	byte *dest;

	count = dc_yh - dc_yl + 1;
	if (count < 0) return;

	dest = buf + ylookup[dc_yl];

	fracstep = dc_iscale;
	frac = dc_texturemid + (dc_yl-centery)*fracstep;

	while (count--) {
		//*dest = test++;
		*dest = shadingtable[dc_source[(frac>>SFRACBITS)]];
		dest += iGLOBAL_SCREENWIDTH;
		frac += fracstep;
	}
}

void R_TransColumn (byte * buf)
{
	int count;
	byte *dest;

	count = dc_yh - dc_yl + 1;
	if (count < 0) return;

	dest = buf + ylookup[dc_yl];

	while (count--)
	{
		*dest = shadingtable[*dest];
		dest += iGLOBAL_SCREENWIDTH;
	}
}

void R_DrawWallColumn (byte * buf)
{
	// This is *NOT* 100% correct - DDOI
	int count;
	int frac, fracstep;
	byte *dest;

	count = dc_yh - dc_yl;
	if (count < 0) return;

	dest = buf + ylookup[dc_yl];

	fracstep = dc_iscale;
	frac = dc_texturemid + (dc_yl-centery)*fracstep;
	frac <<= 10;
	fracstep <<= 10;

	while (count--) {
		//*dest = 6;
		*dest = shadingtable[dc_source[(((unsigned)frac)>>26)]];
		dest += iGLOBAL_SCREENWIDTH;
		frac += fracstep;
	}
}

void R_DrawClippedColumn (byte * buf)
{
	// This is *NOT* 100% correct - DDOI zxcv
	int count;
	int frac, fracstep;
	byte *dest;
//		byte *b;int y;

	count = dc_yh - dc_yl + 1;
	if (count < 0) return;

   dest = buf + ylookup[dc_yl];


	fracstep = dc_iscale;
	frac = dc_texturemid + (dc_yl-centeryclipped)*fracstep;

	while (count--) {
		*dest = shadingtable[dc_source[(((unsigned)frac)>>SFRACBITS)]];
		dest += iGLOBAL_SCREENWIDTH;
		frac += fracstep;
	}
}

void R_DrawSolidColumn (int color, byte * buf)
{
	int count;
	int frac, fracstep;
	byte *dest;

	count = dc_yh - dc_yl + 1;
	if (count < 0) return;

	dest = buf + ylookup[dc_yl];

	while (count--)
	{
		*dest = (byte)color;
		dest += iGLOBAL_SCREENWIDTH;
	}
}

#endif
