Subversion Repositories eduke32

Rev

Rev 870 | Blame | Compare with Previous | Last modification | View Log | RSS feed

// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
//
// This file has been modified from Ken Silverman's original release
// by Jonathon Fowler (jonof@edgenetwk.com)


//#define POLYMOST
//#define SUPERBUILD
#define ENGINE

#include "compat.h"
#include "build.h"
#include "pragmas.h"
#include "cache1d.h"
#include "a.h"
#include "osd.h"
#include "crc32.h"

#include "baselayer.h"

#ifdef POLYMOST
# ifdef _WIN32
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
# endif
# ifdef USE_OPENGL
#  include "glbuild.h"
#  ifdef POLYMER
#  include "polymer.h"
# endif
#endif
#endif

#include <math.h>

#define MAXCLIPNUM 1024
#define MAXPERMS 512
#define MAXTILEFILES 256
#define MAXYSAVES ((MAXXDIM*MAXSPRITES)>>7)
#define MAXNODESPERLINE 42   //Warning: This depends on MAXYSAVES & MAXYDIM!
#define MAXCLIPDIST 1024


void *kmalloc(bsize_t size) { return(Bmalloc(size)); }
#define kkmalloc kmalloc

void kfree(void *buffer) { Bfree(buffer); }
#define kkfree kfree

#ifdef SUPERBUILD
void loadvoxel(int voxindex) { voxindex=0; }
int tiletovox[MAXTILES];
int usevoxels = 1;
#define kloadvoxel loadvoxel

int novoxmips = 0;
int editorgridextent = 131072;

//These variables need to be copied into BUILD
#define MAXXSIZ 256
#define MAXYSIZ 256
#define MAXZSIZ 255
#define MAXVOXMIPS 5
intptr_t voxoff[MAXVOXELS][MAXVOXMIPS]; char voxlock[MAXVOXELS][MAXVOXMIPS];
int voxscale[MAXVOXELS];

static int ggxinc[MAXXSIZ+1], ggyinc[MAXXSIZ+1];
static int lowrecip[1024], nytooclose, nytoofar;
static unsigned int distrecip[65536];
#endif

static intptr_t *lookups = NULL;
static char lookupsalloctype = 255;
int dommxoverlay = 1, beforedrawrooms = 1, indrawroomsandmasks = 0;

static int oxdimen = -1, oviewingrange = -1, oxyaspect = -1;

int curbrightness = 0, gammabrightness = 0;

float vid_gamma = DEFAULT_GAMMA;
float vid_contrast = DEFAULT_CONTRAST;
float vid_brightness = DEFAULT_BRIGHTNESS;

//Textured Map variables
static char globalpolytype;
static short *dotp1[MAXYDIM], *dotp2[MAXYDIM];

static unsigned char tempbuf[MAXWALLS];

int ebpbak, espbak;
int slopalookup[16384];    // was 2048
#if defined(USE_OPENGL)
static palette_t palookupfog[MAXPALOOKUPS];
#endif

static char permanentlock = 255;
int artversion, mapversion=7L; // JBF 20040211: default mapversion to 7
void *pic = NULL;
char picsiz[MAXTILES], tilefilenum[MAXTILES];
int lastageclock;
int tilefileoffs[MAXTILES];

int artsize = 0, cachesize = 0;

static short radarang[1280], radarang2[MAXXDIM];
static unsigned short sqrtable[4096], shlookup[4096+256];
char pow2char[8] = {1,2,4,8,16,32,64,128};
int pow2long[32] =
{
    1L,2L,4L,8L,
    16L,32L,64L,128L,
    256L,512L,1024L,2048L,
    4096L,8192L,16384L,32768L,
    65536L,131072L,262144L,524288L,
    1048576L,2097152L,4194304L,8388608L,
    16777216L,33554432L,67108864L,134217728L,
    268435456L,536870912L,1073741824L,2147483647L
};
int reciptable[2048], fpuasm;

char britable[16][256]; // JBF 20040207: full 8bit precision
//char textfont[1024], smalltextfont[1024];
#include "textfont.c"
#include "smalltextfont.c"

static char kensmessage[128];
char *engineerrstr = "No error";


#if defined(__WATCOMC__) && !defined(NOASM)

//
// Watcom Inline Assembly Routines
//

#pragma aux nsqrtasm =\
    "test eax, 0xff000000",\
    "mov ebx, eax",\
    "jnz short over24",\
    "shr ebx, 12",\
    "mov cx, word ptr shlookup[ebx*2]",\
    "jmp short under24",\
    "over24: shr ebx, 24",\
    "mov cx, word ptr shlookup[ebx*2+8192]",\
    "under24: shr eax, cl",\
    "mov cl, ch",\
    "mov ax, word ptr sqrtable[eax*2]",\
    "shr eax, cl",\
    parm nomemory [eax]\
    modify exact [eax ebx ecx]

unsigned int nsqrtasm(unsigned int);

#pragma aux msqrtasm =\
    "mov eax, 0x40000000",\
    "mov ebx, 0x20000000",\
    "begit: cmp ecx, eax",\
    "jl skip",\
    "sub ecx, eax",\
    "lea eax, [eax+ebx*4]",\
    "skip: sub eax, ebx",\
    "shr eax, 1",\
    "shr ebx, 2",\
    "jnz begit",\
    "cmp ecx, eax",\
    "sbb eax, -1",\
    "shr eax, 1",\
    parm nomemory [ecx]\
    modify exact [eax ebx ecx]

int msqrtasm(unsigned int);

//0x007ff000 is (11<<13), 0x3f800000 is (127<<23)
#pragma aux krecipasm =\
    "mov fpuasm, eax",\
    "fild dword ptr fpuasm",\
    "add eax, eax",\
    "fstp dword ptr fpuasm",\
    "sbb ebx, ebx",\
    "mov eax, fpuasm",\
    "mov ecx, eax",\
    "and eax, 0x007ff000",\
    "shr eax, 10",\
    "sub ecx, 0x3f800000",\
    "shr ecx, 23",\
    "mov eax, dword ptr reciptable[eax]",\
    "sar eax, cl",\
    "xor eax, ebx",\
    parm [eax]\
    modify exact [eax ebx ecx]

int krecipasm(int);

#pragma aux setgotpic =\
    "mov ebx, eax",\
    "cmp byte ptr walock[eax], 200",\
    "jae skipit",\
    "mov byte ptr walock[eax], 199",\
    "skipit: shr eax, 3",\
    "and ebx, 7",\
    "mov dl, byte ptr gotpic[eax]",\
    "mov bl, byte ptr pow2char[ebx]",\
    "or dl, bl",\
    "mov byte ptr gotpic[eax], dl",\
    parm [eax]\
    modify exact [eax ebx ecx edx]

void setgotpic(int);

#pragma aux getclipmask =\
    "sar eax, 31",\
    "add ebx, ebx",\
    "adc eax, eax",\
    "add ecx, ecx",\
    "adc eax, eax",\
    "add edx, edx",\
    "adc eax, eax",\
    "mov ebx, eax",\
    "shl ebx, 4",\
    "or al, 0xf0",\
    "xor eax, ebx",\
    parm [eax][ebx][ecx][edx]\
    modify exact [eax ebx ecx edx]

int getclipmask(int,int,int,int);

#pragma aux getkensmessagecrc =\
    "xor eax, eax",\
    "mov ecx, 32",\
    "beg: mov edx, dword ptr [ebx+ecx*4-4]",\
    "ror edx, cl",\
    "adc eax, edx",\
    "bswap eax",\
    "loop short beg",\
    parm [ebx]\
    modify exact [eax ebx ecx edx]

int getkensmessagecrc(int);

#elif defined(_MSC_VER) && !defined(NOASM)      // __WATCOMC__

//
// Microsoft C Inline Assembly Routines
//

static inline int nsqrtasm(int a)
{
    _asm
    {
        push ebx
        mov eax, a
        test eax, 0xff000000
        mov ebx, eax
        jnz short over24
        shr ebx, 12
        mov cx, word ptr shlookup[ebx*2]
        jmp short under24
over24:
        shr ebx, 24
        mov cx, word ptr shlookup[ebx*2+8192]
under24:
        shr eax, cl
        mov cl, ch
        mov ax, word ptr sqrtable[eax*2]
        shr eax, cl
        pop ebx
    }
}

static inline int msqrtasm(int c)
{
    _asm
    {
        push ebx
        mov ecx, c
        mov eax, 0x40000000
        mov ebx, 0x20000000
begit:
        cmp ecx, eax
        jl skip
        sub ecx, eax
        lea eax, [eax+ebx*4]
skip:
        sub eax, ebx
        shr eax, 1
        shr ebx, 2
        jnz begit
        cmp ecx, eax
        sbb eax, -1
        shr eax, 1
        pop ebx
    }
}

//0x007ff000 is (11<<13), 0x3f800000 is (127<<23)
static inline int krecipasm(int a)
{
    _asm
    {
        push ebx
        mov eax, a
        mov fpuasm, eax
        fild dword ptr fpuasm
        add eax, eax
        fstp dword ptr fpuasm
        sbb ebx, ebx
        mov eax, fpuasm
        mov ecx, eax
        and eax, 0x007ff000
        shr eax, 10
        sub ecx, 0x3f800000
        shr ecx, 23
        mov eax, dword ptr reciptable[eax]
        sar eax, cl
        xor eax, ebx
        pop ebx
    }
}

static inline void setgotpic(int a)
{
    _asm
    {
        push ebx
        mov eax, a
        mov ebx, eax
        cmp byte ptr walock[eax], 200
        jae skipit
        mov byte ptr walock[eax], 199
skipit:
        shr eax, 3
        and ebx, 7
        mov dl, byte ptr gotpic[eax]
        mov bl, byte ptr pow2char[ebx]
        or dl, bl
        mov byte ptr gotpic[eax], dl
        pop ebx
    }
}

static inline int getclipmask(int a, int b, int c, int d)
{
    _asm
    {
        push ebx
        mov eax, a
        mov ebx, b
        mov ecx, c
        mov edx, d
        sar eax, 31
        add ebx, ebx
        adc eax, eax
        add ecx, ecx
        adc eax, eax
        add edx, edx
        adc eax, eax
        mov ebx, eax
        shl ebx, 4
        or al, 0xf0
        xor eax, ebx
        pop ebx
    }
}

static inline int getkensmessagecrc(void *b)
{
    _asm
    {
        push ebx
        mov ebx, b
        xor eax, eax
        mov ecx, 32
beg:
        mov edx, dword ptr [ebx+ecx*4-4]
        ror edx, cl
        adc eax, edx
        bswap eax
        loop short beg
        pop ebx
    }
}

#elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM) // _MSC_VER

//
// GCC "Inline" Assembly Routines
//

#define nsqrtasm(a) \
    ({ int __r, __a=(a); \
       __asm__ __volatile__ ( \
        "testl $0xff000000, %%eax\n\t" \
        "movl %%eax, %%ebx\n\t" \
        "jnz 0f\n\t" \
        "shrl $12, %%ebx\n\t" \
        "movw "ASMSYM("shlookup")"(,%%ebx,2), %%cx\n\t" \
        "jmp 1f\n\t" \
        "0:\n\t" \
        "shrl $24, %%ebx\n\t" \
        "movw ("ASMSYM("shlookup")"+8192)(,%%ebx,2), %%cx\n\t" \
        "1:\n\t" \
        "shrl %%cl, %%eax\n\t" \
        "movb %%ch, %%cl\n\t" \
        "movw "ASMSYM("sqrtable")"(,%%eax,2), %%ax\n\t" \
        "shrl %%cl, %%eax" \
        : "=a" (__r) : "a" (__a) : "ebx", "ecx", "cc"); \
     __r; })


// edx is blown by this code somehow?!
#define msqrtasm(c) \
    ({ int __r, __c=(c); \
       __asm__ __volatile__ ( \
        "movl $0x40000000, %%eax\n\t" \
        "movl $0x20000000, %%ebx\n\t" \
        "0:\n\t" \
        "cmpl %%eax, %%ecx\n\t" \
        "jl 1f\n\t" \
        "subl %%eax, %%ecx\n\t" \
        "leal (%%eax,%%ebx,4), %%eax\n\t" \
        "1:\n\t" \
        "subl %%ebx, %%eax\n\t" \
        "shrl $1, %%eax\n\t" \
        "shrl $2, %%ebx\n\t" \
        "jnz 0b\n\t" \
        "cmpl %%eax, %%ecx\n\t" \
        "sbbl $-1, %%eax\n\t" \
        "shrl $1, %%eax" \
        : "=a" (__r) : "c" (__c) : "edx","ebx", "cc"); \
     __r; })


#define setgotpic(a) \
    ({ int __a=(a); \
       __asm__ __volatile__ ( \
        "movl %%eax, %%ebx\n\t" \
        "cmpb $200, "ASMSYM("walock")"(%%eax)\n\t" \
        "jae 0f\n\t" \
        "movb $199, "ASMSYM("walock")"(%%eax)\n\t" \
        "0:\n\t" \
        "shrl $3, %%eax\n\t" \
        "andl $7, %%ebx\n\t" \
        "movb "ASMSYM("gotpic")"(%%eax), %%dl\n\t" \
        "movb "ASMSYM("pow2char")"(%%ebx), %%bl\n\t" \
        "orb %%bl, %%dl\n\t" \
        "movb %%dl, "ASMSYM("gotpic")"(%%eax)" \
        : "=a" (__a) : "a" (__a) \
        : "ebx", "edx", "memory", "cc"); \
     __a; })


#define krecipasm(a) \
    ({ int __a=(a); \
       __asm__ __volatile__ ( \
            "movl %%eax, ("ASMSYM("fpuasm")"); fildl ("ASMSYM("fpuasm")"); " \
            "addl %%eax, %%eax; fstps ("ASMSYM("fpuasm")"); sbbl %%ebx, %%ebx; " \
            "movl ("ASMSYM("fpuasm")"), %%eax; movl %%eax, %%ecx; " \
            "andl $0x007ff000, %%eax; shrl $10, %%eax; subl $0x3f800000, %%ecx; " \
            "shrl $23, %%ecx; movl "ASMSYM("reciptable")"(%%eax), %%eax; " \
            "sarl %%cl, %%eax; xorl %%ebx, %%eax" \
        : "=a" (__a) : "a" (__a) : "ebx", "ecx", "memory", "cc"); \
     __a; })


#define getclipmask(a,b,c,d) \
    ({ int __a=(a), __b=(b), __c=(c), __d=(d); \
       __asm__ __volatile__ ("sarl $31, %%eax; addl %%ebx, %%ebx; adcl %%eax, %%eax; " \
                "addl %%ecx, %%ecx; adcl %%eax, %%eax; addl %%edx, %%edx; " \
                "adcl %%eax, %%eax; movl %%eax, %%ebx; shl $4, %%ebx; " \
                "orb $0xf0, %%al; xorl %%ebx, %%eax" \
        : "=a" (__a), "=b" (__b), "=c" (__c), "=d" (__d) \
        : "a" (__a), "b" (__b), "c" (__c), "d" (__d) : "cc"); \
     __a; })



#define getkensmessagecrc(b) \
    ({ int __a, __b=(b); \
       __asm__ __volatile__ ( \
        "xorl %%eax, %%eax\n\t" \
        "movl $32, %%ecx\n\t" \
        "0:\n\t" \
        "movl -4(%%ebx,%%ecx,4), %%edx\n\t" \
        "rorl %%cl, %%edx\n\t" \
        "adcl %%edx, %%eax\n\t" \
        "bswapl %%eax\n\t" \
        "loop 0b" \
        : "=a" (__a) : "b" (__b) : "ecx", "edx" \
     __a; })


#else   // __GNUC__ && __i386__

static inline unsigned int nsqrtasm(unsigned int a)
{
    // JBF 20030901: This was a damn lot simpler to reverse engineer than
    // msqrtasm was. Really, it was just like simplifying an algebra equation.
    unsigned short c;

    if (a & 0xff000000)                         // test eax, 0xff000000  /  jnz short over24
    {
        c = shlookup[(a >> 24) + 4096]; // mov ebx, eax
        // over24: shr ebx, 24
        // mov cx, word ptr shlookup[ebx*2+8192]
    }
    else
    {
        c = shlookup[a >> 12];          // mov ebx, eax
        // shr ebx, 12
        // mov cx, word ptr shlookup[ebx*2]
        // jmp short under24
    }
    a >>= c&0xff;                               // under24: shr eax, cl
    a = (a&0xffff0000)|(sqrtable[a]);   // mov ax, word ptr sqrtable[eax*2]
    a >>= ((c&0xff00) >> 8);            // mov cl, ch
    // shr eax, cl
    return a;
}

static inline int msqrtasm(unsigned int c)
{
    unsigned int a,b;

    a = 0x40000000l;            // mov eax, 0x40000000
    b = 0x20000000l;            // mov ebx, 0x20000000
    do                                  // begit:
    {
        if (c >= a)             // cmp ecx, eax  /  jl skip
        {
            c -= a;             // sub ecx, eax
            a += b*4;   // lea eax, [eax+ebx*4]
        }                       // skip:
        a -= b;                 // sub eax, ebx
        a >>= 1;                // shr eax, 1
        b >>= 2;                // shr ebx, 2
    }
    while (b);                  // jnz begit
    if (c >= a)                 // cmp ecx, eax
        a++;                    // sbb eax, -1
    a >>= 1;                    // shr eax, 1
    return a;
}

static inline void setgotpic(int tilenume)
{
    if (walock[tilenume] < 200) walock[tilenume] = 199;
    gotpic[tilenume>>3] |= pow2char[tilenume&7];
}

static inline int krecipasm(int i)
{
    // Ken did this
    float f = (float)i; i = *(int *)&f;
    return((reciptable[(i>>12)&2047]>>(((i-0x3f800000)>>23)&31))^(i>>31));
}


static inline int getclipmask(int a, int b, int c, int d)
{
    // Ken did this
    d = ((a<0)*8) + ((b<0)*4) + ((c<0)*2) + (d<0);
    return(((d<<4)^0xf0)|d);
}

inline int getkensmessagecrc(int b)
{
    return 0x56c764d4l;
    b=b;
}

#endif


static int xb1[MAXWALLSB], yb1[MAXWALLSB], xb2[MAXWALLSB], yb2[MAXWALLSB];
static int rx1[MAXWALLSB], ry1[MAXWALLSB], rx2[MAXWALLSB], ry2[MAXWALLSB];
static short p2[MAXWALLSB], thesector[MAXWALLSB];
short thewall[MAXWALLSB];

static short bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB];

static short smost[MAXYSAVES], smostcnt;
static short smoststart[MAXWALLSB];
static char smostwalltype[MAXWALLSB];
static int smostwall[MAXWALLSB], smostwallcnt = -1L;

short maskwall[MAXWALLSB], maskwallcnt;
static int spritesx[MAXSPRITESONSCREEN];
static int spritesy[MAXSPRITESONSCREEN+1];
static int spritesz[MAXSPRITESONSCREEN];
spritetype *tspriteptr[MAXSPRITESONSCREEN];

short umost[MAXXDIM], dmost[MAXXDIM];
static short bakumost[MAXXDIM], bakdmost[MAXXDIM];
short uplc[MAXXDIM], dplc[MAXXDIM];
static short uwall[MAXXDIM], dwall[MAXXDIM];
static int swplc[MAXXDIM], lplc[MAXXDIM];
static int swall[MAXXDIM], lwall[MAXXDIM+4];
int xdimen = -1, xdimenrecip, halfxdimen, xdimenscale, xdimscale;
int wx1, wy1, wx2, wy2, ydimen;
intptr_t /*viewoffset,*/ frameoffset;

static int nrx1[8], nry1[8], nrx2[8], nry2[8]; // JBF 20031206: Thanks Ken

static int rxi[8], ryi[8], rzi[8], rxi2[8], ryi2[8], rzi2[8];
static int xsi[8], ysi[8], horizycent;
static intptr_t *horizlookup=0, *horizlookup2=0;

int globalposx, globalposy, globalposz, globalhoriz;
short globalang, globalcursectnum;
int globalpal, cosglobalang, singlobalang;
int cosviewingrangeglobalang, sinviewingrangeglobalang;
char *globalpalwritten;
int globaluclip, globaldclip, globvis;
int globalvisibility, globalhisibility, globalpisibility, globalcisibility;
char globparaceilclip, globparaflorclip;

int xyaspect, viewingrangerecip;

intptr_t asm1, asm2, asm3, asm4;
int vplce[4], vince[4], palookupoffse[4], bufplce[4];
char globalxshift, globalyshift;
int globalxpanning, globalypanning, globalshade;
short globalpicnum, globalshiftval;
int globalzd, globalyscale, globalorientation;
intptr_t globalbufplc;
int globalx1, globaly1, globalx2, globaly2, globalx3, globaly3, globalzx;
int globalx, globaly, globalz;

static short sectorborder[256], sectorbordercnt;
static char tablesloaded = 0;
int pageoffset, ydim16, qsetmode = 0;
int startposx, startposy, startposz;
short startang, startsectnum;
short pointhighlight, linehighlight, highlightcnt;
static int lastx[MAXYDIM];
char *transluc = NULL, paletteloaded = 0;

int halfxdim16, midydim16;

#define FASTPALGRIDSIZ 8
static int rdist[129], gdist[129], bdist[129];
static char colhere[((FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2))>>3];
static char colhead[(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)];
static int colnext[256];
static char coldist[8] = {0,1,2,3,4,3,2,1};
static int colscan[27];

static short clipnum, hitwalls[4];
int hitscangoalx = (1<<29)-1, hitscangoaly = (1<<29)-1;
#ifdef POLYMOST
static int hitallsprites = 0;
#endif

typedef struct { int x1, y1, x2, y2; } linetype;
static linetype clipit[MAXCLIPNUM];
static short clipsectorlist[MAXCLIPNUM], clipsectnum;
static short clipobjectval[MAXCLIPNUM];

typedef struct
{
    int sx, sy, z;
    short a, picnum;
    signed char dashade;
    char dapalnum, dastat, pagesleft;
    int cx1, cy1, cx2, cy2;
    int uniqid;    //JF extension
} permfifotype;
static permfifotype permfifo[MAXPERMS];
static int permhead = 0, permtail = 0;

short numscans, numhits, numbunches;
short capturecount = 0;

char vgapal16[4*256] =
{
    00,00,00,00, 42,00,00,00, 00,42,00,00, 42,42,00,00, 00,00,42,00,
    42,00,42,00, 00,21,42,00, 42,42,42,00, 21,21,21,00, 63,21,21,00,
    21,63,21,00, 63,63,21,00, 21,21,63,00, 63,21,63,00, 21,63,63,00,
    63,63,63,00
};

short editstatus = 0;
short searchit;
int searchx = -1, searchy;                          //search input
short searchsector, searchwall, searchstat;     //search output
double msens = 1.0;

static char artfilename[20];
static int numtilefiles, artfil = -1, artfilnum, artfilplc;

static char inpreparemirror = 0;
static int mirrorsx1, mirrorsy1, mirrorsx2, mirrorsy2;

static int setviewcnt = 0; // interface layers use this now
static int bakframeplace[4], bakxsiz[4], bakysiz[4];
static int bakwindowx1[4], bakwindowy1[4];
static int bakwindowx2[4], bakwindowy2[4];
#ifdef POLYMOST
static int bakrendmode,baktile;
#endif

int totalclocklock;

char apptitle[256] = "Build Engine";
palette_t curpalette[256];                      // the current palette, unadjusted for brightness or tint
palette_t curpalettefaded[256];         // the current palette, adjusted for brightness and tint (ie. what gets sent to the card)
palette_t palfadergb = { 0,0,0,0 };
char palfadedelta = 0;



//
// Internal Engine Functions
//
//int cacheresets = 0,cacheinvalidates = 0;


//============================================================================= //POLYMOST BEGINS
#ifdef POLYMOST
static void scansector(short sectnum);
#include "polymost.h"
#include "hightile.c"
#include "polymost.c"
#else
void hicsetpalettetint(int palnum, unsigned char r, unsigned char g, unsigned char b, unsigned char effect) { }
int hicsetsubsttex(int picnum, int palnum, char *filen, float alphacut, float xscale, float yscale, char flags) { return 0; }
int hicsetskybox(int picnum, int palnum, char *faces[6]) { return 0; }
int hicclearsubst(int picnum, int palnum) { return 0; }
int polymost_drawtilescreen(int tilex, int tiley, int wallnum, int dimen, int tilezoom) { return -1; }
#endif
//============================================================================= //POLYMOST ENDS

//
// getpalookup (internal)
//
static inline int getpalookup(int davis, int dashade)
{
    return(min(max(dashade+(davis>>8),0),numpalookups-1));
}


//
// scansector (internal)
//
static void scansector(short sectnum)
{
    walltype *wal, *wal2;
    spritetype *spr;
    int xs, ys, x1, y1, x2, y2, xp1, yp1, xp2=0, yp2=0, tempint;
    short z, zz, startwall, endwall, numscansbefore, scanfirst, bunchfrst;
    short nextsectnum;

    if (sectnum < 0) return;

    if (automapping) show2dsector[sectnum>>3] |= pow2char[sectnum&7];

    sectorborder[0] = sectnum, sectorbordercnt = 1;
    do
    {
        sectnum = sectorborder[--sectorbordercnt];

        for (z=headspritesect[sectnum];z>=0;z=nextspritesect[z])
        {
            spr = &sprite[z];
            if ((((spr->cstat&0x8000) == 0) || (showinvisibility)) &&
                    (spr->xrepeat > 0) && (spr->yrepeat > 0) &&
                    (spritesortcnt < MAXSPRITESONSCREEN))
            {
                xs = spr->x-globalposx; ys = spr->y-globalposy;
                if ((spr->cstat&48) || (xs*cosglobalang+ys*singlobalang > 0))
                {
                    copybufbyte(spr,&tsprite[spritesortcnt],sizeof(spritetype));
                    spriteext[z].tspr = (spritetype *)&tsprite[spritesortcnt];
                    tsprite[spritesortcnt++].owner = z;
                }
            }
        }

        gotsector[sectnum>>3] |= pow2char[sectnum&7];

        bunchfrst = numbunches;
        numscansbefore = numscans;

        startwall = sector[sectnum].wallptr;
        endwall = startwall + sector[sectnum].wallnum;
        scanfirst = numscans;
        for (z=startwall,wal=&wall[z];z<endwall;z++,wal++)
        {
            nextsectnum = wal->nextsector;

            wal2 = &wall[wal->point2];
            x1 = wal->x-globalposx; y1 = wal->y-globalposy;
            x2 = wal2->x-globalposx; y2 = wal2->y-globalposy;

            if ((nextsectnum >= 0) && ((wal->cstat&32) == 0))
                if ((gotsector[nextsectnum>>3]&pow2char[nextsectnum&7]) == 0)
                {
                    tempint = x1*y2-x2*y1;
                    if (((unsigned)tempint+262144) < 524288)
                        if (mulscale5(tempint,tempint) <= (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
                            sectorborder[sectorbordercnt++] = nextsectnum;
                }

            if ((z == startwall) || (wall[z-1].point2 != z))
            {
                xp1 = dmulscale6(y1,cosglobalang,-x1,singlobalang);
                yp1 = dmulscale6(x1,cosviewingrangeglobalang,y1,sinviewingrangeglobalang);
            }
            else
            {
                xp1 = xp2;
                yp1 = yp2;
            }
            xp2 = dmulscale6(y2,cosglobalang,-x2,singlobalang);
            yp2 = dmulscale6(x2,cosviewingrangeglobalang,y2,sinviewingrangeglobalang);
            if ((yp1 < 256) && (yp2 < 256)) goto skipitaddwall;

            //If wall's NOT facing you
            if (dmulscale32(xp1,yp2,-xp2,yp1) >= 0) goto skipitaddwall;

            if (xp1 >= -yp1)
            {
                if ((xp1 > yp1) || (yp1 == 0)) goto skipitaddwall;
                xb1[numscans] = halfxdimen + scale(xp1,halfxdimen,yp1);
                if (xp1 >= 0) xb1[numscans]++;   //Fix for SIGNED divide
                if (xb1[numscans] >= xdimen) xb1[numscans] = xdimen-1;
                yb1[numscans] = yp1;
            }
            else
            {
                if (xp2 < -yp2) goto skipitaddwall;
                xb1[numscans] = 0;
                tempint = yp1-yp2+xp1-xp2;
                if (tempint == 0) goto skipitaddwall;
                yb1[numscans] = yp1 + scale(yp2-yp1,xp1+yp1,tempint);
            }
            if (yb1[numscans] < 256) goto skipitaddwall;

            if (xp2 <= yp2)
            {
                if ((xp2 < -yp2) || (yp2 == 0)) goto skipitaddwall;
                xb2[numscans] = halfxdimen + scale(xp2,halfxdimen,yp2) - 1;
                if (xp2 >= 0) xb2[numscans]++;   //Fix for SIGNED divide
                if (xb2[numscans] >= xdimen) xb2[numscans] = xdimen-1;
                yb2[numscans] = yp2;
            }
            else
            {
                if (xp1 > yp1) goto skipitaddwall;
                xb2[numscans] = xdimen-1;
                tempint = xp2-xp1+yp1-yp2;
                if (tempint == 0) goto skipitaddwall;
                yb2[numscans] = yp1 + scale(yp2-yp1,yp1-xp1,tempint);
            }
            if ((yb2[numscans] < 256) || (xb1[numscans] > xb2[numscans])) goto skipitaddwall;

            //Made it all the way!
            thesector[numscans] = sectnum; thewall[numscans] = z;
            rx1[numscans] = xp1; ry1[numscans] = yp1;
            rx2[numscans] = xp2; ry2[numscans] = yp2;
            p2[numscans] = numscans+1;
            numscans++;
skipitaddwall:

            if ((wall[z].point2 < z) && (scanfirst < numscans))
                p2[numscans-1] = scanfirst, scanfirst = numscans;
        }

        for (z=numscansbefore;z<numscans;z++)
            if ((wall[thewall[z]].point2 != thewall[p2[z]]) || (xb2[z] >= xb1[p2[z]]))
                bunchfirst[numbunches++] = p2[z], p2[z] = -1;

        for (z=bunchfrst;z<numbunches;z++)
        {
            for (zz=bunchfirst[z];p2[zz]>=0;zz=p2[zz]);
            bunchlast[z] = zz;
        }
    }
    while (sectorbordercnt > 0);
}


//
// maskwallscan (internal)
//
static void maskwallscan(int x1, int x2, short *uwal, short *dwal, int *swal, int *lwal)
{
    int i, x,/* startx,*/ xnice, ynice, fpalookup;
    intptr_t startx, p;
    int y1ve[4], y2ve[4], u4, d4, dax, z,/* p,*/ tsizx, tsizy;
    char bad;

    tsizx = tilesizx[globalpicnum];
    tsizy = tilesizy[globalpicnum];
    setgotpic(globalpicnum);
    if ((tsizx <= 0) || (tsizy <= 0)) return;
    if ((uwal[x1] > ydimen) && (uwal[x2] > ydimen)) return;
    if ((dwal[x1] < 0) && (dwal[x2] < 0)) return;

    if (waloff[globalpicnum] == 0) loadtile(globalpicnum);

    startx = x1;

    xnice = (pow2long[picsiz[globalpicnum]&15] == tsizx);
    if (xnice) tsizx = (tsizx-1);
    ynice = (pow2long[picsiz[globalpicnum]>>4] == tsizy);
    if (ynice) tsizy = (picsiz[globalpicnum]>>4);

    if (palookup[globalpal] == NULL)
        globalpal = 0;

    fpalookup = FP_OFF(palookup[globalpal]);

    setupmvlineasm(globalshiftval);

#ifndef ENGINE_USING_A_C

    x = startx;
    while ((startumost[x+windowx1] > startdmost[x+windowx1]) && (x <= x2)) x++;

    p = x+frameoffset;

    for (;(x<=x2)&&(p&3);x++,p++)
    {
        y1ve[0] = max(uwal[x],startumost[x+windowx1]-windowy1);
        y2ve[0] = min(dwal[x],startdmost[x+windowx1]-windowy1);
        if (y2ve[0] <= y1ve[0]) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);

        bufplce[0] = lwal[x] + globalxpanning;
        if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; }
        if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy;

        vince[0] = swal[x]*globalyscale;
        vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);

        mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],p+ylookup[y1ve[0]]);
    }
    for (;x<=x2-3;x+=4,p+=4)
    {
        bad = 0;
        for (z=3,dax=x+3;z>=0;z--,dax--)
        {
            y1ve[z] = max(uwal[dax],startumost[dax+windowx1]-windowy1);
            y2ve[z] = min(dwal[dax],startdmost[dax+windowx1]-windowy1)-1;
            if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }

            i = lwal[dax] + globalxpanning;
            if (i >= tsizx) { if (xnice == 0) i %= tsizx; else i &= tsizx; }
            if (ynice == 0) i *= tsizy; else i <<= tsizy;
            bufplce[z] = waloff[globalpicnum]+i;

            vince[z] = swal[dax]*globalyscale;
            vplce[z] = globalzd + vince[z]*(y1ve[z]-globalhoriz+1);
        }
        if (bad == 15) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);
        palookupoffse[3] = fpalookup+(getpalookup((int)mulscale16(swal[x+3],globvis),globalshade)<<8);

        if ((palookupoffse[0] == palookupoffse[3]) && ((bad&0x9) == 0))
        {
            palookupoffse[1] = palookupoffse[0];
            palookupoffse[2] = palookupoffse[0];
        }
        else
        {
            palookupoffse[1] = fpalookup+(getpalookup((int)mulscale16(swal[x+1],globvis),globalshade)<<8);
            palookupoffse[2] = fpalookup+(getpalookup((int)mulscale16(swal[x+2],globvis),globalshade)<<8);
        }

        u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3]));
        d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3]));

        if ((bad > 0) || (u4 >= d4))
        {
            if (!(bad&1)) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0);
            if (!(bad&2)) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1);
            if (!(bad&4)) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2);
            if (!(bad&8)) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3);
            continue;
        }

        if (u4 > y1ve[0]) vplce[0] = mvlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0);
        if (u4 > y1ve[1]) vplce[1] = mvlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1);
        if (u4 > y1ve[2]) vplce[2] = mvlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2);
        if (u4 > y1ve[3]) vplce[3] = mvlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3);

        if (d4 >= u4) mvlineasm4(d4-u4+1,ylookup[u4]+p);

        i = p+ylookup[d4+1];
        if (y2ve[0] > d4) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0);
        if (y2ve[1] > d4) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1);
        if (y2ve[2] > d4) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2);
        if (y2ve[3] > d4) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3);
    }
    for (;x<=x2;x++,p++)
    {
        y1ve[0] = max(uwal[x],startumost[x+windowx1]-windowy1);
        y2ve[0] = min(dwal[x],startdmost[x+windowx1]-windowy1);
        if (y2ve[0] <= y1ve[0]) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);

        bufplce[0] = lwal[x] + globalxpanning;
        if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; }
        if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy;

        vince[0] = swal[x]*globalyscale;
        vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);

        mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],p+ylookup[y1ve[0]]);
    }

#else   // ENGINE_USING_A_C

    p = startx+frameoffset;
    for (x=startx;x<=x2;x++,p++)
    {
        y1ve[0] = max(uwal[x],startumost[x+windowx1]-windowy1);
        y2ve[0] = min(dwal[x],startdmost[x+windowx1]-windowy1);
        if (y2ve[0] <= y1ve[0]) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);

        bufplce[0] = lwal[x] + globalxpanning;
        if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; }
        if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy;

        vince[0] = swal[x]*globalyscale;
        vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);

        mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],p+ylookup[y1ve[0]]);
    }

#endif

    faketimerhandler();
}


//
// wallfront (internal)
//
static int wallfront(int l1, int l2)
{
    walltype *wal;
    int x11, y11, x21, y21, x12, y12, x22, y22, dx, dy, t1, t2;

    wal = &wall[thewall[l1]]; x11 = wal->x; y11 = wal->y;
    wal = &wall[wal->point2]; x21 = wal->x; y21 = wal->y;
    wal = &wall[thewall[l2]]; x12 = wal->x; y12 = wal->y;
    wal = &wall[wal->point2]; x22 = wal->x; y22 = wal->y;

    dx = x21-x11; dy = y21-y11;
    t1 = dmulscale2(x12-x11,dy,-dx,y12-y11); //p1(l2) vs. l1
    t2 = dmulscale2(x22-x11,dy,-dx,y22-y11); //p2(l2) vs. l1
    if (t1 == 0) { t1 = t2; if (t1 == 0) return(-1); }
    if (t2 == 0) t2 = t1;
    if ((t1^t2) >= 0)
    {
        t2 = dmulscale2(globalposx-x11,dy,-dx,globalposy-y11); //pos vs. l1
        return((t2^t1) >= 0);
    }

    dx = x22-x12; dy = y22-y12;
    t1 = dmulscale2(x11-x12,dy,-dx,y11-y12); //p1(l1) vs. l2
    t2 = dmulscale2(x21-x12,dy,-dx,y21-y12); //p2(l1) vs. l2
    if (t1 == 0) { t1 = t2; if (t1 == 0) return(-1); }
    if (t2 == 0) t2 = t1;
    if ((t1^t2) >= 0)
    {
        t2 = dmulscale2(globalposx-x12,dy,-dx,globalposy-y12); //pos vs. l2
        return((t2^t1) < 0);
    }
    return(-2);
}


//
// spritewallfront (internal)
//
static int spritewallfront(spritetype *s, int w)
{
    walltype *wal;
    int x1, y1;

    wal = &wall[w]; x1 = wal->x; y1 = wal->y;
    wal = &wall[wal->point2];
    return (dmulscale32(wal->x-x1,s->y-y1,-(s->x-x1),wal->y-y1) >= 0);
}

//
//  spritebehindwall(internal)
//
#if 0
static int spriteobstructswall(spritetype *s, int w)
{
    walltype *wal;
    int x, y;
    int x1, y1;
    int x2, y2;
    double a1, b1, c1;
    double a2, b2, c2;
    double d1, d2;

    // wall line equation
    wal = &wall[w]; x1 = wal->x - globalposx; y1 = wal->y - globalposy;
    wal = &wall[wal->point2]; x2 = wal->x - globalposx; y2 = wal->y - globalposy;
    if ((x2 - x1) != 0)
        a1 = (float)(y2 - y1)/(x2 - x1);
    else
        a1 = 1e+37; // not infinite, but almost ;)
    b1 = -1;
    c1 = (y1 - (a1 * x1));

    // player to sprite line equation
    if ((s->x - globalposx) != 0)
        a2 = (float)(s->y - globalposy)/(s->x - globalposx);
    else
        a2 = 1e+37;
    b2 = -1;
    c2 = 0;

    // intersection point
    d1 = (float)(1) / (a1*b2 - a2*b1);
    x = ((b1*c2 - b2*c1) * d1);
    y = ((a2*c1 - a1*c2) * d1);

    // distance between the sprite and the player
    a1 = s->x - globalposx;
    b1 = s->y - globalposy;
    d1 = (a1 * a1 + b1 * b1);

    // distance between the intersection point and the player
    d2 = (x * x + y * y);

    // check if the sprite obstructs the wall
    if ((d1 < d2) && (min(x1, x2) <= x) && (x <= max(x1, x2)) && (min(y1, y2) <= y) && (y <= max(y1, y2)))
        return (1);
    else
        return (0);
}
#endif
//
// bunchfront (internal)
//
static int bunchfront(int b1, int b2)
{
    int x1b1, x2b1, x1b2, x2b2, b1f, b2f, i;

    b1f = bunchfirst[b1]; x1b1 = xb1[b1f]; x2b2 = xb2[bunchlast[b2]]+1;
    if (x1b1 >= x2b2) return(-1);
    b2f = bunchfirst[b2]; x1b2 = xb1[b2f]; x2b1 = xb2[bunchlast[b1]]+1;
    if (x1b2 >= x2b1) return(-1);

    if (x1b1 >= x1b2)
    {
        for (i=b2f;xb2[i]<x1b1;i=p2[i]);
        return(wallfront(b1f,i));
    }
    for (i=b1f;xb2[i]<x1b2;i=p2[i]);
    return(wallfront(i,b2f));
}


//
// hline (internal)
//
static void hline(int xr, int yp)
{
    int xl, r, s;

    xl = lastx[yp]; if (xl > xr) return;
    r = horizlookup2[yp-globalhoriz+horizycent];
    asm1 = globalx1*r;
    asm2 = globaly2*r;
    s = ((int)getpalookup((int)mulscale16(r,globvis),globalshade)<<8);

    hlineasm4(xr-xl,0,s,globalx2*r+globalypanning,globaly1*r+globalxpanning,
              ylookup[yp]+xr+frameoffset);
}


//
// slowhline (internal)
//
static void slowhline(int xr, int yp)
{
    int xl, r;

    xl = lastx[yp]; if (xl > xr) return;
    r = horizlookup2[yp-globalhoriz+horizycent];
    asm1 = globalx1*r;
    asm2 = globaly2*r;

    asm3 = (intptr_t)globalpalwritten + ((intptr_t)getpalookup((int)mulscale16(r,globvis),globalshade)<<8);
    if (!(globalorientation&256))
    {
        mhline(globalbufplc,globaly1*r+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L,
               globalx2*r+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset);
        return;
    }
    thline(globalbufplc,globaly1*r+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L,
           globalx2*r+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset);
}


//
// prepwall (internal)
//
static void prepwall(int z, walltype *wal)
{
    int i, l=0, ol=0, splc, sinc, x, topinc, top, botinc, bot, walxrepeat;

    walxrepeat = (wal->xrepeat<<3);

    //lwall calculation
    i = xb1[z]-halfxdimen;
    topinc = -(ry1[z]>>2);
    botinc = ((ry2[z]-ry1[z])>>8);
    top = mulscale5(rx1[z],xdimen)+mulscale2(topinc,i);
    bot = mulscale11(rx1[z]-rx2[z],xdimen)+mulscale2(botinc,i);

    splc = mulscale19(ry1[z],xdimscale);
    sinc = mulscale16(ry2[z]-ry1[z],xdimscale);

    x = xb1[z];
    if (bot != 0)
    {
        l = divscale12(top,bot);
        swall[x] = mulscale21(l,sinc)+splc;
        l *= walxrepeat;
        lwall[x] = (l>>18);
    }
    while (x+4 <= xb2[z])
    {
        top += topinc; bot += botinc;
        if (bot != 0)
        {
            ol = l; l = divscale12(top,bot);
            swall[x+4] = mulscale21(l,sinc)+splc;
            l *= walxrepeat;
            lwall[x+4] = (l>>18);
        }
        i = ((ol+l)>>1);
        lwall[x+2] = (i>>18);
        lwall[x+1] = ((ol+i)>>19);
        lwall[x+3] = ((l+i)>>19);
        swall[x+2] = ((swall[x]+swall[x+4])>>1);
        swall[x+1] = ((swall[x]+swall[x+2])>>1);
        swall[x+3] = ((swall[x+4]+swall[x+2])>>1);
        x += 4;
    }
    if (x+2 <= xb2[z])
    {
        top += (topinc>>1); bot += (botinc>>1);
        if (bot != 0)
        {
            ol = l; l = divscale12(top,bot);
            swall[x+2] = mulscale21(l,sinc)+splc;
            l *= walxrepeat;
            lwall[x+2] = (l>>18);
        }
        lwall[x+1] = ((l+ol)>>19);
        swall[x+1] = ((swall[x]+swall[x+2])>>1);
        x += 2;
    }
    if (x+1 <= xb2[z])
    {
        bot += (botinc>>2);
        if (bot != 0)
        {
            l = divscale12(top+(topinc>>2),bot);
            swall[x+1] = mulscale21(l,sinc)+splc;
            lwall[x+1] = mulscale18(l,walxrepeat);
        }
    }

    if (lwall[xb1[z]] < 0) lwall[xb1[z]] = 0;
    if ((lwall[xb2[z]] >= walxrepeat) && (walxrepeat)) lwall[xb2[z]] = walxrepeat-1;
    if (wal->cstat&8)
    {
        walxrepeat--;
        for (x=xb1[z];x<=xb2[z];x++) lwall[x] = walxrepeat-lwall[x];
    }
}


//
// animateoffs (internal)
//
int animateoffs(short tilenum, short fakevar)
{
    int i, k, offs;

    UNREFERENCED_PARAMETER(fakevar);

    offs = 0;
    i = (totalclocklock>>((picanm[tilenum]>>24)&15));
    if ((picanm[tilenum]&63) > 0)
    {
        switch (picanm[tilenum]&192)
        {
        case 64:
            k = (i%((picanm[tilenum]&63)<<1));
            if (k < (picanm[tilenum]&63))
                offs = k;
            else
                offs = (((picanm[tilenum]&63)<<1)-k);
            break;
        case 128:
            offs = (i%((picanm[tilenum]&63)+1));
            break;
        case 192:
            offs = -(i%((picanm[tilenum]&63)+1));
        }
    }
    return(offs);
}


//
// owallmost (internal)
//
static int owallmost(short *mostbuf, int w, int z)
{
    int bad, inty, xcross, y, yinc;
    int s1, s2, s3, s4, ix1, ix2, iy1, iy2, t;
    int i;

    z <<= 7;
    s1 = mulscale20(globaluclip,yb1[w]); s2 = mulscale20(globaluclip,yb2[w]);
    s3 = mulscale20(globaldclip,yb1[w]); s4 = mulscale20(globaldclip,yb2[w]);
    bad = (z<s1)+((z<s2)<<1)+((z>s3)<<2)+((z>s4)<<3);

    ix1 = xb1[w]; iy1 = yb1[w];
    ix2 = xb2[w]; iy2 = yb2[w];

    if ((bad&3) == 3)
    {
        //clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),0L);
        for (i=ix1; i<=ix2; i++) mostbuf[i] = 0;
        return(bad);
    }

    if ((bad&12) == 12)
    {
        //clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
        for (i=ix1; i<=ix2; i++) mostbuf[i] = ydimen;
        return(bad);
    }

    if (bad&3)
    {
        t = divscale30(z-s1,s2-s1);
        inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
        xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty);

        if ((bad&3) == 2)
        {
            if (xb1[w] <= xcross) { iy2 = inty; ix2 = xcross; }
            //clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),0L);
            for (i=xcross+1; i<=xb2[w]; i++) mostbuf[i] = 0;
        }
        else
        {
            if (xcross <= xb2[w]) { iy1 = inty; ix1 = xcross; }
            //clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),0L);
            for (i=xb1[w]; i<=xcross; i++) mostbuf[i] = 0;
        }
    }

    if (bad&12)
    {
        t = divscale30(z-s3,s4-s3);
        inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
        xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty);

        if ((bad&12) == 8)
        {
            if (xb1[w] <= xcross) { iy2 = inty; ix2 = xcross; }
            //clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
            for (i=xcross+1; i<=xb2[w]; i++) mostbuf[i] = ydimen;
        }
        else
        {
            if (xcross <= xb2[w]) { iy1 = inty; ix1 = xcross; }
            //clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
            for (i=xb1[w]; i<=xcross; i++) mostbuf[i] = ydimen;
        }
    }

    y = (scale(z,xdimenscale,iy1)<<4);
    yinc = ((scale(z,xdimenscale,iy2)<<4)-y) / (ix2-ix1+1);
    qinterpolatedown16short((intptr_t)&mostbuf[ix1],ix2-ix1+1,y+(globalhoriz<<16),yinc);

    if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
    if (mostbuf[ix1] > ydimen) mostbuf[ix1] = ydimen;
    if (mostbuf[ix2] < 0) mostbuf[ix2] = 0;
    if (mostbuf[ix2] > ydimen) mostbuf[ix2] = ydimen;

    return(bad);
}


//
// wallmost (internal)
//
static int wallmost(short *mostbuf, int w, int sectnum, char dastat)
{
    int bad, i, j, t, y, z, inty, intz, xcross, yinc, fw;
    int x1, y1, z1, x2, y2, z2, xv, yv, dx, dy, dasqr, oz1, oz2;
    int s1, s2, s3, s4, ix1, ix2, iy1, iy2;
    //char datempbuf[256];

    if (dastat == 0)
    {
        z = sector[sectnum].ceilingz-globalposz;
        if ((sector[sectnum].ceilingstat&2) == 0) return(owallmost(mostbuf,w,z));
    }
    else
    {
        z = sector[sectnum].floorz-globalposz;
        if ((sector[sectnum].floorstat&2) == 0) return(owallmost(mostbuf,w,z));
    }

    i = thewall[w];
    if (i == sector[sectnum].wallptr) return(owallmost(mostbuf,w,z));

    x1 = wall[i].x; x2 = wall[wall[i].point2].x-x1;
    y1 = wall[i].y; y2 = wall[wall[i].point2].y-y1;

    fw = sector[sectnum].wallptr; i = wall[fw].point2;
    dx = wall[i].x-wall[fw].x; dy = wall[i].y-wall[fw].y;
    dasqr = krecipasm(nsqrtasm(dx*dx+dy*dy));

    if (xb1[w] == 0)
        { xv = cosglobalang+sinviewingrangeglobalang; yv = singlobalang-cosviewingrangeglobalang; }
    else
        { xv = x1-globalposx; yv = y1-globalposy; }
    i = xv*(y1-globalposy)-yv*(x1-globalposx); j = yv*x2-xv*y2;
    if (klabs(j) > klabs(i>>3)) i = divscale28(i,j);
    if (dastat == 0)
    {
        t = mulscale15(sector[sectnum].ceilingheinum,dasqr);
        z1 = sector[sectnum].ceilingz;
    }
    else
    {
        t = mulscale15(sector[sectnum].floorheinum,dasqr);
        z1 = sector[sectnum].floorz;
    }
    z1 = dmulscale24(dx*t,mulscale20(y2,i)+((y1-wall[fw].y)<<8),
                     -dy*t,mulscale20(x2,i)+((x1-wall[fw].x)<<8))+((z1-globalposz)<<7);


    if (xb2[w] == xdimen-1)
        { xv = cosglobalang-sinviewingrangeglobalang; yv = singlobalang+cosviewingrangeglobalang; }
    else
        { xv = (x2+x1)-globalposx; yv = (y2+y1)-globalposy; }
    i = xv*(y1-globalposy)-yv*(x1-globalposx); j = yv*x2-xv*y2;
    if (klabs(j) > klabs(i>>3)) i = divscale28(i,j);
    if (dastat == 0)
    {
        t = mulscale15(sector[sectnum].ceilingheinum,dasqr);
        z2 = sector[sectnum].ceilingz;
    }
    else
    {
        t = mulscale15(sector[sectnum].floorheinum,dasqr);
        z2 = sector[sectnum].floorz;
    }
    z2 = dmulscale24(dx*t,mulscale20(y2,i)+((y1-wall[fw].y)<<8),
                     -dy*t,mulscale20(x2,i)+((x1-wall[fw].x)<<8))+((z2-globalposz)<<7);


    s1 = mulscale20(globaluclip,yb1[w]); s2 = mulscale20(globaluclip,yb2[w]);
    s3 = mulscale20(globaldclip,yb1[w]); s4 = mulscale20(globaldclip,yb2[w]);
    bad = (z1<s1)+((z2<s2)<<1)+((z1>s3)<<2)+((z2>s4)<<3);

    ix1 = xb1[w]; ix2 = xb2[w];
    iy1 = yb1[w]; iy2 = yb2[w];
    oz1 = z1; oz2 = z2;

    if ((bad&3) == 3)
    {
        //clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),0L);
        for (i=ix1; i<=ix2; i++) mostbuf[i] = 0;
        return(bad);
    }

    if ((bad&12) == 12)
    {
        //clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
        for (i=ix1; i<=ix2; i++) mostbuf[i] = ydimen;
        return(bad);
    }

    if (bad&3)
    {
        //inty = intz / (globaluclip>>16)
        t = divscale30(oz1-s1,s2-s1+oz1-oz2);
        inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
        intz = oz1 + mulscale30(oz2-oz1,t);
        xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty);

        //t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4));
        //inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
        //intz = z1 + mulscale30(z2-z1,t);

        if ((bad&3) == 2)
        {
            if (xb1[w] <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; }
            //clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),0L);
            for (i=xcross+1; i<=xb2[w]; i++) mostbuf[i] = 0;
        }
        else
        {
            if (xcross <= xb2[w]) { z1 = intz; iy1 = inty; ix1 = xcross; }
            //clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),0L);
            for (i=xb1[w]; i<=xcross; i++) mostbuf[i] = 0;
        }
    }

    if (bad&12)
    {
        //inty = intz / (globaldclip>>16)
        t = divscale30(oz1-s3,s4-s3+oz1-oz2);
        inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
        intz = oz1 + mulscale30(oz2-oz1,t);
        xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty);

        //t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4));
        //inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
        //intz = z1 + mulscale30(z2-z1,t);

        if ((bad&12) == 8)
        {
            if (xb1[w] <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; }
            //clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
            for (i=xcross+1; i<=xb2[w]; i++) mostbuf[i] = ydimen;
        }
        else
        {
            if (xcross <= xb2[w]) { z1 = intz; iy1 = inty; ix1 = xcross; }
            //clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16));
            for (i=xb1[w]; i<=xcross; i++) mostbuf[i] = ydimen;
        }
    }

    y = (scale(z1,xdimenscale,iy1)<<4);
    yinc = ((scale(z2,xdimenscale,iy2)<<4)-y) / (ix2-ix1+1);
    qinterpolatedown16short((intptr_t)&mostbuf[ix1],ix2-ix1+1,y+(globalhoriz<<16),yinc);

    if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
    if (mostbuf[ix1] > ydimen) mostbuf[ix1] = ydimen;
    if (mostbuf[ix2] < 0) mostbuf[ix2] = 0;
    if (mostbuf[ix2] > ydimen) mostbuf[ix2] = ydimen;

    return(bad);
}


//
// ceilscan (internal)
//
static void ceilscan(int x1, int x2, int sectnum)
{
    int i, j, ox, oy, x, y1, y2, twall, bwall;
    sectortype *sec;

    sec = &sector[sectnum];
    if (palookup[sec->ceilingpal] != globalpalwritten)
    {
        globalpalwritten = palookup[sec->ceilingpal];
        if (!globalpalwritten) globalpalwritten = palookup[globalpal];  // JBF: fixes null-pointer crash
        setpalookupaddress(globalpalwritten);
    }

    globalzd = sec->ceilingz-globalposz;
    if (globalzd > 0) return;
    globalpicnum = sec->ceilingpicnum;
    if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
    setgotpic(globalpicnum);
    if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return;
    if (picanm[globalpicnum]&192) globalpicnum += animateoffs((short)globalpicnum,(short)sectnum);

    if (waloff[globalpicnum] == 0) loadtile(globalpicnum);
    globalbufplc = waloff[globalpicnum];

    globalshade = (int)sec->ceilingshade;
    globvis = globalcisibility;
    if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
    globalorientation = (int)sec->ceilingstat;


    if ((globalorientation&64) == 0)
    {
        globalx1 = singlobalang; globalx2 = singlobalang;
        globaly1 = cosglobalang; globaly2 = cosglobalang;
        globalxpanning = (globalposx<<20);
        globalypanning = -(globalposy<<20);
    }
    else
    {
        j = sec->wallptr;
        ox = wall[wall[j].point2].x - wall[j].x;
        oy = wall[wall[j].point2].y - wall[j].y;
        i = nsqrtasm(ox*ox+oy*oy); if (i == 0) i = 1024; else i = 1048576/i;
        globalx1 = mulscale10(dmulscale10(ox,singlobalang,-oy,cosglobalang),i);
        globaly1 = mulscale10(dmulscale10(ox,cosglobalang,oy,singlobalang),i);
        globalx2 = -globalx1;
        globaly2 = -globaly1;

        ox = ((wall[j].x-globalposx)<<6); oy = ((wall[j].y-globalposy)<<6);
        i = dmulscale14(oy,cosglobalang,-ox,singlobalang);
        j = dmulscale14(ox,cosglobalang,oy,singlobalang);
        ox = i; oy = j;
        globalxpanning = globalx1*ox - globaly1*oy;
        globalypanning = globaly2*ox + globalx2*oy;
    }
    globalx2 = mulscale16(globalx2,viewingrangerecip);
    globaly1 = mulscale16(globaly1,viewingrangerecip);
    globalxshift = (8-(picsiz[globalpicnum]&15));
    globalyshift = (8-(picsiz[globalpicnum]>>4));
    if (globalorientation&8) { globalxshift++; globalyshift++; }

    if ((globalorientation&0x4) > 0)
    {
        i = globalxpanning; globalxpanning = globalypanning; globalypanning = i;
        i = globalx2; globalx2 = -globaly1; globaly1 = -i;
        i = globalx1; globalx1 = globaly2; globaly2 = i;
    }
    if ((globalorientation&0x10) > 0) globalx1 = -globalx1, globaly1 = -globaly1, globalxpanning = -globalxpanning;
    if ((globalorientation&0x20) > 0) globalx2 = -globalx2, globaly2 = -globaly2, globalypanning = -globalypanning;
    globalx1 <<= globalxshift; globaly1 <<= globalxshift;
    globalx2 <<= globalyshift;  globaly2 <<= globalyshift;
    globalxpanning <<= globalxshift; globalypanning <<= globalyshift;
    globalxpanning += (((int)sec->ceilingxpanning)<<24);
    globalypanning += (((int)sec->ceilingypanning)<<24);
    globaly1 = (-globalx1-globaly1)*halfxdimen;
    globalx2 = (globalx2-globaly2)*halfxdimen;

    sethlinesizes(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4,globalbufplc);

    globalx2 += globaly2*(x1-1);
    globaly1 += globalx1*(x1-1);
    globalx1 = mulscale16(globalx1,globalzd);
    globalx2 = mulscale16(globalx2,globalzd);
    globaly1 = mulscale16(globaly1,globalzd);
    globaly2 = mulscale16(globaly2,globalzd);
    globvis = klabs(mulscale10(globvis,globalzd));

    if (!(globalorientation&0x180))
    {
        y1 = umost[x1]; y2 = y1;
        for (x=x1;x<=x2;x++)
        {
            twall = umost[x]-1; bwall = min(uplc[x],dmost[x]);
            if (twall < bwall-1)
            {
                if (twall >= y2)
                {
                    while (y1 < y2-1) hline(x-1,++y1);
                    y1 = twall;
                }
                else
                {
                    while (y1 < twall) hline(x-1,++y1);
                    while (y1 > twall) lastx[y1--] = x;
                }
                while (y2 > bwall) hline(x-1,--y2);
                while (y2 < bwall) lastx[y2++] = x;
            }
            else
            {
                while (y1 < y2-1) hline(x-1,++y1);
                if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; }
                y1 = umost[x+1]; y2 = y1;
            }
            globalx2 += globaly2; globaly1 += globalx1;
        }
        while (y1 < y2-1) hline(x2,++y1);
        faketimerhandler();
        return;
    }

    switch (globalorientation&0x180)
    {
    case 128:
        msethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
        break;
    case 256:
        settransnormal();
        tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
        break;
    case 384:
        settransreverse();
        tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
        break;
    }

    y1 = umost[x1]; y2 = y1;
    for (x=x1;x<=x2;x++)
    {
        twall = umost[x]-1; bwall = min(uplc[x],dmost[x]);
        if (twall < bwall-1)
        {
            if (twall >= y2)
            {
                while (y1 < y2-1) slowhline(x-1,++y1);
                y1 = twall;
            }
            else
            {
                while (y1 < twall) slowhline(x-1,++y1);
                while (y1 > twall) lastx[y1--] = x;
            }
            while (y2 > bwall) slowhline(x-1,--y2);
            while (y2 < bwall) lastx[y2++] = x;
        }
        else
        {
            while (y1 < y2-1) slowhline(x-1,++y1);
            if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; }
            y1 = umost[x+1]; y2 = y1;
        }
        globalx2 += globaly2; globaly1 += globalx1;
    }
    while (y1 < y2-1) slowhline(x2,++y1);
    faketimerhandler();
}


//
// florscan (internal)
//
static void florscan(int x1, int x2, int sectnum)
{
    int i, j, ox, oy, x, y1, y2, twall, bwall;
    sectortype *sec;

    sec = &sector[sectnum];
    if (palookup[sec->floorpal] != globalpalwritten)
    {
        globalpalwritten = palookup[sec->floorpal];
        if (!globalpalwritten) globalpalwritten = palookup[globalpal];  // JBF: fixes null-pointer crash
        setpalookupaddress(globalpalwritten);
    }

    globalzd = globalposz-sec->floorz;
    if (globalzd > 0) return;
    globalpicnum = sec->floorpicnum;
    if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
    setgotpic(globalpicnum);
    if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return;
    if (picanm[globalpicnum]&192) globalpicnum += animateoffs((short)globalpicnum,(short)sectnum);

    if (waloff[globalpicnum] == 0) loadtile(globalpicnum);
    globalbufplc = waloff[globalpicnum];

    globalshade = (int)sec->floorshade;
    globvis = globalcisibility;
    if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
    globalorientation = (int)sec->floorstat;


    if ((globalorientation&64) == 0)
    {
        globalx1 = singlobalang; globalx2 = singlobalang;
        globaly1 = cosglobalang; globaly2 = cosglobalang;
        globalxpanning = (globalposx<<20);
        globalypanning = -(globalposy<<20);
    }
    else
    {
        j = sec->wallptr;
        ox = wall[wall[j].point2].x - wall[j].x;
        oy = wall[wall[j].point2].y - wall[j].y;
        i = nsqrtasm(ox*ox+oy*oy); if (i == 0) i = 1024; else i = 1048576/i;
        globalx1 = mulscale10(dmulscale10(ox,singlobalang,-oy,cosglobalang),i);
        globaly1 = mulscale10(dmulscale10(ox,cosglobalang,oy,singlobalang),i);
        globalx2 = -globalx1;
        globaly2 = -globaly1;

        ox = ((wall[j].x-globalposx)<<6); oy = ((wall[j].y-globalposy)<<6);
        i = dmulscale14(oy,cosglobalang,-ox,singlobalang);
        j = dmulscale14(ox,cosglobalang,oy,singlobalang);
        ox = i; oy = j;
        globalxpanning = globalx1*ox - globaly1*oy;
        globalypanning = globaly2*ox + globalx2*oy;
    }
    globalx2 = mulscale16(globalx2,viewingrangerecip);
    globaly1 = mulscale16(globaly1,viewingrangerecip);
    globalxshift = (8-(picsiz[globalpicnum]&15));
    globalyshift = (8-(picsiz[globalpicnum]>>4));
    if (globalorientation&8) { globalxshift++; globalyshift++; }

    if ((globalorientation&0x4) > 0)
    {
        i = globalxpanning; globalxpanning = globalypanning; globalypanning = i;
        i = globalx2; globalx2 = -globaly1; globaly1 = -i;
        i = globalx1; globalx1 = globaly2; globaly2 = i;
    }
    if ((globalorientation&0x10) > 0) globalx1 = -globalx1, globaly1 = -globaly1, globalxpanning = -globalxpanning;
    if ((globalorientation&0x20) > 0) globalx2 = -globalx2, globaly2 = -globaly2, globalypanning = -globalypanning;
    globalx1 <<= globalxshift; globaly1 <<= globalxshift;
    globalx2 <<= globalyshift;  globaly2 <<= globalyshift;
    globalxpanning <<= globalxshift; globalypanning <<= globalyshift;
    globalxpanning += (((int)sec->floorxpanning)<<24);
    globalypanning += (((int)sec->floorypanning)<<24);
    globaly1 = (-globalx1-globaly1)*halfxdimen;
    globalx2 = (globalx2-globaly2)*halfxdimen;

    sethlinesizes(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4,globalbufplc);

    globalx2 += globaly2*(x1-1);
    globaly1 += globalx1*(x1-1);
    globalx1 = mulscale16(globalx1,globalzd);
    globalx2 = mulscale16(globalx2,globalzd);
    globaly1 = mulscale16(globaly1,globalzd);
    globaly2 = mulscale16(globaly2,globalzd);
    globvis = klabs(mulscale10(globvis,globalzd));

    if (!(globalorientation&0x180))
    {
        y1 = max(dplc[x1],umost[x1]); y2 = y1;
        for (x=x1;x<=x2;x++)
        {
            twall = max(dplc[x],umost[x])-1; bwall = dmost[x];
            if (twall < bwall-1)
            {
                if (twall >= y2)
                {
                    while (y1 < y2-1) hline(x-1,++y1);
                    y1 = twall;
                }
                else
                {
                    while (y1 < twall) hline(x-1,++y1);
                    while (y1 > twall) lastx[y1--] = x;
                }
                while (y2 > bwall) hline(x-1,--y2);
                while (y2 < bwall) lastx[y2++] = x;
            }
            else
            {
                while (y1 < y2-1) hline(x-1,++y1);
                if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; }
                y1 = max(dplc[x+1],umost[x+1]); y2 = y1;
            }
            globalx2 += globaly2; globaly1 += globalx1;
        }
        while (y1 < y2-1) hline(x2,++y1);
        faketimerhandler();
        return;
    }

    switch (globalorientation&0x180)
    {
    case 128:
        msethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
        break;
    case 256:
        settransnormal();
        tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
        break;
    case 384:
        settransreverse();
        tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4);
        break;
    }

    y1 = max(dplc[x1],umost[x1]); y2 = y1;
    for (x=x1;x<=x2;x++)
    {
        twall = max(dplc[x],umost[x])-1; bwall = dmost[x];
        if (twall < bwall-1)
        {
            if (twall >= y2)
            {
                while (y1 < y2-1) slowhline(x-1,++y1);
                y1 = twall;
            }
            else
            {
                while (y1 < twall) slowhline(x-1,++y1);
                while (y1 > twall) lastx[y1--] = x;
            }
            while (y2 > bwall) slowhline(x-1,--y2);
            while (y2 < bwall) lastx[y2++] = x;
        }
        else
        {
            while (y1 < y2-1) slowhline(x-1,++y1);
            if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; }
            y1 = max(dplc[x+1],umost[x+1]); y2 = y1;
        }
        globalx2 += globaly2; globaly1 += globalx1;
    }
    while (y1 < y2-1) slowhline(x2,++y1);
    faketimerhandler();
}


//
// wallscan (internal)
//
static void wallscan(int x1, int x2, short *uwal, short *dwal, int *swal, int *lwal)
{
    int i, x, xnice, ynice, fpalookup;
    int y1ve[4], y2ve[4], u4, d4, z, tsizx, tsizy;
    char bad;

    if (x2 >= xdim) x2 = xdim-1;

    tsizx = tilesizx[globalpicnum];
    tsizy = tilesizy[globalpicnum];
    setgotpic(globalpicnum);
    if ((tsizx <= 0) || (tsizy <= 0)) return;
    if ((uwal[x1] > ydimen) && (uwal[x2] > ydimen)) return;
    if ((dwal[x1] < 0) && (dwal[x2] < 0)) return;

    if (waloff[globalpicnum] == 0) loadtile(globalpicnum);

    xnice = (pow2long[picsiz[globalpicnum]&15] == tsizx);
    if (xnice) tsizx--;
    ynice = (pow2long[picsiz[globalpicnum]>>4] == tsizy);
    if (ynice) tsizy = (picsiz[globalpicnum]>>4);

    fpalookup = FP_OFF(palookup[globalpal]);

    setupvlineasm(globalshiftval);

#ifndef ENGINE_USING_A_C

    x = x1;
    while ((umost[x] > dmost[x]) && (x <= x2)) x++;

    for (;(x<=x2)&&((x+frameoffset)&3);x++)
    {
        y1ve[0] = max(uwal[x],umost[x]);
        y2ve[0] = min(dwal[x],dmost[x]);
        if (y2ve[0] <= y1ve[0]) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);

        bufplce[0] = lwal[x] + globalxpanning;
        if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; }
        if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy;

        vince[0] = swal[x]*globalyscale;
        vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);

        vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],x+frameoffset+ylookup[y1ve[0]]);
    }
    for (;x<=x2-3;x+=4)
    {
        bad = 0;
        for (z=3;z>=0;z--)
        {
            y1ve[z] = max(uwal[x+z],umost[x+z]);
            y2ve[z] = min(dwal[x+z],dmost[x+z])-1;
            if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }

            i = lwal[x+z] + globalxpanning;
            if (i >= tsizx) { if (xnice == 0) i %= tsizx; else i &= tsizx; }
            if (ynice == 0) i *= tsizy; else i <<= tsizy;
            bufplce[z] = waloff[globalpicnum]+i;

            vince[z] = swal[x+z]*globalyscale;
            vplce[z] = globalzd + vince[z]*(y1ve[z]-globalhoriz+1);
        }
        if (bad == 15) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);
        palookupoffse[3] = fpalookup+(getpalookup((int)mulscale16(swal[x+3],globvis),globalshade)<<8);

        if ((palookupoffse[0] == palookupoffse[3]) && ((bad&0x9) == 0))
        {
            palookupoffse[1] = palookupoffse[0];
            palookupoffse[2] = palookupoffse[0];
        }
        else
        {
            palookupoffse[1] = fpalookup+(getpalookup((int)mulscale16(swal[x+1],globvis),globalshade)<<8);
            palookupoffse[2] = fpalookup+(getpalookup((int)mulscale16(swal[x+2],globvis),globalshade)<<8);
        }

        u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3]));
        d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3]));

        if ((bad != 0) || (u4 >= d4))
        {
            if (!(bad&1)) prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+x+frameoffset+0);
            if (!(bad&2)) prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+x+frameoffset+1);
            if (!(bad&4)) prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+x+frameoffset+2);
            if (!(bad&8)) prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+x+frameoffset+3);
            continue;
        }

        if (u4 > y1ve[0]) vplce[0] = prevlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+x+frameoffset+0);
        if (u4 > y1ve[1]) vplce[1] = prevlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+x+frameoffset+1);
        if (u4 > y1ve[2]) vplce[2] = prevlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+x+frameoffset+2);
        if (u4 > y1ve[3]) vplce[3] = prevlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+x+frameoffset+3);

        if (d4 >= u4) vlineasm4(d4-u4+1,ylookup[u4]+x+frameoffset);

        i = x+frameoffset+ylookup[d4+1];
        if (y2ve[0] > d4) prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0);
        if (y2ve[1] > d4) prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1);
        if (y2ve[2] > d4) prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2);
        if (y2ve[3] > d4) prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3);
    }
    for (;x<=x2;x++)
    {
        y1ve[0] = max(uwal[x],umost[x]);
        y2ve[0] = min(dwal[x],dmost[x]);
        if (y2ve[0] <= y1ve[0]) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);

        bufplce[0] = lwal[x] + globalxpanning;
        if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; }
        if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy;

        vince[0] = swal[x]*globalyscale;
        vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);

        vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],x+frameoffset+ylookup[y1ve[0]]);
    }

#else   // ENGINE_USING_A_C

    for (x=x1;x<=x2;x++)
    {
        y1ve[0] = max(uwal[x],umost[x]);
        y2ve[0] = min(dwal[x],dmost[x]);
        if (y2ve[0] <= y1ve[0]) continue;

        palookupoffse[0] = fpalookup+(getpalookup((int)mulscale16(swal[x],globvis),globalshade)<<8);

        bufplce[0] = lwal[x] + globalxpanning;
        if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; }
        if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy;

        vince[0] = swal[x]*globalyscale;
        vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);

        vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],x+frameoffset+ylookup[y1ve[0]]);
    }

#endif

    faketimerhandler();
}


//
// transmaskvline (internal)
//
static void transmaskvline(int x)
{
    int vplc, vinc, i;
    intptr_t palookupoffs;
    intptr_t bufplc,p;
    short y1v, y2v;

    if ((x < 0) || (x >= xdimen)) return;

    y1v = max(uwall[x],startumost[x+windowx1]-windowy1);
    y2v = min(dwall[x],startdmost[x+windowx1]-windowy1);
    y2v--;
    if (y2v < y1v) return;

    palookupoffs = FP_OFF(palookup[globalpal]) + (getpalookup((int)mulscale16(swall[x],globvis),globalshade)<<8);

    vinc = swall[x]*globalyscale;
    vplc = globalzd + vinc*(y1v-globalhoriz+1);

    i = lwall[x]+globalxpanning;
    if (i >= tilesizx[globalpicnum]) i %= tilesizx[globalpicnum];
    bufplc = waloff[globalpicnum]+i*tilesizy[globalpicnum];

    p = ylookup[y1v]+x+frameoffset;

    tvlineasm1(vinc,palookupoffs,y2v-y1v,vplc,bufplc,p);
}


//
// transmaskvline2 (internal)
//
#ifndef ENGINE_USING_A_C
static void transmaskvline2(int x)
{
    int i, y1, y2, x2;
    short y1ve[2], y2ve[2];

    if ((x < 0) || (x >= xdimen)) return;
    if (x == xdimen-1) { transmaskvline(x); return; }

    x2 = x+1;

    y1ve[0] = max(uwall[x],startumost[x+windowx1]-windowy1);
    y2ve[0] = min(dwall[x],startdmost[x+windowx1]-windowy1)-1;
    if (y2ve[0] < y1ve[0]) { transmaskvline(x2); return; }
    y1ve[1] = max(uwall[x2],startumost[x2+windowx1]-windowy1);
    y2ve[1] = min(dwall[x2],startdmost[x2+windowx1]-windowy1)-1;
    if (y2ve[1] < y1ve[1]) { transmaskvline(x); return; }

    palookupoffse[0] = FP_OFF(palookup[globalpal]) + (getpalookup((int)mulscale16(swall[x],globvis),globalshade)<<8);
    palookupoffse[1] = FP_OFF(palookup[globalpal]) + (getpalookup((int)mulscale16(swall[x2],globvis),globalshade)<<8);

    setuptvlineasm2(globalshiftval,palookupoffse[0],palookupoffse[1]);

    vince[0] = swall[x]*globalyscale;
    vince[1] = swall[x2]*globalyscale;
    vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1);
    vplce[1] = globalzd + vince[1]*(y1ve[1]-globalhoriz+1);

    i = lwall[x] + globalxpanning;
    if (i >= tilesizx[globalpicnum]) i %= tilesizx[globalpicnum];
    bufplce[0] = waloff[globalpicnum]+i*tilesizy[globalpicnum];

    i = lwall[x2] + globalxpanning;
    if (i >= tilesizx[globalpicnum]) i %= tilesizx[globalpicnum];
    bufplce[1] = waloff[globalpicnum]+i*tilesizy[globalpicnum];

    y1 = max(y1ve[0],y1ve[1]);
    y2 = min(y2ve[0],y2ve[1]);

    i = x+frameoffset;

    if (y1ve[0] != y1ve[1])
    {
        if (y1ve[0] < y1)
            vplce[0] = tvlineasm1(vince[0],palookupoffse[0],y1-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+i);
        else
            vplce[1] = tvlineasm1(vince[1],palookupoffse[1],y1-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+i+1);
    }

    if (y2 > y1)
    {
        asm1 = vince[1];
        asm2 = ylookup[y2]+i+1;
        tvlineasm2(vplce[1],vince[0],bufplce[0],bufplce[1],vplce[0],ylookup[y1]+i);
    }
    else
    {
        asm1 = vplce[0];
        asm2 = vplce[1];
    }

    if (y2ve[0] > y2ve[1])
        tvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y2-1,asm1,bufplce[0],ylookup[y2+1]+i);
    else if (y2ve[0] < y2ve[1])
        tvlineasm1(vince[1],palookupoffse[1],y2ve[1]-y2-1,asm2,bufplce[1],ylookup[y2+1]+i+1);

    faketimerhandler();
}
#endif

//
// transmaskwallscan (internal)
//
static void transmaskwallscan(int x1, int x2)
{
    int x;

    setgotpic(globalpicnum);
    if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return;

    if (waloff[globalpicnum] == 0) loadtile(globalpicnum);

    setuptvlineasm(globalshiftval);

    x = x1;
    while ((startumost[x+windowx1] > startdmost[x+windowx1]) && (x <= x2)) x++;
#ifndef ENGINE_USING_A_C
    if ((x <= x2) && (x&1)) transmaskvline(x), x++;
    while (x < x2) transmaskvline2(x), x += 2;
#endif
    while (x <= x2) transmaskvline(x), x++;
    faketimerhandler();
}


//
// ceilspritehline (internal)
//
static void ceilspritehline(int x2, int y)
{
    int x1, v, bx, by;

    //x = x1 + (x2-x1)t + (y1-y2)u  ~  x = 160v
    //y = y1 + (y2-y1)t + (x2-x1)u  ~  y = (scrx-160)v
    //z = z1 = z2                   ~  z = posz + (scry-horiz)v

    x1 = lastx[y]; if (x2 < x1) return;

    v = mulscale20(globalzd,horizlookup[y-globalhoriz+horizycent]);
    bx = mulscale14(globalx2*x1+globalx1,v) + globalxpanning;
    by = mulscale14(globaly2*x1+globaly1,v) + globalypanning;
    asm1 = mulscale14(globalx2,v);
    asm2 = mulscale14(globaly2,v);

    asm3 = FP_OFF(palookup[globalpal]) + (getpalookup((int)mulscale28(klabs(v),globvis),globalshade)<<8);

    if ((globalorientation&2) == 0)
        mhline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset);
    else
    {
        thline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset);
    }
}


//
// ceilspritescan (internal)
//
static void ceilspritescan(int x1, int x2)
{
    int x, y1, y2, twall, bwall;

    y1 = uwall[x1]; y2 = y1;
    for (x=x1;x<=x2;x++)
    {
        twall = uwall[x]-1; bwall = dwall[x];
        if (twall < bwall-1)
        {
            if (twall >= y2)
            {
                while (y1 < y2-1) ceilspritehline(x-1,++y1);
                y1 = twall;
            }
            else
            {
                while (y1 < twall) ceilspritehline(x-1,++y1);
                while (y1 > twall) lastx[y1--] = x;
            }
            while (y2 > bwall) ceilspritehline(x-1,--y2);
            while (y2 < bwall) lastx[y2++] = x;
        }
        else
        {
            while (y1 < y2-1) ceilspritehline(x-1,++y1);
            if (x == x2) break;
            y1 = uwall[x+1]; y2 = y1;
        }
    }
    while (y1 < y2-1) ceilspritehline(x2,++y1);
    faketimerhandler();
}


//
// grouscan (internal)
//
#define BITSOFPRECISION 3  //Don't forget to change this in A.ASM also!
static void grouscan(int dax1, int dax2, int sectnum, char dastat)
{
    int i, j, l, x, y, dx, dy, wx, wy, y1, y2, daz;
    int daslope, dasqr;
    int shoffs, shinc, m1, m2, *mptr1, *mptr2, *nptr1, *nptr2;
    walltype *wal;
    sectortype *sec;

    sec = &sector[sectnum];

    if (dastat == 0)
    {
        if (globalposz <= getceilzofslope(sectnum,globalposx,globalposy))
            return;  //Back-face culling
        globalorientation = sec->ceilingstat;
        globalpicnum = sec->ceilingpicnum;
        globalshade = sec->ceilingshade;
        globalpal = sec->ceilingpal;
        daslope = sec->ceilingheinum;
        daz = sec->ceilingz;
    }
    else
    {
        if (globalposz >= getflorzofslope(sectnum,globalposx,globalposy))
            return;  //Back-face culling
        globalorientation = sec->floorstat;
        globalpicnum = sec->floorpicnum;
        globalshade = sec->floorshade;
        globalpal = sec->floorpal;
        daslope = sec->floorheinum;
        daz = sec->floorz;
    }

    if ((picanm[globalpicnum]&192) != 0) globalpicnum += animateoffs(globalpicnum,sectnum);
    setgotpic(globalpicnum);
    if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return;
    if (waloff[globalpicnum] == 0) loadtile(globalpicnum);

    wal = &wall[sec->wallptr];
    wx = wall[wal->point2].x - wal->x;
    wy = wall[wal->point2].y - wal->y;
    dasqr = krecipasm(nsqrtasm(wx*wx+wy*wy));
    i = mulscale21(daslope,dasqr);
    wx *= i; wy *= i;

    globalx = -mulscale19(singlobalang,xdimenrecip);
    globaly = mulscale19(cosglobalang,xdimenrecip);
    globalx1 = (globalposx<<8);
    globaly1 = -(globalposy<<8);
    i = (dax1-halfxdimen)*xdimenrecip;
    globalx2 = mulscale16(cosglobalang<<4,viewingrangerecip) - mulscale27(singlobalang,i);
    globaly2 = mulscale16(singlobalang<<4,viewingrangerecip) + mulscale27(cosglobalang,i);
    globalzd = (xdimscale<<9);
    globalzx = -dmulscale17(wx,globaly2,-wy,globalx2) + mulscale10(1-globalhoriz,globalzd);
    globalz = -dmulscale25(wx,globaly,-wy,globalx);

    if (globalorientation&64)  //Relative alignment
    {
        dx = mulscale14(wall[wal->point2].x-wal->x,dasqr);
        dy = mulscale14(wall[wal->point2].y-wal->y,dasqr);

        i = nsqrtasm(daslope*daslope+16777216);

        x = globalx; y = globaly;
        globalx = dmulscale16(x,dx,y,dy);
        globaly = mulscale12(dmulscale16(-y,dx,x,dy),i);

        x = ((wal->x-globalposx)<<8); y = ((wal->y-globalposy)<<8);
        globalx1 = dmulscale16(-x,dx,-y,dy);
        globaly1 = mulscale12(dmulscale16(-y,dx,x,dy),i);

        x = globalx2; y = globaly2;
        globalx2 = dmulscale16(x,dx,y,dy);
        globaly2 = mulscale12(dmulscale16(-y,dx,x,dy),i);
    }
    if (globalorientation&0x4)
    {
        i = globalx; globalx = -globaly; globaly = -i;
        i = globalx1; globalx1 = globaly1; globaly1 = i;
        i = globalx2; globalx2 = -globaly2; globaly2 = -i;
    }
    if (globalorientation&0x10) { globalx1 = -globalx1, globalx2 = -globalx2, globalx = -globalx; }
    if (globalorientation&0x20) { globaly1 = -globaly1, globaly2 = -globaly2, globaly = -globaly; }

    daz = dmulscale9(wx,globalposy-wal->y,-wy,globalposx-wal->x) + ((daz-globalposz)<<8);
    globalx2 = mulscale20(globalx2,daz); globalx = mulscale28(globalx,daz);
    globaly2 = mulscale20(globaly2,-daz); globaly = mulscale28(globaly,-daz);

    i = 8-(picsiz[globalpicnum]&15); j = 8-(picsiz[globalpicnum]>>4);
    if (globalorientation&8) { i++; j++; }
    globalx1 <<= (i+12); globalx2 <<= i; globalx <<= i;
    globaly1 <<= (j+12); globaly2 <<= j; globaly <<= j;

    if (dastat == 0)
    {
        globalx1 += (((int)sec->ceilingxpanning)<<24);
        globaly1 += (((int)sec->ceilingypanning)<<24);
    }
    else
    {
        globalx1 += (((int)sec->floorxpanning)<<24);
        globaly1 += (((int)sec->floorypanning)<<24);
    }

    asm1 = -(globalzd>>(16-BITSOFPRECISION));

    globvis = globalvisibility;
    if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
    globvis = mulscale13(globvis,daz);
    globvis = mulscale16(globvis,xdimscale);
    j = FP_OFF(palookup[globalpal]);

    setupslopevlin(((int)(picsiz[globalpicnum]&15))+(((int)(picsiz[globalpicnum]>>4))<<8),waloff[globalpicnum],-ylookup[1]);

    l = (globalzd>>16);

    shinc = mulscale16(globalz,xdimenscale);
    if (shinc > 0) shoffs = (4<<15); else shoffs = ((16380-ydimen)<<15);    // JBF: was 2044
    if (dastat == 0) y1 = umost[dax1]; else y1 = max(umost[dax1],dplc[dax1]);
    m1 = mulscale16(y1,globalzd) + (globalzx>>6);
    //Avoid visibility overflow by crossing horizon
    if (globalzd > 0) m1 += (globalzd>>16); else m1 -= (globalzd>>16);
    m2 = m1+l;
    mptr1 = (int *)&slopalookup[y1+(shoffs>>15)]; mptr2 = mptr1+1;

    for (x=dax1;x<=dax2;x++)
    {
        if (dastat == 0) { y1 = umost[x]; y2 = min(dmost[x],uplc[x])-1; }
        else { y1 = max(umost[x],dplc[x]); y2 = dmost[x]-1; }
        if (y1 <= y2)
        {
            nptr1 = (int *)&slopalookup[y1+(shoffs>>15)];
            nptr2 = (int *)&slopalookup[y2+(shoffs>>15)];
            while (nptr1 <= mptr1)
            {
                *mptr1-- = j + (getpalookup((int)mulscale24(krecipasm(m1),globvis),globalshade)<<8);
                m1 -= l;
            }
            while (nptr2 >= mptr2)
            {
                *mptr2++ = j + (getpalookup((int)mulscale24(krecipasm(m2),globvis),globalshade)<<8);
                m2 += l;
            }

            globalx3 = (globalx2>>10);
            globaly3 = (globaly2>>10);
            asm3 = mulscale16(y2,globalzd) + (globalzx>>6);
            slopevlin(ylookup[y2]+x+frameoffset,krecipasm(asm3>>3),(intptr_t)nptr2,y2-y1+1,globalx1,globaly1);

            if ((x&15) == 0) faketimerhandler();
        }
        globalx2 += globalx;
        globaly2 += globaly;
        globalzx += globalz;
        shoffs += shinc;
    }
}


//
// parascan (internal)
//
static void parascan(int dax1, int dax2, int sectnum, char dastat, int bunch)
{
    sectortype *sec;
    int j, k, l, m, n, x, z, wallnum, nextsectnum, globalhorizbak;
    short *topptr, *botptr;

    UNREFERENCED_PARAMETER(dax1);
    UNREFERENCED_PARAMETER(dax2);

    sectnum = thesector[bunchfirst[bunch]]; sec = &sector[sectnum];

    globalhorizbak = globalhoriz;
    if (parallaxyscale != 65536)
        globalhoriz = mulscale16(globalhoriz-(ydimen>>1),parallaxyscale) + (ydimen>>1);
    globvis = globalpisibility;
    //globalorientation = 0L;
    if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));

    if (dastat == 0)
    {
        globalpal = sec->ceilingpal;
        globalpicnum = sec->ceilingpicnum;
        globalshade = (int)sec->ceilingshade;
        globalxpanning = (int)sec->ceilingxpanning;
        globalypanning = (int)sec->ceilingypanning;
        topptr = umost;
        botptr = uplc;
    }
    else
    {
        globalpal = sec->floorpal;
        globalpicnum = sec->floorpicnum;
        globalshade = (int)sec->floorshade;
        globalxpanning = (int)sec->floorxpanning;
        globalypanning = (int)sec->floorypanning;
        topptr = dplc;
        botptr = dmost;
    }

    if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
    if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)sectnum);
    globalshiftval = (picsiz[globalpicnum]>>4);
    if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++;
    globalshiftval = 32-globalshiftval;
    globalzd = (((tilesizy[globalpicnum]>>1)+parallaxyoffs)<<globalshiftval)+(globalypanning<<24);
    globalyscale = (8<<(globalshiftval-19));
    //if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd;

    k = 11 - (picsiz[globalpicnum]&15) - pskybits;
    x = -1;

    for (z=bunchfirst[bunch];z>=0;z=p2[z])
    {
        wallnum = thewall[z]; nextsectnum = wall[wallnum].nextsector;

        if (nextsectnum >= 0)  //else negative array access
        {
            if (dastat == 0) j = sector[nextsectnum].ceilingstat;
            else j = sector[nextsectnum].floorstat;
        }

        if ((nextsectnum < 0) || (wall[wallnum].cstat&32) || ((j&1) == 0))
        {
            if (x == -1) x = xb1[z];

            if (parallaxtype == 0)
            {
                n = mulscale16(xdimenrecip,viewingrange);
                for (j=xb1[z];j<=xb2[z];j++)
                    lplc[j] = (((mulscale23(j-halfxdimen,n)+globalang)&2047)>>k);
            }
            else
            {
                for (j=xb1[z];j<=xb2[z];j++)
                    lplc[j] = ((((int)radarang2[j]+globalang)&2047)>>k);
            }
            if (parallaxtype == 2)
            {
                n = mulscale16(xdimscale,viewingrange);
                for (j=xb1[z];j<=xb2[z];j++)
                    swplc[j] = mulscale14(sintable[((int)radarang2[j]+512)&2047],n);
            }
            else
                clearbuf(&swplc[xb1[z]],xb2[z]-xb1[z]+1,mulscale16(xdimscale,viewingrange));
        }
        else if (x >= 0)
        {
            l = globalpicnum; m = (picsiz[globalpicnum]&15);
            globalpicnum = l+pskyoff[lplc[x]>>m];

            if (((lplc[x]^lplc[xb1[z]-1])>>m) == 0)
                wallscan(x,xb1[z]-1,topptr,botptr,swplc,lplc);
            else
            {
                j = x;
                while (x < xb1[z])
                {
                    n = l+pskyoff[lplc[x]>>m];
                    if (n != globalpicnum)
                    {
                        wallscan(j,x-1,topptr,botptr,swplc,lplc);
                        j = x;
                        globalpicnum = n;
                    }
                    x++;
                }
                if (j < x)
                    wallscan(j,x-1,topptr,botptr,swplc,lplc);
            }

            globalpicnum = l;
            x = -1;
        }
    }

    if (x >= 0)
    {
        l = globalpicnum; m = (picsiz[globalpicnum]&15);
        globalpicnum = l+pskyoff[lplc[x]>>m];

        if (((lplc[x]^lplc[xb2[bunchlast[bunch]]])>>m) == 0)
            wallscan(x,xb2[bunchlast[bunch]],topptr,botptr,swplc,lplc);
        else
        {
            j = x;
            while (x <= xb2[bunchlast[bunch]])
            {
                n = l+pskyoff[lplc[x]>>m];
                if (n != globalpicnum)
                {
                    wallscan(j,x-1,topptr,botptr,swplc,lplc);
                    j = x;
                    globalpicnum = n;
                }
                x++;
            }
            if (j <= x)
                wallscan(j,x-1,topptr,botptr,swplc,lplc);
        }
        globalpicnum = l;
    }
    globalhoriz = globalhorizbak;
}


//
// drawalls (internal)
//
static void drawalls(int bunch)
{
    sectortype *sec, *nextsec;
    walltype *wal;
    int i, x, x1, x2, cz[5], fz[5];
    int z, wallnum, sectnum, nextsectnum;
    int startsmostwallcnt, startsmostcnt, gotswall;
    char andwstat1, andwstat2;

    z = bunchfirst[bunch];
    sectnum = thesector[z]; sec = &sector[sectnum];

    andwstat1 = 0xff; andwstat2 = 0xff;
    for (;z>=0;z=p2[z]) //uplc/dplc calculation
    {
        andwstat1 &= wallmost(uplc,z,sectnum,(char)0);
        andwstat2 &= wallmost(dplc,z,sectnum,(char)1);
    }

    if ((andwstat1&3) != 3)     //draw ceilings
    {
        if ((sec->ceilingstat&3) == 2)
            grouscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,0);
        else if ((sec->ceilingstat&1) == 0)
            ceilscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum);
        else
            parascan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,0,bunch);
    }
    if ((andwstat2&12) != 12)   //draw floors
    {
        if ((sec->floorstat&3) == 2)
            grouscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,1);
        else if ((sec->floorstat&1) == 0)
            florscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum);
        else
            parascan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,1,bunch);
    }

    //DRAW WALLS SECTION!
    for (z=bunchfirst[bunch];z>=0;z=p2[z])
    {
        x1 = xb1[z]; x2 = xb2[z];
        if (umost[x2] >= dmost[x2])
        {
            for (x=x1;x<x2;x++)
                if (umost[x] < dmost[x]) break;
            if (x >= x2)
            {
                smostwall[smostwallcnt] = z;
                smostwalltype[smostwallcnt] = 0;
                smostwallcnt++;
                continue;
            }
        }

        wallnum = thewall[z]; wal = &wall[wallnum];
        nextsectnum = wal->nextsector; nextsec = &sector[nextsectnum];

        gotswall = 0;

        startsmostwallcnt = smostwallcnt;
        startsmostcnt = smostcnt;

        if ((searchit == 2) && (searchx >= x1) && (searchx <= x2))
        {
            if (searchy <= uplc[searchx]) //ceiling
            {
                searchsector = sectnum; searchwall = wallnum;
                searchstat = 1; searchit = 1;
            }
            else if (searchy >= dplc[searchx]) //floor
            {
                searchsector = sectnum; searchwall = wallnum;
                searchstat = 2; searchit = 1;
            }
        }

        if (nextsectnum >= 0)
        {
            getzsofslope((short)sectnum,wal->x,wal->y,&cz[0],&fz[0]);
            getzsofslope((short)sectnum,wall[wal->point2].x,wall[wal->point2].y,&cz[1],&fz[1]);
            getzsofslope((short)nextsectnum,wal->x,wal->y,&cz[2],&fz[2]);
            getzsofslope((short)nextsectnum,wall[wal->point2].x,wall[wal->point2].y,&cz[3],&fz[3]);
            getzsofslope((short)nextsectnum,globalposx,globalposy,&cz[4],&fz[4]);

            if ((wal->cstat&48) == 16) maskwall[maskwallcnt++] = z;

            if (((sec->ceilingstat&1) == 0) || ((nextsec->ceilingstat&1) == 0))
            {
                if ((cz[2] <= cz[0]) && (cz[3] <= cz[1]))
                {
                    if (globparaceilclip)
                        for (x=x1;x<=x2;x++)
                            if (uplc[x] > umost[x])
                                if (umost[x] <= dmost[x])
                                {
                                    umost[x] = uplc[x];
                                    if (umost[x] > dmost[x]) numhits--;
                                }
                }
                else
                {
                    wallmost(dwall,z,nextsectnum,(char)0);
                    if ((cz[2] > fz[0]) || (cz[3] > fz[1]))
                        for (i=x1;i<=x2;i++) if (dwall[i] > dplc[i]) dwall[i] = dplc[i];

                    if ((searchit == 2) && (searchx >= x1) && (searchx <= x2))
                        if (searchy <= dwall[searchx]) //wall
                        {
                            searchsector = sectnum; searchwall = wallnum;
                            searchstat = 0; searchit = 1;
                        }

                    globalorientation = (int)wal->cstat;
                    globalpicnum = wal->picnum;
                    if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
                    globalxpanning = (int)wal->xpanning;
                    globalypanning = (int)wal->ypanning;
                    globalshiftval = (picsiz[globalpicnum]>>4);
                    if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++;
                    globalshiftval = 32-globalshiftval;
                    if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)wallnum+16384);
                    globalshade = (int)wal->shade;
                    globvis = globalvisibility;
                    if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
                    globalpal = (int)wal->pal;
                    if (palookup[globalpal] == NULL) globalpal = 0;    // JBF: fixes crash
                    globalyscale = (wal->yrepeat<<(globalshiftval-19));
                    if ((globalorientation&4) == 0)
                        globalzd = (((globalposz-nextsec->ceilingz)*globalyscale)<<8);
                    else
                        globalzd = (((globalposz-sec->ceilingz)*globalyscale)<<8);
                    globalzd += (globalypanning<<24);
                    if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd;

                    if (gotswall == 0) { gotswall = 1; prepwall(z,wal); }
                    wallscan(x1,x2,uplc,dwall,swall,lwall);

                    if ((cz[2] >= cz[0]) && (cz[3] >= cz[1]))
                    {
                        for (x=x1;x<=x2;x++)
                            if (dwall[x] > umost[x])
                                if (umost[x] <= dmost[x])
                                {
                                    umost[x] = dwall[x];
                                    if (umost[x] > dmost[x]) numhits--;
                                }
                    }
                    else
                    {
                        for (x=x1;x<=x2;x++)
                            if (umost[x] <= dmost[x])
                            {
                                i = max(uplc[x],dwall[x]);
                                if (i > umost[x])
                                {
                                    umost[x] = i;
                                    if (umost[x] > dmost[x]) numhits--;
                                }
                            }
                    }
                }
                if ((cz[2] < cz[0]) || (cz[3] < cz[1]) || (globalposz < cz[4]))
                {
                    i = x2-x1+1;
                    if (smostcnt+i < MAXYSAVES)
                    {
                        smoststart[smostwallcnt] = smostcnt;
                        smostwall[smostwallcnt] = z;
                        smostwalltype[smostwallcnt] = 1;   //1 for umost
                        smostwallcnt++;
                        copybufbyte(&umost[x1],&smost[smostcnt],i*sizeof(smost[0]));
                        smostcnt += i;
                    }
                }
            }
            if (((sec->floorstat&1) == 0) || ((nextsec->floorstat&1) == 0))
            {
                if ((fz[2] >= fz[0]) && (fz[3] >= fz[1]))
                {
                    if (globparaflorclip)
                        for (x=x1;x<=x2;x++)
                            if (dplc[x] < dmost[x])
                                if (umost[x] <= dmost[x])
                                {
                                    dmost[x] = dplc[x];
                                    if (umost[x] > dmost[x]) numhits--;
                                }
                }
                else
                {
                    wallmost(uwall,z,nextsectnum,(char)1);
                    if ((fz[2] < cz[0]) || (fz[3] < cz[1]))
                        for (i=x1;i<=x2;i++) if (uwall[i] < uplc[i]) uwall[i] = uplc[i];

                    if ((searchit == 2) && (searchx >= x1) && (searchx <= x2))
                        if (searchy >= uwall[searchx]) //wall
                        {
                            searchsector = sectnum; searchwall = wallnum;
                            if ((wal->cstat&2) > 0) searchwall = wal->nextwall;
                            searchstat = 0; searchit = 1;
                        }

                    if ((wal->cstat&2) > 0)
                    {
                        wallnum = wal->nextwall; wal = &wall[wallnum];
                        globalorientation = (int)wal->cstat;
                        globalpicnum = wal->picnum;
                        if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
                        globalxpanning = (int)wal->xpanning;
                        globalypanning = (int)wal->ypanning;
                        if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)wallnum+16384);
                        globalshade = (int)wal->shade;
                        globalpal = (int)wal->pal;
                        wallnum = thewall[z]; wal = &wall[wallnum];
                    }
                    else
                    {
                        globalorientation = (int)wal->cstat;
                        globalpicnum = wal->picnum;
                        if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
                        globalxpanning = (int)wal->xpanning;
                        globalypanning = (int)wal->ypanning;
                        if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)wallnum+16384);
                        globalshade = (int)wal->shade;
                        globalpal = (int)wal->pal;
                    }
                    if (palookup[globalpal] == NULL) globalpal = 0;    // JBF: fixes crash
                    globvis = globalvisibility;
                    if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
                    globalshiftval = (picsiz[globalpicnum]>>4);
                    if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++;
                    globalshiftval = 32-globalshiftval;
                    globalyscale = (wal->yrepeat<<(globalshiftval-19));
                    if ((globalorientation&4) == 0)
                        globalzd = (((globalposz-nextsec->floorz)*globalyscale)<<8);
                    else
                        globalzd = (((globalposz-sec->ceilingz)*globalyscale)<<8);
                    globalzd += (globalypanning<<24);
                    if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd;

                    if (gotswall == 0) { gotswall = 1; prepwall(z,wal); }
                    wallscan(x1,x2,uwall,dplc,swall,lwall);

                    if ((fz[2] <= fz[0]) && (fz[3] <= fz[1]))
                    {
                        for (x=x1;x<=x2;x++)
                            if (uwall[x] < dmost[x])
                                if (umost[x] <= dmost[x])
                                {
                                    dmost[x] = uwall[x];
                                    if (umost[x] > dmost[x]) numhits--;
                                }
                    }
                    else
                    {
                        for (x=x1;x<=x2;x++)
                            if (umost[x] <= dmost[x])
                            {
                                i = min(dplc[x],uwall[x]);
                                if (i < dmost[x])
                                {
                                    dmost[x] = i;
                                    if (umost[x] > dmost[x]) numhits--;
                                }
                            }
                    }
                }
                if ((fz[2] > fz[0]) || (fz[3] > fz[1]) || (globalposz > fz[4]))
                {
                    i = x2-x1+1;
                    if (smostcnt+i < MAXYSAVES)
                    {
                        smoststart[smostwallcnt] = smostcnt;
                        smostwall[smostwallcnt] = z;
                        smostwalltype[smostwallcnt] = 2;   //2 for dmost
                        smostwallcnt++;
                        copybufbyte(&dmost[x1],&smost[smostcnt],i*sizeof(smost[0]));
                        smostcnt += i;
                    }
                }
            }
            if (numhits < 0) return;
            if ((!(wal->cstat&32)) && ((gotsector[nextsectnum>>3]&pow2char[nextsectnum&7]) == 0))
            {
                if (umost[x2] < dmost[x2])
                    scansector(nextsectnum);
                else
                {
                    for (x=x1;x<x2;x++)
                        if (umost[x] < dmost[x])
                            { scansector(nextsectnum); break; }

                    //If can't see sector beyond, then cancel smost array and just
                    //store wall!
                    if (x == x2)
                    {
                        smostwallcnt = startsmostwallcnt;
                        smostcnt = startsmostcnt;
                        smostwall[smostwallcnt] = z;
                        smostwalltype[smostwallcnt] = 0;
                        smostwallcnt++;
                    }
                }
            }
        }
        if ((nextsectnum < 0) || (wal->cstat&32))   //White/1-way wall
        {
            globalorientation = (int)wal->cstat;
            if (nextsectnum < 0) globalpicnum = wal->picnum;
            else globalpicnum = wal->overpicnum;
            if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
            globalxpanning = (int)wal->xpanning;
            globalypanning = (int)wal->ypanning;
            if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)wallnum+16384);
            globalshade = (int)wal->shade;
            globvis = globalvisibility;
            if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
            globalpal = (int)wal->pal;
            if (palookup[globalpal] == NULL) globalpal = 0;    // JBF: fixes crash
            globalshiftval = (picsiz[globalpicnum]>>4);
            if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++;
            globalshiftval = 32-globalshiftval;
            globalyscale = (wal->yrepeat<<(globalshiftval-19));
            if (nextsectnum >= 0)
            {
                if ((globalorientation&4) == 0) globalzd = globalposz-nextsec->ceilingz;
                else globalzd = globalposz-sec->ceilingz;
            }
            else
            {
                if ((globalorientation&4) == 0) globalzd = globalposz-sec->ceilingz;
                else globalzd = globalposz-sec->floorz;
            }
            globalzd = ((globalzd*globalyscale)<<8) + (globalypanning<<24);
            if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd;

            if (gotswall == 0) { gotswall = 1; prepwall(z,wal); }
            wallscan(x1,x2,uplc,dplc,swall,lwall);

            for (x=x1;x<=x2;x++)
                if (umost[x] <= dmost[x])
                    { umost[x] = 1; dmost[x] = 0; numhits--; }
            smostwall[smostwallcnt] = z;
            smostwalltype[smostwallcnt] = 0;
            smostwallcnt++;

            if ((searchit == 2) && (searchx >= x1) && (searchx <= x2))
            {
                searchit = 1; searchsector = sectnum; searchwall = wallnum;
                if (nextsectnum < 0) searchstat = 0; else searchstat = 4;
            }
        }
    }
}


//
// drawvox
//
#ifdef SUPERBUILD
static void drawvox(int dasprx, int daspry, int dasprz, int dasprang,
                    int daxscale, int dayscale, char daindex,
                    signed char dashade, char dapal, int *daumost, int *dadmost)
{
    int i, j, k, x, y, syoff, ggxstart, ggystart, nxoff;
    int cosang, sinang, sprcosang, sprsinang, backx, backy, gxinc, gyinc;
    int daxsiz, daysiz, dazsiz, daxpivot, daypivot, dazpivot;
    int daxscalerecip, dayscalerecip, cnt, gxstart, gystart, odayscale;
    int l1, l2, /*slabxoffs,*/ xyvoxoffs, *longptr;
    intptr_t slabxoffs;
    int lx, rx, nx, ny, x1=0, y1=0, z1, x2=0, y2=0, z2, yplc, yinc=0;
    int yoff, xs=0, ys=0, xe, ye, xi=0, yi=0, cbackx, cbacky, dagxinc, dagyinc;
    short *shortptr;
    char *voxptr, *voxend, *davoxptr, oand, oand16, oand32;

    cosang = sintable[(globalang+512)&2047];
    sinang = sintable[globalang&2047];
    sprcosang = sintable[(dasprang+512)&2047];
    sprsinang = sintable[dasprang&2047];

    i = klabs(dmulscale6(dasprx-globalposx,cosang,daspry-globalposy,sinang));
    j = (int)(getpalookup((int)mulscale21(globvis,i),(int)dashade)<<8);
    setupdrawslab(ylookup[1],FP_OFF(palookup[dapal])+j);
    j = 1310720;
    j *= min(daxscale,dayscale); j >>= 6;  //New hacks (for sized-down voxels)
    for (k=0;k<MAXVOXMIPS;k++)
    {
        if (i < j) { i = k; break; }
        j <<= 1;
    }
    if (k >= MAXVOXMIPS) i = MAXVOXMIPS-1;

    if (novoxmips) i = 0;
    davoxptr = (char *)voxoff[daindex][i];
    if (!davoxptr && i > 0) { davoxptr = (char *)voxoff[daindex][0]; i = 0; }
    if (!davoxptr) return;

    if (voxscale[daindex] == 65536)
        { daxscale <<= (i+8); dayscale <<= (i+8); }
    else
    {
        daxscale = mulscale8(daxscale<<i,voxscale[daindex]);
        dayscale = mulscale8(dayscale<<i,voxscale[daindex]);
    }

    odayscale = dayscale;
    daxscale = mulscale16(daxscale,xyaspect);
    daxscale = scale(daxscale,xdimenscale,xdimen<<8);
    dayscale = scale(dayscale,mulscale16(xdimenscale,viewingrangerecip),xdimen<<8);

    daxscalerecip = (1<<30)/daxscale;
    dayscalerecip = (1<<30)/dayscale;

    longptr = (int *)davoxptr;
    daxsiz = B_LITTLE32(longptr[0]); daysiz = B_LITTLE32(longptr[1]); dazsiz = B_LITTLE32(longptr[2]);
    daxpivot = B_LITTLE32(longptr[3]); daypivot = B_LITTLE32(longptr[4]); dazpivot = B_LITTLE32(longptr[5]);
    davoxptr += (6<<2);

    x = mulscale16(globalposx-dasprx,daxscalerecip);
    y = mulscale16(globalposy-daspry,daxscalerecip);
    backx = ((dmulscale10(x,sprcosang,y,sprsinang)+daxpivot)>>8);
    backy = ((dmulscale10(y,sprcosang,x,-sprsinang)+daypivot)>>8);
    cbackx = min(max(backx,0),daxsiz-1);
    cbacky = min(max(backy,0),daysiz-1);

    sprcosang = mulscale14(daxscale,sprcosang);
    sprsinang = mulscale14(daxscale,sprsinang);

    x = (dasprx-globalposx) - dmulscale18(daxpivot,sprcosang,daypivot,-sprsinang);
    y = (daspry-globalposy) - dmulscale18(daypivot,sprcosang,daxpivot,sprsinang);

    cosang = mulscale16(cosang,dayscalerecip);
    sinang = mulscale16(sinang,dayscalerecip);

    gxstart = y*cosang - x*sinang;
    gystart = x*cosang + y*sinang;
    gxinc = dmulscale10(sprsinang,cosang,sprcosang,-sinang);
    gyinc = dmulscale10(sprcosang,cosang,sprsinang,sinang);

    x = 0; y = 0; j = max(daxsiz,daysiz);
    for (i=0;i<=j;i++)
    {
        ggxinc[i] = x; x += gxinc;
        ggyinc[i] = y; y += gyinc;
    }

    if ((klabs(globalposz-dasprz)>>10) >= klabs(odayscale)) return;
    syoff = divscale21(globalposz-dasprz,odayscale) + (dazpivot<<7);
    yoff = ((klabs(gxinc)+klabs(gyinc))>>1);
    longptr = (int *)davoxptr;
    xyvoxoffs = ((daxsiz+1)<<2);

    begindrawing(); //{{{

    for (cnt=0;cnt<8;cnt++)
    {
        switch (cnt)
        {
        case 0:
            xs = 0;        ys = 0;        xi = 1;  yi = 1;  break;
        case 1:
            xs = daxsiz-1; ys = 0;        xi = -1; yi = 1;  break;
        case 2:
            xs = 0;        ys = daysiz-1; xi = 1;  yi = -1; break;
        case 3:
            xs = daxsiz-1; ys = daysiz-1; xi = -1; yi = -1; break;
        case 4:
            xs = 0;        ys = cbacky;   xi = 1;  yi = 2;  break;
        case 5:
            xs = daxsiz-1; ys = cbacky;   xi = -1; yi = 2;  break;
        case 6:
            xs = cbackx;   ys = 0;        xi = 2;  yi = 1;  break;
        case 7:
            xs = cbackx;   ys = daysiz-1; xi = 2;  yi = -1; break;
        }
        xe = cbackx; ye = cbacky;
        if (cnt < 4)
        {
            if ((xi < 0) && (xe >= xs)) continue;
            if ((xi > 0) && (xe <= xs)) continue;
            if ((yi < 0) && (ye >= ys)) continue;
            if ((yi > 0) && (ye <= ys)) continue;
        }
        else
        {
            if ((xi < 0) && (xe > xs)) continue;
            if ((xi > 0) && (xe < xs)) continue;
            if ((yi < 0) && (ye > ys)) continue;
            if ((yi > 0) && (ye < ys)) continue;
            xe += xi; ye += yi;
        }

        i = ksgn(ys-backy)+ksgn(xs-backx)*3+4;
        switch (i)
        {
        case 6:
        case 7:
            x1 = 0; y1 = 0; break;
        case 8:
        case 5:
            x1 = gxinc; y1 = gyinc; break;
        case 0:
        case 3:
            x1 = gyinc; y1 = -gxinc; break;
        case 2:
        case 1:
            x1 = gxinc+gyinc; y1 = gyinc-gxinc; break;
        }
        switch (i)
        {
        case 2:
        case 5:
            x2 = 0; y2 = 0; break;
        case 0:
        case 1:
            x2 = gxinc; y2 = gyinc; break;
        case 8:
        case 7:
            x2 = gyinc; y2 = -gxinc; break;
        case 6:
        case 3:
            x2 = gxinc+gyinc; y2 = gyinc-gxinc; break;
        }
        oand = pow2char[(xs<backx)+0]+pow2char[(ys<backy)+2];
        oand16 = oand+16;
        oand32 = oand+32;

        if (yi > 0) { dagxinc = gxinc; dagyinc = mulscale16(gyinc,viewingrangerecip); }
        else { dagxinc = -gxinc; dagyinc = -mulscale16(gyinc,viewingrangerecip); }

        //Fix for non 90 degree viewing ranges
        nxoff = mulscale16(x2-x1,viewingrangerecip);
        x1 = mulscale16(x1,viewingrangerecip);

        ggxstart = gxstart+ggyinc[ys];
        ggystart = gystart-ggxinc[ys];

        for (x=xs;x!=xe;x+=xi)
        {
            slabxoffs = (intptr_t)&davoxptr[B_LITTLE32(longptr[x])];
            shortptr = (short *)&davoxptr[((x*(daysiz+1))<<1)+xyvoxoffs];

            nx = mulscale16(ggxstart+ggxinc[x],viewingrangerecip)+x1;
            ny = ggystart+ggyinc[x];
            for (y=ys;y!=ye;y+=yi,nx+=dagyinc,ny-=dagxinc)
            {
                if ((ny <= nytooclose) || (ny >= nytoofar)) continue;
                voxptr = (char *)(B_LITTLE16(shortptr[y])+slabxoffs);
                voxend = (char *)(B_LITTLE16(shortptr[y+1])+slabxoffs);
                if (voxptr == voxend) continue;

                lx = mulscale32(nx>>3,distrecip[(ny+y1)>>14])+halfxdimen;
                if (lx < 0) lx = 0;
                rx = mulscale32((nx+nxoff)>>3,distrecip[(ny+y2)>>14])+halfxdimen;
                if (rx > xdimen) rx = xdimen;
                if (rx <= lx) continue;
                rx -= lx;

                l1 = distrecip[(ny-yoff)>>14];
                l2 = distrecip[(ny+yoff)>>14];
                for (;voxptr<voxend;voxptr+=voxptr[1]+3)
                {
                    j = (voxptr[0]<<15)-syoff;
                    if (j < 0)
                    {
                        k = j+(voxptr[1]<<15);
                        if (k < 0)
                        {
                            if ((voxptr[2]&oand32) == 0) continue;
                            z2 = mulscale32(l2,k) + globalhoriz;     //Below slab
                        }
                        else
                        {
                            if ((voxptr[2]&oand) == 0) continue;    //Middle of slab
                            z2 = mulscale32(l1,k) + globalhoriz;
                        }
                        z1 = mulscale32(l1,j) + globalhoriz;
                    }
                    else
                    {
                        if ((voxptr[2]&oand16) == 0) continue;
                        z1 = mulscale32(l2,j) + globalhoriz;        //Above slab
                        z2 = mulscale32(l1,j+(voxptr[1]<<15)) + globalhoriz;
                    }

                    if (voxptr[1] == 1)
                    {
                        yplc = 0; yinc = 0;
                        if (z1 < daumost[lx]) z1 = daumost[lx];
                    }
                    else
                    {
                        if (z2-z1 >= 1024) yinc = divscale16(voxptr[1],z2-z1);
                        else if (z2 > z1) yinc = (lowrecip[z2-z1]*voxptr[1]>>8);
                        if (z1 < daumost[lx]) { yplc = yinc*(daumost[lx]-z1); z1 = daumost[lx]; }
                        else yplc = 0;
                    }
                    if (z2 > dadmost[lx]) z2 = dadmost[lx];
                    z2 -= z1; if (z2 <= 0) continue;

                    drawslab(rx,yplc,z2,yinc,(intptr_t)&voxptr[3],ylookup[z1]+lx+frameoffset);
                }
            }
        }
    }

    enddrawing();   //}}}
}
#endif

//
// drawsprite (internal)
//
static void drawsprite(int snum)
{
    spritetype *tspr;
    sectortype *sec;
    int startum, startdm, sectnum, xb, yp, cstat;
    int siz, xsiz, ysiz, xoff, yoff, xspan, yspan;
    int x1, y1, x2, y2, lx, rx, dalx2, darx2, i, j, k, x, linum, linuminc;
    int yinc, z, z1, z2, xp1, yp1, xp2, yp2;
    int xv, yv, top, topinc, bot, botinc, hplc, hinc;
    int cosang, sinang, dax, day, lpoint, lmax, rpoint, rmax, dax1, dax2, y;
    int npoints, npoints2, zz, t, zsgn, zzsgn, *longptr;
    int tilenum, vtilenum = 0, spritenum;
    char swapped, daclip;

    //============================================================================= //POLYMOST BEGINS
#ifdef POLYMOST
    if (rendmode == 3)
    {
        polymost_drawsprite(snum);
# ifdef USE_OPENGL
        bglDisable(GL_POLYGON_OFFSET_FILL);
# endif
        return;
    }
# ifdef POLYMER
    if (rendmode == 4)
    {
        bglEnable(GL_ALPHA_TEST);
        bglEnable(GL_BLEND);

        polymer_drawsprite(snum);

        bglDisable(GL_BLEND);
        bglDisable(GL_ALPHA_TEST);
        return;
    }
# endif
#endif
    //============================================================================= //POLYMOST ENDS

    tspr = tspriteptr[snum];

    xb = spritesx[snum];
    yp = spritesy[snum];
    tilenum = tspr->picnum;
    spritenum = tspr->owner;
    cstat = tspr->cstat;

#ifdef SUPERBUILD
    if ((cstat&48)==48) vtilenum = tilenum; // if the game wants voxels, it gets voxels
    else if ((cstat&48)!=48 && (usevoxels) && (tiletovox[tilenum] != -1)
#if defined(POLYMOST) && defined(USE_OPENGL)
             && (!(spriteext[tspr->owner].flags&SPREXT_NOTMD))
#endif
            )
    {
        vtilenum = tiletovox[tilenum];
        cstat |= 48;
    }
#endif

    if ((cstat&48) != 48)
    {
        if (picanm[tilenum]&192) tilenum += animateoffs(tilenum,spritenum+32768);
        if ((tilesizx[tilenum] <= 0) || (tilesizy[tilenum] <= 0) || (spritenum < 0))
            return;
    }
    if ((tspr->xrepeat <= 0) || (tspr->yrepeat <= 0)) return;

    sectnum = tspr->sectnum; sec = &sector[sectnum];
    globalpal = tspr->pal;
    if (palookup[globalpal] == NULL) globalpal = 0;    // JBF: fixes null-pointer crash
    globalshade = tspr->shade;
    if (cstat&2)
    {
        if (cstat&512) settransreverse(); else settransnormal();
    }

    xoff = (int)((signed char)((picanm[tilenum]>>8)&255))+((int)tspr->xoffset);
    yoff = (int)((signed char)((picanm[tilenum]>>16)&255))+((int)tspr->yoffset);

    if ((cstat&48) == 0)
    {
        if (yp <= (4<<8)) return;

        siz = divscale19(xdimenscale,yp);

        xv = mulscale16(((int)tspr->xrepeat)<<16,xyaspect);

        xspan = tilesizx[tilenum];
        yspan = tilesizy[tilenum];
        xsiz = mulscale30(siz,xv*xspan);
        ysiz = mulscale14(siz,tspr->yrepeat*yspan);

        if (((tilesizx[tilenum]>>11) >= xsiz) || (yspan >= (ysiz>>1)))
            return;  //Watch out for divscale overflow

        x1 = xb-(xsiz>>1);
        if (xspan&1) x1 += mulscale31(siz,xv);  //Odd xspans
        i = mulscale30(siz,xv*xoff);
        if ((cstat&4) == 0) x1 -= i; else x1 += i;

        y1 = mulscale16(tspr->z-globalposz,siz);
        y1 -= mulscale14(siz,tspr->yrepeat*yoff);
        y1 += (globalhoriz<<8)-ysiz;
        if (cstat&128)
        {
            y1 += (ysiz>>1);
            if (yspan&1) y1 += mulscale15(siz,tspr->yrepeat);  //Odd yspans
        }

        x2 = x1+xsiz-1;
        y2 = y1+ysiz-1;
        if ((y1|255) >= (y2|255)) return;

        lx = (x1>>8)+1; if (lx < 0) lx = 0;
        rx = (x2>>8); if (rx >= xdimen) rx = xdimen-1;
        if (lx > rx) return;

        yinc = divscale32(yspan,ysiz);

        if ((sec->ceilingstat&3) == 0)
            startum = globalhoriz+mulscale24(siz,sec->ceilingz-globalposz)-1;
        else
            startum = 0;
        if ((sec->floorstat&3) == 0)
            startdm = globalhoriz+mulscale24(siz,sec->floorz-globalposz)+1;
        else
            startdm = 0x7fffffff;
        if ((y1>>8) > startum) startum = (y1>>8);
        if ((y2>>8) < startdm) startdm = (y2>>8);

        if (startum < -32768) startum = -32768;
        if (startdm > 32767) startdm = 32767;
        if (startum >= startdm) return;

        if ((cstat&4) == 0)
        {
            linuminc = divscale24(xspan,xsiz);
            linum = mulscale8((lx<<8)-x1,linuminc);
        }
        else
        {
            linuminc = -divscale24(xspan,xsiz);
            linum = mulscale8((lx<<8)-x2,linuminc);
        }
        if ((cstat&8) > 0)
        {
            yinc = -yinc;
            i = y1; y1 = y2; y2 = i;
        }

        for (x=lx;x<=rx;x++)
        {
            uwall[x] = max(startumost[x+windowx1]-windowy1,(short)startum);
            dwall[x] = min(startdmost[x+windowx1]-windowy1,(short)startdm);
        }
        daclip = 0;
        for (i=smostwallcnt-1;i>=0;i--)
        {
            if (smostwalltype[i]&daclip) continue;
            j = smostwall[i];
            if ((xb1[j] > rx) || (xb2[j] < lx)) continue;
            if ((yp <= yb1[j]) && (yp <= yb2[j])) continue;
            if (spritewallfront(tspr,(int)thewall[j]) && ((yp <= yb1[j]) || (yp <= yb2[j]))) continue;

            dalx2 = max(xb1[j],lx); darx2 = min(xb2[j],rx);

            switch (smostwalltype[i])
            {
            case 0:
                if (dalx2 <= darx2)
                {
                    if ((dalx2 == lx) && (darx2 == rx)) return;
                    //clearbufbyte(&dwall[dalx2],(darx2-dalx2+1)*sizeof(dwall[0]),0L);
                    for (k=dalx2; k<=darx2; k++) dwall[k] = 0;
                }
                break;
            case 1:
                k = smoststart[i] - xb1[j];
                for (x=dalx2;x<=darx2;x++)
                    if (smost[k+x] > uwall[x]) uwall[x] = smost[k+x];
                if ((dalx2 == lx) && (darx2 == rx)) daclip |= 1;
                break;
            case 2:
                k = smoststart[i] - xb1[j];
                for (x=dalx2;x<=darx2;x++)
                    if (smost[k+x] < dwall[x]) dwall[x] = smost[k+x];
                if ((dalx2 == lx) && (darx2 == rx)) daclip |= 2;
                break;
            }
        }

        if (uwall[rx] >= dwall[rx])
        {
            for (x=lx;x<rx;x++)
                if (uwall[x] < dwall[x]) break;
            if (x == rx) return;
        }

        //sprite
        if ((searchit >= 1) && (searchx >= lx) && (searchx <= rx))
            if ((searchy >= uwall[searchx]) && (searchy < dwall[searchx]))
            {
                searchsector = sectnum; searchwall = spritenum;
                searchstat = 3; searchit = 1;
            }

        z2 = tspr->z - ((yoff*tspr->yrepeat)<<2);
        if (cstat&128)
        {
            z2 += ((yspan*tspr->yrepeat)<<1);
            if (yspan&1) z2 += (tspr->yrepeat<<1);        //Odd yspans
        }
        z1 = z2 - ((yspan*tspr->yrepeat)<<2);

        globalorientation = 0;
        globalpicnum = tilenum;
        if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
        globalxpanning = 0L;
        globalypanning = 0L;
        globvis = globalvisibility;
        if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
        globalshiftval = (picsiz[globalpicnum]>>4);
        if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++;
        globalshiftval = 32-globalshiftval;
        globalyscale = divscale(512,tspr->yrepeat,globalshiftval-19);
        globalzd = (((globalposz-z1)*globalyscale)<<8);
        if ((cstat&8) > 0)
        {
            globalyscale = -globalyscale;
            globalzd = (((globalposz-z2)*globalyscale)<<8);
        }

        qinterpolatedown16((intptr_t)&lwall[lx],rx-lx+1,linum,linuminc);
        clearbuf(&swall[lx],rx-lx+1,mulscale19(yp,xdimscale));

        if ((cstat&2) == 0)
            maskwallscan(lx,rx,uwall,dwall,swall,lwall);
        else
            transmaskwallscan(lx,rx);
    }
    else if ((cstat&48) == 16)
    {
        if ((cstat&4) > 0) xoff = -xoff;
        if ((cstat&8) > 0) yoff = -yoff;

        xspan = tilesizx[tilenum]; yspan = tilesizy[tilenum];
        xv = tspr->xrepeat*sintable[(tspr->ang+2560+1536)&2047];
        yv = tspr->xrepeat*sintable[(tspr->ang+2048+1536)&2047];
        i = (xspan>>1)+xoff;
        x1 = tspr->x-globalposx-mulscale16(xv,i); x2 = x1+mulscale16(xv,xspan);
        y1 = tspr->y-globalposy-mulscale16(yv,i); y2 = y1+mulscale16(yv,xspan);

        yp1 = dmulscale6(x1,cosviewingrangeglobalang,y1,sinviewingrangeglobalang);
        yp2 = dmulscale6(x2,cosviewingrangeglobalang,y2,sinviewingrangeglobalang);
        if ((yp1 <= 0) && (yp2 <= 0)) return;
        xp1 = dmulscale6(y1,cosglobalang,-x1,singlobalang);
        xp2 = dmulscale6(y2,cosglobalang,-x2,singlobalang);

        x1 += globalposx; y1 += globalposy;
        x2 += globalposx; y2 += globalposy;

        swapped = 0;
        if (dmulscale32(xp1,yp2,-xp2,yp1) >= 0)  //If wall's NOT facing you
        {
            if ((cstat&64) != 0) return;
            i = xp1, xp1 = xp2, xp2 = i;
            i = yp1, yp1 = yp2, yp2 = i;
            i = x1, x1 = x2, x2 = i;
            i = y1, y1 = y2, y2 = i;
            swapped = 1;
        }

        if (xp1 >= -yp1)
        {
            if (xp1 > yp1) return;

            if (yp1 == 0) return;
            xb1[MAXWALLSB-1] = halfxdimen + scale(xp1,halfxdimen,yp1);
            if (xp1 >= 0) xb1[MAXWALLSB-1]++;   //Fix for SIGNED divide
            if (xb1[MAXWALLSB-1] >= xdimen) xb1[MAXWALLSB-1] = xdimen-1;
            yb1[MAXWALLSB-1] = yp1;
        }
        else
        {
            if (xp2 < -yp2) return;
            xb1[MAXWALLSB-1] = 0;
            i = yp1-yp2+xp1-xp2;
            if (i == 0) return;
            yb1[MAXWALLSB-1] = yp1 + scale(yp2-yp1,xp1+yp1,i);
        }
        if (xp2 <= yp2)
        {
            if (xp2 < -yp2) return;

            if (yp2 == 0) return;
            xb2[MAXWALLSB-1] = halfxdimen + scale(xp2,halfxdimen,yp2) - 1;
            if (xp2 >= 0) xb2[MAXWALLSB-1]++;   //Fix for SIGNED divide
            if (xb2[MAXWALLSB-1] >= xdimen) xb2[MAXWALLSB-1] = xdimen-1;
            yb2[MAXWALLSB-1] = yp2;
        }
        else
        {
            if (xp1 > yp1) return;

            xb2[MAXWALLSB-1] = xdimen-1;
            i = xp2-xp1+yp1-yp2;
            if (i == 0) return;
            yb2[MAXWALLSB-1] = yp1 + scale(yp2-yp1,yp1-xp1,i);
        }

        if ((yb1[MAXWALLSB-1] < 256) || (yb2[MAXWALLSB-1] < 256) || (xb1[MAXWALLSB-1] > xb2[MAXWALLSB-1]))
            return;

        topinc = -mulscale10(yp1,xspan);
        top = (((mulscale10(xp1,xdimen) - mulscale9(xb1[MAXWALLSB-1]-halfxdimen,yp1))*xspan)>>3);
        botinc = ((yp2-yp1)>>8);
        bot = mulscale11(xp1-xp2,xdimen) + mulscale2(xb1[MAXWALLSB-1]-halfxdimen,botinc);

        j = xb2[MAXWALLSB-1]+3;
        z = mulscale20(top,krecipasm(bot));
        lwall[xb1[MAXWALLSB-1]] = (z>>8);
        for (x=xb1[MAXWALLSB-1]+4;x<=j;x+=4)
        {
            top += topinc; bot += botinc;
            zz = z; z = mulscale20(top,krecipasm(bot));
            lwall[x] = (z>>8);
            i = ((z+zz)>>1);
            lwall[x-2] = (i>>8);
            lwall[x-3] = ((i+zz)>>9);
            lwall[x-1] = ((i+z)>>9);
        }

        if (lwall[xb1[MAXWALLSB-1]] < 0) lwall[xb1[MAXWALLSB-1]] = 0;
        if (lwall[xb2[MAXWALLSB-1]] >= xspan) lwall[xb2[MAXWALLSB-1]] = xspan-1;

        if ((swapped^((cstat&4)>0)) > 0)
        {
            j = xspan-1;
            for (x=xb1[MAXWALLSB-1];x<=xb2[MAXWALLSB-1];x++)
                lwall[x] = j-lwall[x];
        }

        rx1[MAXWALLSB-1] = xp1; ry1[MAXWALLSB-1] = yp1;
        rx2[MAXWALLSB-1] = xp2; ry2[MAXWALLSB-1] = yp2;

        hplc = divscale19(xdimenscale,yb1[MAXWALLSB-1]);
        hinc = divscale19(xdimenscale,yb2[MAXWALLSB-1]);
        hinc = (hinc-hplc)/(xb2[MAXWALLSB-1]-xb1[MAXWALLSB-1]+1);

        z2 = tspr->z - ((yoff*tspr->yrepeat)<<2);
        if (cstat&128)
        {
            z2 += ((yspan*tspr->yrepeat)<<1);
            if (yspan&1) z2 += (tspr->yrepeat<<1);        //Odd yspans
        }
        z1 = z2 - ((yspan*tspr->yrepeat)<<2);

        globalorientation = 0;
        globalpicnum = tilenum;
        if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0;
        globalxpanning = 0L;
        globalypanning = 0L;
        globvis = globalvisibility;
        if (sec->visibility != 0) globvis = mulscale4(globvis,(int)((unsigned char)(sec->visibility+16)));
        globalshiftval = (picsiz[globalpicnum]>>4);
        if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++;
        globalshiftval = 32-globalshiftval;
        globalyscale = divscale(512,tspr->yrepeat,globalshiftval-19);
        globalzd = (((globalposz-z1)*globalyscale)<<8);
        if ((cstat&8) > 0)
        {
            globalyscale = -globalyscale;
            globalzd = (((globalposz-z2)*globalyscale)<<8);
        }

        if (((sec->ceilingstat&1) == 0) && (z1 < sec->ceilingz))
            z1 = sec->ceilingz;
        if (((sec->floorstat&1) == 0) && (z2 > sec->floorz))
            z2 = sec->floorz;

        owallmost(uwall,(int)(MAXWALLSB-1),z1-globalposz);
        owallmost(dwall,(int)(MAXWALLSB-1),z2-globalposz);
        for (i=xb1[MAXWALLSB-1];i<=xb2[MAXWALLSB-1];i++)
            { swall[i] = (krecipasm(hplc)<<2); hplc += hinc; }

        for (i=smostwallcnt-1;i>=0;i--)
        {
            j = smostwall[i];

            if ((xb1[j] > xb2[MAXWALLSB-1]) || (xb2[j] < xb1[MAXWALLSB-1])) continue;

            dalx2 = xb1[j]; darx2 = xb2[j];
            if (max(yb1[MAXWALLSB-1],yb2[MAXWALLSB-1]) > min(yb1[j],yb2[j]))
            {
                if (min(yb1[MAXWALLSB-1],yb2[MAXWALLSB-1]) > max(yb1[j],yb2[j]))
                {
                    x = 0x80000000;
                }
                else
                {
                    x = thewall[j]; xp1 = wall[x].x; yp1 = wall[x].y;
                    x = wall[x].point2; xp2 = wall[x].x; yp2 = wall[x].y;

                    z1 = (xp2-xp1)*(y1-yp1) - (yp2-yp1)*(x1-xp1);
                    z2 = (xp2-xp1)*(y2-yp1) - (yp2-yp1)*(x2-xp1);
                    if ((z1^z2) >= 0)
                        x = (z1+z2);
                    else
                    {
                        z1 = (x2-x1)*(yp1-y1) - (y2-y1)*(xp1-x1);
                        z2 = (x2-x1)*(yp2-y1) - (y2-y1)*(xp2-x1);

                        if ((z1^z2) >= 0)
                            x = -(z1+z2);
                        else
                        {
                            if ((xp2-xp1)*(tspr->y-yp1) == (tspr->x-xp1)*(yp2-yp1))
                            {
                                if (wall[thewall[j]].nextsector == tspr->sectnum)
                                    x = 0x80000000;
                                else
                                    x = 0x7fffffff;
                            }
                            else
                            {
                                //INTERSECTION!
                                x = (xp1-globalposx) + scale(xp2-xp1,z1,z1-z2);
                                y = (yp1-globalposy) + scale(yp2-yp1,z1,z1-z2);

                                yp1 = dmulscale14(x,cosglobalang,y,singlobalang);
                                if (yp1 > 0)
                                {
                                    xp1 = dmulscale14(y,cosglobalang,-x,singlobalang);

                                    x = halfxdimen + scale(xp1,halfxdimen,yp1);
                                    if (xp1 >= 0) x++;   //Fix for SIGNED divide

                                    if (z1 < 0)
                                        { if (dalx2 < x) dalx2 = x; }
                                    else
                                        { if (darx2 > x) darx2 = x; }
                                    x = 0x80000001;
                                }
                                else
                                    x = 0x7fffffff;
                            }
                        }
                    }
                }
                if (x < 0)
                {
                    if (dalx2 < xb1[MAXWALLSB-1]) dalx2 = xb1[MAXWALLSB-1];
                    if (darx2 > xb2[MAXWALLSB-1]) darx2 = xb2[MAXWALLSB-1];
                    switch (smostwalltype[i])
                    {
                    case 0:
                        if (dalx2 <= darx2)
                        {
                            if ((dalx2 == xb1[MAXWALLSB-1]) && (darx2 == xb2[MAXWALLSB-1])) return;
                            //clearbufbyte(&dwall[dalx2],(darx2-dalx2+1)*sizeof(dwall[0]),0L);
                            for (k=dalx2; k<=darx2; k++) dwall[k] = 0;
                        }
                        break;
                    case 1:
                        k = smoststart[i] - xb1[j];
                        for (x=dalx2;x<=darx2;x++)
                            if (smost[k+x] > uwall[x]) uwall[x] = smost[k+x];
                        break;
                    case 2:
                        k = smoststart[i] - xb1[j];
                        for (x=dalx2;x<=darx2;x++)
                            if (smost[k+x] < dwall[x]) dwall[x] = smost[k+x];
                        break;
                    }
                }
            }
        }

        //sprite
        if ((searchit >= 1) && (searchx >= xb1[MAXWALLSB-1]) && (searchx <= xb2[MAXWALLSB-1]))
            if ((searchy >= uwall[searchx]) && (searchy <= dwall[searchx]))
            {
                searchsector = sectnum; searchwall = spritenum;
                searchstat = 3; searchit = 1;
            }

        if ((cstat&2) == 0)
        {
            maskwallscan(xb1[MAXWALLSB-1],xb2[MAXWALLSB-1],uwall,dwall,swall,lwall);
        }
        else
        {
            transmaskwallscan(xb1[MAXWALLSB-1],xb2[MAXWALLSB-1]);
        }
    }
    else if ((cstat&48) == 32)
    {
        if ((cstat&64) != 0)
            if ((globalposz > tspr->z) == ((cstat&8)==0))
                return;

        if ((cstat&4) > 0) xoff = -xoff;
        if ((cstat&8) > 0) yoff = -yoff;
        xspan = tilesizx[tilenum];
        yspan = tilesizy[tilenum];

        //Rotate center point
        dax = tspr->x-globalposx;
        day = tspr->y-globalposy;
        rzi[0] = dmulscale10(cosglobalang,dax,singlobalang,day);
        rxi[0] = dmulscale10(cosglobalang,day,-singlobalang,dax);

        //Get top-left corner
        i = ((tspr->ang+2048-globalang)&2047);
        cosang = sintable[(i+512)&2047]; sinang = sintable[i];
        dax = ((xspan>>1)+xoff)*tspr->xrepeat;
        day = ((yspan>>1)+yoff)*tspr->yrepeat;
        rzi[0] += dmulscale12(sinang,dax,cosang,day);
        rxi[0] += dmulscale12(sinang,day,-cosang,dax);

        //Get other 3 corners
        dax = xspan*tspr->xrepeat;
        day = yspan*tspr->yrepeat;
        rzi[1] = rzi[0]-mulscale12(sinang,dax);
        rxi[1] = rxi[0]+mulscale12(cosang,dax);
        dax = -mulscale12(cosang,day);
        day = -mulscale12(sinang,day);
        rzi[2] = rzi[1]+dax; rxi[2] = rxi[1]+day;
        rzi[3] = rzi[0]+dax; rxi[3] = rxi[0]+day;

        //Put all points on same z
        ryi[0] = scale((tspr->z-globalposz),yxaspect,320<<8);
        if (ryi[0] == 0) return;
        ryi[1] = ryi[2] = ryi[3] = ryi[0];

        if ((cstat&4) == 0)
            { z = 0; z1 = 1; z2 = 3; }
        else
            { z = 1; z1 = 0; z2 = 2; }

        dax = rzi[z1]-rzi[z]; day = rxi[z1]-rxi[z];
        bot = dmulscale8(dax,dax,day,day);
        if (((klabs(dax)>>13) >= bot) || ((klabs(day)>>13) >= bot)) return;
        globalx1 = divscale18(dax,bot);
        globalx2 = divscale18(day,bot);

        dax = rzi[z2]-rzi[z]; day = rxi[z2]-rxi[z];
        bot = dmulscale8(dax,dax,day,day);
        if (((klabs(dax)>>13) >= bot) || ((klabs(day)>>13) >= bot)) return;
        globaly1 = divscale18(dax,bot);
        globaly2 = divscale18(day,bot);

        //Calculate globals for hline texture mapping function
        globalxpanning = (rxi[z]<<12);
        globalypanning = (rzi[z]<<12);
        globalzd = (ryi[z]<<12);

        rzi[0] = mulscale16(rzi[0],viewingrange);
        rzi[1] = mulscale16(rzi[1],viewingrange);
        rzi[2] = mulscale16(rzi[2],viewingrange);
        rzi[3] = mulscale16(rzi[3],viewingrange);

        if