shithub: fork

Download patch

ref: e4c57f3ea9cb88c50b47ca3c99b2adf85ab1a984
parent: 237770519d77497c6db9da7ed13851be38c78d8e
author: qwx <qwx@sciops.net>
date: Tue Jul 8 02:28:47 EDT 2025

doom: allow sprite replacements in pwads

--- /dev/null
+++ b/sys/src/games/doom/r_things.c
@@ -1,0 +1,992 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// $Id:$
+//
+// Copyright (C) 1993-1996 by id Software, Inc.
+//
+// This source is available for distribution and/or modification
+// only under the terms of the DOOM Source Code License as
+// published by id Software. All rights reserved.
+//
+// The source is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
+// for more details.
+//
+// $Log:$
+//
+// DESCRIPTION:
+//	Refresh of things, i.e. objects represented by sprites.
+//
+//-----------------------------------------------------------------------------
+
+
+static const char
+rcsid[] = "$Id: r_things.c,v 1.5 1997/02/03 16:47:56 b1 Exp $";
+
+#include "doomdef.h"
+#include "m_swap.h"
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+
+#include "doomstat.h"
+
+
+
+#define MINZ				(FRACUNIT*4)
+#define BASEYCENTER			100
+
+//void R_DrawColumn (void);
+//void R_DrawFuzzColumn (void);
+
+
+
+typedef struct
+{
+	int	x1;
+	int	x2;
+
+	int	column;
+	int	topclip;
+	int	bottomclip;
+} maskdraw_t;
+
+
+
+//
+// Sprite rotation 0 is facing the viewer,
+//  rotation 1 is one angle turn CLOCKWISE around the axis.
+// This is not the same as the angle,
+//  which increases counter clockwise (protractor).
+// There was a lot of stuff grabbed wrong, so I changed it...
+//
+fixed_t		pspritescale;
+fixed_t		pspriteiscale;
+
+lighttable_t**	spritelights;
+
+// constant arrays
+//  used for psprite clipping and initializing clipping
+short		negonearray[SCREENWIDTH];
+short		screenheightarray[SCREENWIDTH];
+
+
+//
+// INITIALIZATION FUNCTIONS
+//
+
+// variables used to look up
+//  and range check thing_t sprites patches
+spritedef_t*	sprites;
+int		numsprites;
+
+spriteframe_t	sprtemp[29];
+int		maxframe;
+char*		spritename;
+
+
+
+
+//
+// R_InstallSpriteLump
+// Local function for R_InitSprites.
+//
+void
+R_InstallSpriteLump
+( int		lump,
+  unsigned	frame,
+  unsigned	rotation,
+  boolean	flipped )
+{
+    int		r;
+	
+    if (frame >= 29 || rotation > 8)
+	I_Error("R_InstallSpriteLump: "
+		"Bad frame characters in lump %i", lump);
+	
+    if ((int)frame > maxframe)
+	maxframe = frame;
+		
+    if (rotation == 0)
+    {
+	// the lump should be used for all rotations
+	if (sprtemp[frame].rotate == false)
+	    //I_Error ("R_InitSprites: Sprite %s frame %c has "
+		//     "multip rot=0 lump", spritename, 'A'+frame);
+		return;
+
+	if (sprtemp[frame].rotate == true)
+	    I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
+		     "and a rot=0 lump", spritename, 'A'+frame);
+			
+	sprtemp[frame].rotate = false;
+	for (r=0 ; r<8 ; r++)
+	{
+	    sprtemp[frame].lump[r] = lump - firstspritelump;
+	    sprtemp[frame].flip[r] = (byte)flipped;
+	}
+	return;
+    }
+	
+    // the lump is only used for one rotation
+    if (sprtemp[frame].rotate == false)
+	I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
+		 "and a rot=0 lump", spritename, 'A'+frame);
+		
+    sprtemp[frame].rotate = true;
+
+    // make 0 based
+    rotation--;		
+    if (sprtemp[frame].lump[rotation] != -1)
+	I_Error ("R_InitSprites: Sprite %s : %c : %c "
+		 "has two lumps mapped to it",
+		 spritename, 'A'+frame, '1'+rotation);
+		
+    sprtemp[frame].lump[rotation] = lump - firstspritelump;
+    sprtemp[frame].flip[rotation] = (byte)flipped;
+}
+
+
+
+
+//
+// R_InitSpriteDefs
+// Pass a null terminated list of sprite names
+//  (4 chars exactly) to be used.
+// Builds the sprite rotation matrixes to account
+//  for horizontally flipped sprites.
+// Will report an error if the lumps are inconsistant. 
+// Only called at startup.
+//
+// Sprite lump names are 4 characters for the actor,
+//  a letter for the frame, and a number for the rotation.
+// A sprite that is flippable will have an additional
+//  letter/number appended.
+// The rotation character can be 0 to signify no rotations.
+//
+void R_InitSpriteDefs (char** namelist) 
+{ 
+/*    char**	check; */
+    int		i;
+    int		l;
+    int		frame;
+    int		rotation;
+    int		start;
+    int		end;
+    int		patched;
+    char*	name;
+
+/* BUG
+   This would work if the namelist was NULL terminated which it is not.
+   The array comes from info.c which is limited to NUMSPRITES, so simply
+   use NUMSPRITES for numsprites.. simple.
+
+   This is left here in case a decision is made to make it NULL terminated.
+
+    // count the number of sprite names
+    check = namelist;
+    while (*check != NULL)
+	check++;
+
+    numsprites = check-namelist;
+
+    if (!numsprites)
+	return;
+*/
+numsprites = NUMSPRITES;
+		
+    sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
+	
+    start = firstspritelump-1;
+    end = lastspritelump+1;
+	
+    // scan all the lump names for each of the names,
+    //  noting the highest frame letter.
+    // Just compare 4 characters as ints
+    for (i=0 ; i<numsprites ; i++)
+    {
+	spritename = namelist[i];
+	memset (sprtemp,-1, sizeof(sprtemp));
+		
+	maxframe = -1;
+	name = namelist[i];
+	
+	// scan the lumps,
+	//  filling in the frames for whatever is found
+	for (l=start+1 ; l<end ; l++)
+	{
+	    if (memcmp(lumpinfo[l].name, name, 4) == 0)
+	    {
+		frame = lumpinfo[l].name[4] - 'A';
+		rotation = lumpinfo[l].name[5] - '0';
+
+		if (modifiedgame)
+		    patched = W_GetNumForName (lumpinfo[l].name);
+		else
+		    patched = l;
+
+		R_InstallSpriteLump (patched, frame, rotation, false);
+
+		if (lumpinfo[l].name[6])
+		{
+		    frame = lumpinfo[l].name[6] - 'A';
+		    rotation = lumpinfo[l].name[7] - '0';
+		    R_InstallSpriteLump (l, frame, rotation, true);
+		}
+	    }
+	}
+	
+	// check the frames that were found for completeness
+	if (maxframe == -1)
+	{
+	    sprites[i].numframes = 0;
+	    continue;
+	}
+		
+	maxframe++;
+	
+	for (frame = 0 ; frame < maxframe ; frame++)
+	{
+	    switch ((int)sprtemp[frame].rotate)
+	    {
+	      case -1:
+		// no rotations were found for that frame at all
+		I_Error ("R_InitSprites: No patches found "
+			 "for %s frame %c", namelist[i], frame+'A');
+		break;
+		
+	      case 0:
+		// only the first rotation is needed
+		break;
+			
+	      case 1:
+		// must have all 8 frames
+		for (rotation=0 ; rotation<8 ; rotation++)
+		    if (sprtemp[frame].lump[rotation] == -1)
+			I_Error ("R_InitSprites: Sprite %s frame %c "
+				 "is missing rotations",
+				 namelist[i], frame+'A');
+		break;
+	    }
+	}
+	
+	// allocate space for the frames present and copy sprtemp to it
+	sprites[i].numframes = maxframe;
+	sprites[i].spriteframes = 
+	    Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
+	memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
+    }
+
+}
+
+
+
+
+//
+// GAME FUNCTIONS
+//
+vissprite_t	vissprites[MAXVISSPRITES];
+vissprite_t*	vissprite_p;
+int		newvissprite;
+
+
+
+//
+// R_InitSprites
+// Called at program start.
+//
+void R_InitSprites (char** namelist)
+{
+    int		i;
+	
+    for (i=0 ; i<SCREENWIDTH ; i++)
+    {
+	negonearray[i] = -1;
+    }
+	
+    R_InitSpriteDefs (namelist);
+}
+
+
+
+//
+// R_ClearSprites
+// Called at frame start.
+//
+void R_ClearSprites (void)
+{
+    vissprite_p = vissprites;
+}
+
+
+//
+// R_NewVisSprite
+//
+vissprite_t	overflowsprite;
+
+vissprite_t* R_NewVisSprite (void)
+{
+    if (vissprite_p == &vissprites[MAXVISSPRITES])
+	return &overflowsprite;
+    
+    vissprite_p++;
+    return vissprite_p-1;
+}
+
+
+
+//
+// R_DrawMaskedColumn
+// Used for sprites and masked mid textures.
+// Masked means: partly transparent, i.e. stored
+//  in posts/runs of opaque pixels.
+//
+short*		mfloorclip;
+short*		mceilingclip;
+
+fixed_t		spryscale;
+fixed_t		sprtopscreen;
+
+void R_DrawMaskedColumn (column_t* column)
+{
+    int		topscreen;
+    int 	bottomscreen;
+    fixed_t	basetexturemid;
+	
+    basetexturemid = dc_texturemid;
+	
+    for ( ; column->topdelta != 0xff ; ) 
+    {
+	// calculate unclipped screen coordinates
+	//  for post
+	topscreen = sprtopscreen + spryscale*column->topdelta;
+	bottomscreen = topscreen + spryscale*column->length;
+
+	dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
+	dc_yh = (bottomscreen-1)>>FRACBITS;
+		
+	if (dc_yh >= mfloorclip[dc_x])
+	    dc_yh = mfloorclip[dc_x]-1;
+	if (dc_yl <= mceilingclip[dc_x])
+	    dc_yl = mceilingclip[dc_x]+1;
+
+	if (dc_yl <= dc_yh)
+	{
+	    dc_source = (byte *)column + 3;
+	    dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
+	    // dc_source = (byte *)column + 3 - column->topdelta;
+
+	    // Drawn by either R_DrawColumn
+	    //  or (SHADOW) R_DrawFuzzColumn.
+	    colfunc ();	
+	}
+	column = (column_t *)(  (byte *)column + column->length + 4);
+    }
+	
+    dc_texturemid = basetexturemid;
+}
+
+
+
+//
+// R_DrawVisSprite
+//  mfloorclip and mceilingclip should also be set.
+//
+void
+R_DrawVisSprite
+( vissprite_t*		vis,
+  int			/*x1*/,
+  int			/*x2*/ )
+{
+    column_t*		column;
+    int			texturecolumn;
+    fixed_t		frac;
+    patch_t*		patch;
+	
+	
+    patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE);
+
+    dc_colormap = vis->colormap;
+    
+    if (!dc_colormap)
+    {
+	// NULL colormap = shadow draw
+	colfunc = fuzzcolfunc;
+    }
+    else if (vis->mobjflags & MF_TRANSLATION)
+    {
+	colfunc = R_DrawTranslatedColumn;
+	dc_translation = translationtables - 256 +
+	    ( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
+    }
+	
+    dc_iscale = abs(vis->xiscale)>>detailshift;
+    dc_texturemid = vis->texturemid;
+    frac = vis->startfrac;
+    spryscale = vis->scale;
+    sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
+	
+    for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale)
+    {
+	texturecolumn = frac>>FRACBITS;
+#ifdef RANGECHECK
+	if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+	    I_Error ("R_DrawSpriteRange: bad texturecolumn");
+#endif
+	column = (column_t *) ((byte *)patch +
+			       LONG(patch->columnofs[texturecolumn]));
+	R_DrawMaskedColumn (column);
+    }
+
+    colfunc = basecolfunc;
+}
+
+
+
+//
+// R_ProjectSprite
+// Generates a vissprite for a thing
+//  if it might be visible.
+//
+void R_ProjectSprite (mobj_t* thing)
+{
+    fixed_t		tr_x;
+    fixed_t		tr_y;
+    
+    fixed_t		gxt;
+    fixed_t		gyt;
+    
+    fixed_t		tx;
+    fixed_t		tz;
+
+    fixed_t		xscale;
+    
+    int			x1;
+    int			x2;
+
+    spritedef_t*	sprdef;
+    spriteframe_t*	sprframe;
+    int			lump;
+    
+    unsigned		rot;
+    boolean		flip;
+    
+    int			index;
+
+    vissprite_t*	vis;
+    
+    angle_t		ang;
+    fixed_t		iscale;
+    
+    // transform the origin point
+    tr_x = thing->x - viewx;
+    tr_y = thing->y - viewy;
+	
+    gxt = FixedMul(tr_x,viewcos); 
+    gyt = -FixedMul(tr_y,viewsin);
+    
+    tz = gxt-gyt; 
+
+    // thing is behind view plane?
+    if (tz < MINZ)
+	return;
+    
+    xscale = FixedDiv(projection, tz);
+	
+    gxt = -FixedMul(tr_x,viewsin); 
+    gyt = FixedMul(tr_y,viewcos); 
+    tx = -(gyt+gxt); 
+
+    // too far off the side?
+    if (abs(tx)>(tz<<2))
+	return;
+    
+    // decide which patch to use for sprite relative to player
+#ifdef RANGECHECK
+    if ((unsigned)thing->sprite >= numsprites)
+	I_Error ("R_ProjectSprite: invalid sprite number %i ",
+		 thing->sprite);
+#endif
+    sprdef = &sprites[thing->sprite];
+#ifdef RANGECHECK
+    if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes )
+	I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
+		 thing->sprite, thing->frame);
+#endif
+    sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
+
+    if (sprframe->rotate)
+    {
+	// choose a different rotation based on player view
+	ang = R_PointToAngle (thing->x, thing->y);
+	rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
+	lump = sprframe->lump[rot];
+	flip = (boolean)sprframe->flip[rot];
+    }
+    else
+    {
+	// use single rotation for all views
+	lump = sprframe->lump[0];
+	flip = (boolean)sprframe->flip[0];
+    }
+    
+    // calculate edges of the shape
+    tx -= spriteoffset[lump];	
+    x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
+
+    // off the right side?
+    if (x1 > viewwidth)
+	return;
+    
+    tx +=  spritewidth[lump];
+    x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
+
+    // off the left side
+    if (x2 < 0)
+	return;
+    
+    // store information in a vissprite
+    vis = R_NewVisSprite ();
+    vis->mobjflags = thing->flags;
+    vis->scale = xscale<<detailshift;
+    vis->gx = thing->x;
+    vis->gy = thing->y;
+    vis->gz = thing->z;
+    vis->gzt = thing->z + spritetopoffset[lump];
+    vis->texturemid = vis->gzt - viewz;
+    vis->x1 = x1 < 0 ? 0 : x1;
+    vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;	
+    iscale = FixedDiv (FRACUNIT, xscale);
+
+    if (flip)
+    {
+	vis->startfrac = spritewidth[lump]-1;
+	vis->xiscale = -iscale;
+    }
+    else
+    {
+	vis->startfrac = 0;
+	vis->xiscale = iscale;
+    }
+
+    if (vis->x1 > x1)
+	vis->startfrac += vis->xiscale*(vis->x1-x1);
+    vis->patch = lump;
+    
+    // get light level
+    if (thing->flags & MF_SHADOW)
+    {
+	// shadow draw
+	vis->colormap = NULL;
+    }
+    else if (fixedcolormap)
+    {
+	// fixed map
+	vis->colormap = fixedcolormap;
+    }
+    else if (thing->frame & FF_FULLBRIGHT)
+    {
+	// full bright
+	vis->colormap = colormaps;
+    }
+    
+    else
+    {
+	// diminished light
+	index = xscale>>(LIGHTSCALESHIFT-detailshift);
+
+	if (index >= MAXLIGHTSCALE) 
+	    index = MAXLIGHTSCALE-1;
+
+	vis->colormap = spritelights[index];
+    }	
+}
+
+
+
+
+//
+// R_AddSprites
+// During BSP traversal, this adds sprites by sector.
+//
+void R_AddSprites (sector_t* sec)
+{
+    mobj_t*		thing;
+    int			lightnum;
+
+    // BSP is traversed by subsector.
+    // A sector might have been split into several
+    //  subsectors during BSP building.
+    // Thus we check whether its already added.
+    if (sec->validcount == validcount)
+	return;		
+
+    // Well, now it will be done.
+    sec->validcount = validcount;
+	
+    lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+    if (lightnum < 0)		
+	spritelights = scalelight[0];
+    else if (lightnum >= LIGHTLEVELS)
+	spritelights = scalelight[LIGHTLEVELS-1];
+    else
+	spritelights = scalelight[lightnum];
+
+    // Handle all things in sector.
+    for (thing = sec->thinglist ; thing ; thing = thing->snext)
+	R_ProjectSprite (thing);
+}
+
+
+//
+// R_DrawPSprite
+//
+void R_DrawPSprite (pspdef_t* psp)
+{
+    fixed_t		tx;
+    int			x1;
+    int			x2;
+    spritedef_t*	sprdef;
+    spriteframe_t*	sprframe;
+    int			lump;
+    boolean		flip;
+    vissprite_t*	vis;
+    vissprite_t		avis;
+    
+    // decide which patch to use
+#ifdef RANGECHECK
+    if ( (unsigned)psp->state->sprite >= numsprites)
+	I_Error ("R_ProjectSprite: invalid sprite number %i ",
+		 psp->state->sprite);
+#endif
+    sprdef = &sprites[psp->state->sprite];
+#ifdef RANGECHECK
+    if ( (psp->state->frame & FF_FRAMEMASK)  >= sprdef->numframes)
+	I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
+		 psp->state->sprite, psp->state->frame);
+#endif
+    sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
+
+    lump = sprframe->lump[0];
+    flip = (boolean)sprframe->flip[0];
+    
+    // calculate edges of the shape
+    tx = psp->sx-160*FRACUNIT;
+	
+    tx -= spriteoffset[lump];	
+    x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS;
+
+    // off the right side
+    if (x1 > viewwidth)
+	return;		
+
+    tx +=  spritewidth[lump];
+    x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
+
+    // off the left side
+    if (x2 < 0)
+	return;
+    
+    // store information in a vissprite
+    vis = &avis;
+    vis->mobjflags = 0;
+    vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2-(psp->sy-spritetopoffset[lump]);
+    vis->x1 = x1 < 0 ? 0 : x1;
+    vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;	
+    vis->scale = pspritescale<<detailshift;
+    
+    if (flip)
+    {
+	vis->xiscale = -pspriteiscale;
+	vis->startfrac = spritewidth[lump]-1;
+    }
+    else
+    {
+	vis->xiscale = pspriteiscale;
+	vis->startfrac = 0;
+    }
+    
+    if (vis->x1 > x1)
+	vis->startfrac += vis->xiscale*(vis->x1-x1);
+
+    vis->patch = lump;
+
+    if (viewplayer->powers[pw_invisibility] > 4*32
+	|| viewplayer->powers[pw_invisibility] & 8)
+    {
+	// shadow draw
+	vis->colormap = NULL;
+    }
+    else if (fixedcolormap)
+    {
+	// fixed color
+	vis->colormap = fixedcolormap;
+    }
+    else if (psp->state->frame & FF_FULLBRIGHT)
+    {
+	// full bright
+	vis->colormap = colormaps;
+    }
+    else
+    {
+	// local light
+	vis->colormap = spritelights[MAXLIGHTSCALE-1];
+    }
+	
+    R_DrawVisSprite (vis, vis->x1, vis->x2);
+}
+
+
+
+//
+// R_DrawPlayerSprites
+//
+void R_DrawPlayerSprites (void)
+{
+    int		i;
+    int		lightnum;
+    pspdef_t*	psp;
+    
+    // get light level
+    lightnum =
+	(viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) 
+	+extralight;
+
+    if (lightnum < 0)		
+	spritelights = scalelight[0];
+    else if (lightnum >= LIGHTLEVELS)
+	spritelights = scalelight[LIGHTLEVELS-1];
+    else
+	spritelights = scalelight[lightnum];
+    
+    // clip to screen bounds
+    mfloorclip = screenheightarray;
+    mceilingclip = negonearray;
+    
+    // add all active psprites
+    for (i=0, psp=viewplayer->psprites;
+	 i<NUMPSPRITES;
+	 i++,psp++)
+    {
+	if (psp->state)
+	    R_DrawPSprite (psp);
+    }
+}
+
+
+
+
+//
+// R_SortVisSprites
+//
+vissprite_t	vsprsortedhead;
+
+
+void R_SortVisSprites (void)
+{
+    int			i;
+    int			count;
+    vissprite_t*	ds;
+    vissprite_t*	best;
+    vissprite_t		unsorted;
+    fixed_t		bestscale;
+
+    count = vissprite_p - vissprites;
+	
+    unsorted.next = unsorted.prev = &unsorted;
+
+    if (!count)
+	return;
+		
+    for (ds=vissprites ; ds<vissprite_p ; ds++)
+    {
+	ds->next = ds+1;
+	ds->prev = ds-1;
+    }
+    
+    vissprites[0].prev = &unsorted;
+    unsorted.next = &vissprites[0];
+    (vissprite_p-1)->next = &unsorted;
+    unsorted.prev = vissprite_p-1;
+    
+    // pull the vissprites out by scale
+    vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
+    for (best=nil,i=0 ; i<count ; i++)
+    {
+	bestscale = MAXINT;
+	for (ds=unsorted.next ; ds!= &unsorted ; ds=ds->next)
+	{
+	    if (ds->scale < bestscale)
+	    {
+		bestscale = ds->scale;
+		best = ds;
+	    }
+	}
+	best->next->prev = best->prev;
+	best->prev->next = best->next;
+	best->next = &vsprsortedhead;
+	best->prev = vsprsortedhead.prev;
+	vsprsortedhead.prev->next = best;
+	vsprsortedhead.prev = best;
+    }
+}
+
+
+
+//
+// R_DrawSprite
+//
+void R_DrawSprite (vissprite_t* spr)
+{
+    drawseg_t*		ds;
+    short		clipbot[SCREENWIDTH];
+    short		cliptop[SCREENWIDTH];
+    int			x;
+    int			r1;
+    int			r2;
+    fixed_t		scale;
+    fixed_t		lowscale;
+    int			silhouette;
+		
+    for (x = spr->x1 ; x<=spr->x2 ; x++)
+	clipbot[x] = cliptop[x] = -2;
+    
+    // Scan drawsegs from end to start for obscuring segs.
+    // The first drawseg that has a greater scale
+    //  is the clip seg.
+    for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
+    {
+	// determine if the drawseg obscures the sprite
+	if (ds->x1 > spr->x2
+	    || ds->x2 < spr->x1
+	    || (!ds->silhouette
+		&& !ds->maskedtexturecol) )
+	{
+	    // does not cover sprite
+	    continue;
+	}
+			
+	r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
+	r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
+
+	if (ds->scale1 > ds->scale2)
+	{
+	    lowscale = ds->scale2;
+	    scale = ds->scale1;
+	}
+	else
+	{
+	    lowscale = ds->scale1;
+	    scale = ds->scale2;
+	}
+		
+	if (scale < spr->scale
+	    || ( lowscale < spr->scale
+		 && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline) ) )
+	{
+	    // masked mid texture?
+	    if (ds->maskedtexturecol)	
+		R_RenderMaskedSegRange (ds, r1, r2);
+	    // seg is behind sprite
+	    continue;			
+	}
+
+	
+	// clip this piece of the sprite
+	silhouette = ds->silhouette;
+	
+	if (spr->gz >= ds->bsilheight)
+	    silhouette &= ~SIL_BOTTOM;
+
+	if (spr->gzt <= ds->tsilheight)
+	    silhouette &= ~SIL_TOP;
+			
+	if (silhouette == 1)
+	{
+	    // bottom sil
+	    for (x=r1 ; x<=r2 ; x++)
+		if (clipbot[x] == -2)
+		    clipbot[x] = ds->sprbottomclip[x];
+	}
+	else if (silhouette == 2)
+	{
+	    // top sil
+	    for (x=r1 ; x<=r2 ; x++)
+		if (cliptop[x] == -2)
+		    cliptop[x] = ds->sprtopclip[x];
+	}
+	else if (silhouette == 3)
+	{
+	    // both
+	    for (x=r1 ; x<=r2 ; x++)
+	    {
+		if (clipbot[x] == -2)
+		    clipbot[x] = ds->sprbottomclip[x];
+		if (cliptop[x] == -2)
+		    cliptop[x] = ds->sprtopclip[x];
+	    }
+	}
+		
+    }
+    
+    // all clipping has been performed, so draw the sprite
+
+    // check for unclipped columns
+    for (x = spr->x1 ; x<=spr->x2 ; x++)
+    {
+	if (clipbot[x] == -2)		
+	    clipbot[x] = viewheight;
+
+	if (cliptop[x] == -2)
+	    cliptop[x] = -1;
+    }
+		
+    mfloorclip = clipbot;
+    mceilingclip = cliptop;
+    R_DrawVisSprite (spr, spr->x1, spr->x2);
+}
+
+
+
+
+//
+// R_DrawMasked
+//
+void R_DrawMasked (void)
+{
+    vissprite_t*	spr;
+    drawseg_t*		ds;
+	
+    R_SortVisSprites ();
+
+    if (vissprite_p > vissprites)
+    {
+	// draw all vissprites back to front
+	for (spr = vsprsortedhead.next ;
+	     spr != &vsprsortedhead ;
+	     spr=spr->next)
+	{
+	    
+	    R_DrawSprite (spr);
+	}
+    }
+    
+    // render any remaining masked mid textures
+    for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
+	if (ds->maskedtexturecol)
+	    R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
+    
+    // draw the psprites on top of everything
+    //  but does not draw on side views
+    if (!viewangleoffset)		
+	R_DrawPlayerSprites ();
+}
+
+
+
--