code:
// "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 (jf@jonof.id.au)
// by the EDuke32 team (development@voidpoint.com)

#include "build.h"
#include "editor.h"

int32_t editorgridextent = 131072;

////////// editor side view //////////
int32_t m32_sideview = 0;
int32_t m32_sideelev = 256;  // elevation in BUILD degrees, 0..512
int16_t m32_sideang = 200;  // azimuth, 0..2047

int32_t m32_sidecos, m32_sidesin;
int32_t m32_swcnt;
int32_t m32_wallscreenxy[MAXWALLS][2];
int16_t m32_wallsprite[MAXWALLS+MAXSPRITES];
static int32_t m32_sidedist[MAXWALLS+MAXSPRITES];
static vec3_t m32_viewplane;

static void drawpixel_safe(void *s, char a)
{
#if defined __GNUC__
    if (__builtin_expect((intptr_t) s >= frameplace && (intptr_t) s < frameplace+bytesperline*ydim, 1))
#else
    if ((intptr_t) s >= frameplace && (intptr_t) s < frameplace+bytesperline*ydim)
#endif
        drawpixel(s, a);
#ifdef DEBUGGINGAIDS
    else
    {
        const char c = editorcolors[15];

        drawpixel((intptr_t *) frameplace, c);
        drawpixel((intptr_t *) frameplace+1, c);
        drawpixel((intptr_t *) frameplace+2, c);
        drawpixel((intptr_t *) frameplace+bytesperline, c);
        drawpixel((intptr_t *) frameplace+bytesperline+1, c);
        drawpixel((intptr_t *) frameplace+bytesperline+2, c);
        drawpixel((intptr_t *) frameplace+2*bytesperline, c);
        drawpixel((intptr_t *) frameplace+2*bytesperline+1, c);
        drawpixel((intptr_t *) frameplace+2*bytesperline+2, c);
    }
#endif
}

//
// plotpixel
//
void plotpixel(int32_t x, int32_t y, char col)
{
#if defined USE_OPENGL && !defined EDUKE32_GLES
    if (videoGetRenderMode() >= REND_POLYMOST && in3dmode())
    {
        palette_t p = paletteGetColor(col);
        buildgl_setEnabled(GL_SCISSOR_TEST);
        glScissor(x,ydim-y+1,1,1);
        glClearColor((float)p.r*(1.0f/255.0f),(float)p.g*(1.0f/255.0f),(float)p.b*(1.0f)/255.0f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(0.0f,0.0f,0.0f,1.0f); // XXX: there must be a better way
        buildgl_setDisabled(GL_SCISSOR_TEST);
        return;
    }
#endif

    videoBeginDrawing(); //{{{
    drawpixel_safe((void *) (ylookup[y]+x+frameplace), col);
    videoEndDrawing();   //}}}
}

void plotlines2d(const int32_t *xx, const int32_t *yy, int32_t numpoints, int col)
{
    int32_t i;

#ifdef USE_OPENGL
    if (videoGetRenderMode() >= REND_POLYMOST && in3dmode())
    {
        palette_t p = paletteGetColor(col);

        polymost_useColorOnly(true);
        glBegin(GL_LINE_STRIP);

        glColor4ub(p.r, p.g, p.b, 1);

        for (i=0; i<numpoints; i++)
            glVertex2i(xx[i], yy[i]);

        glEnd();
        polymost_useColorOnly(false);
        return;
    }
#endif
    {
        int32_t odrawlinepat = drawlinepat;
        drawlinepat = 0xffffffff;

        videoBeginDrawing();
        for (i=0; i<numpoints-1; i++)
            editorDraw2dLine(xx[i], yy[i], xx[i+1], yy[i+1], col);
        videoEndDrawing();

        drawlinepat = odrawlinepat;
    }
}

//
// drawline256
//
#ifdef USE_OPENGL
static void drawlinegl(int32_t x1, int32_t y1, int32_t x2, int32_t y2, palette_t p)
{
    //        setpolymost2dview();	// JBF 20040205: more efficient setup

    int const dx = x2-x1;
    int const dy = y2-y1;

    if (dx >= 0)
    {
        if ((x1 >= wx2) || (x2 < wx1)) return;
        if (x1 < wx1) y1 += scale(wx1-x1, dy, dx), x1 = wx1;
        if (x2 > wx2) y2 += scale(wx2-x2, dy, dx), x2 = wx2;
    }
    else
    {
        if ((x2 >= wx2) || (x1 < wx1)) return;
        if (x2 < wx1) y2 += scale(wx1-x2, dy, dx), x2 = wx1;
        if (x1 > wx2) y1 += scale(wx2-x1, dy, dx), x1 = wx2;
    }
    if (dy >= 0)
    {
        if ((y1 >= wy2) || (y2 < wy1)) return;
        if (y1 < wy1) x1 += scale(wy1-y1, dx, dy), y1 = wy1;
        if (y2 > wy2) x2 += scale(wy2-y2, dx, dy), y2 = wy2;
    }
    else
    {
        if ((y2 >= wy2) || (y1 < wy1)) return;
        if (y2 < wy1) x2 += scale(wy1-y2, dx, dy), y2 = wy1;
        if (y1 > wy2) x1 += scale(wy2-y1, dx, dy), y1 = wy2;
    }

    glViewport(0, 0, xdim, ydim);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, xdim, ydim, 0, -1, 1);
    if (videoGetRenderMode() == REND_POLYMER)
    {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }

    polymost2d = 1;
    buildgl_setDisabled(GL_ALPHA_TEST);
    buildgl_setDisabled(GL_DEPTH_TEST);
    buildgl_setEnabled(GL_BLEND);	// When using line antialiasing, this is needed

    polymost_useColorOnly(true);
    glBegin(GL_LINES);
    glColor4ub(p.r, p.g, p.b, 255);

    glVertex2f((float) x1 * (1.f/4096.f), (float) y1 * (1.f/4096.f));
    glVertex2f((float) x2 * (1.f/4096.f), (float) y2 * (1.f/4096.f));

    glEnd();
    polymost_useColorOnly(false);
}
#endif

static void drawlinepixels(int32_t x1, int32_t y1, int32_t x2, int32_t y2, char col)
{
    int32_t dx, dy, i, j, inc, plc, daend;
    intptr_t p;

    dx = x2-x1; dy = y2-y1;
    if (dx >= 0)
    {
        if ((x1 >= wx2) || (x2 < wx1)) return;
        if (x1 < wx1) y1 += scale(wx1-x1, dy, dx), x1 = wx1;
        if (x2 > wx2) y2 += scale(wx2-x2, dy, dx), x2 = wx2;
    }
    else
    {
        if ((x2 >= wx2) || (x1 < wx1)) return;
        if (x2 < wx1) y2 += scale(wx1-x2, dy, dx), x2 = wx1;
        if (x1 > wx2) y1 += scale(wx2-x1, dy, dx), x1 = wx2;
    }
    if (dy >= 0)
    {
        if ((y1 >= wy2) || (y2 < wy1)) return;
        if (y1 < wy1) x1 += scale(wy1-y1, dx, dy), y1 = wy1;
        if (y2 > wy2) x2 += scale(wy2-y2, dx, dy), y2 = wy2;
    }
    else
    {
        if ((y2 >= wy2) || (y1 < wy1)) return;
        if (y2 < wy1) x2 += scale(wy1-y2, dx, dy), y2 = wy1;
        if (y1 > wy2) x1 += scale(wy2-y1, dx, dy), y1 = wy2;
    }

    if (klabs(dx) >= klabs(dy))
    {
        if (dx == 0) return;
        if (dx < 0)
        {
            i = x1; x1 = x2; x2 = i;
            i = y1; y1 = y2; y2 = i;
        }

        inc = divscale12(dy, dx);
        plc = y1+mulscale12((2047-x1)&4095, inc);
        i = ((x1+2048)>>12); daend = ((x2+2048)>>12);

        videoBeginDrawing(); //{{{
        for (; i<daend; i++)
        {
            j = (plc>>12);
            if ((j >= startumost[i]) && (j < startdmost[i]))
                drawpixel_safe((void *) (frameplace+ylookup[j]+i), col);
            plc += inc;
        }
        videoEndDrawing();   //}}}
    }
    else
    {
        if (dy < 0)
        {
            i = x1; x1 = x2; x2 = i;
            i = y1; y1 = y2; y2 = i;
        }

        inc = divscale12(dx, dy);
        plc = x1+mulscale12((2047-y1)&4095, inc);
        i = ((y1+2048)>>12); daend = ((y2+2048)>>12);

        videoBeginDrawing(); //{{{
        p = ylookup[i]+frameplace;
        for (; i<daend; i++)
        {
            j = (plc>>12);
            if ((i >= startumost[j]) && (i < startdmost[j]))
                drawpixel_safe((void *) (j+p), col);
            plc += inc; p += ylookup[1];
        }
        videoEndDrawing();   //}}}
    }
}

void drawlinergb(int32_t x1, int32_t y1, int32_t x2, int32_t y2, palette_t p)
{
#ifdef USE_OPENGL
    if (videoGetRenderMode() >= REND_POLYMOST)
    {
        drawlinegl(x1, y1, x2, y2, p);
        return;
    }
#endif

    char const col = palookup[0][p.f];
    drawlinepixels(x1, y1, x2, y2, col);
}

void renderDrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, char col)
{
    col = palookup[0][col];

#ifdef USE_OPENGL
    if (videoGetRenderMode() >= REND_POLYMOST)
    {
        palette_t p = paletteGetColor(col);
        p.f = col;
        drawlinegl(x1, y1, x2, y2, p);
        return;
    }
#endif

    drawlinepixels(x1, y1, x2, y2, col);
}

//static void attach_here() {}

//
// drawline16
//
// JBF: Had to add extra tests to make sure x-coordinates weren't winding up -'ve
//   after clipping or crashes would ensue
uint32_t drawlinepat = 0xffffffff;

int32_t editorDraw2dLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int col)
{
    //int32_t odx,ody;
    //int32_t ox1=x1,oy1=y1, ox2=x2,oy2=y2;

    vec2_t d = { x2-x1, y2-y1 };

    //odx=dx;
    //ody=dy;

    if (d.x < 0)
    {
        swaplong(&x1, &x2);
        swaplong(&y1, &y2);
    }

    if (x1 >= xdim || x2 < 0)
        return 0;

    if (x1 < 0)
    {
        if (d.y) y1 += scale(0-x1, d.y, d.x);
        x1 = 0;
    }

    if (x2 >= xdim)
    {
        if (d.y) y2 += scale(xdim-1-x2, d.y, d.x);
        x2 = xdim-1;
    }

    if ((d.x < 0 && d.y >= 0) || (d.y < 0 && d.x >= 0))
    {
        swaplong(&x1, &x2);
        swaplong(&y1, &y2);
    }

    if (y1 >= ydim16 || y2 < 0)
        return 0;

    if (y1 < 0)
    {
        if (d.x)
            x1 = clamp(x1 + scale(0 - y1, d.x, d.y), 0, xdim - 1);
        y1 = 0;
    }

    if (y2 >= ydim16)
    {
        if (d.x)
            x2 = clamp(x2 + scale(ydim16-1-y2, d.x, d.y), 0, xdim-1);
        y2 = ydim16-1;
    }

    if (d.y < 0)
    {
        swaplong(&x1, &x2);
        swaplong(&y1, &y2);
    }

    //if (ox1||ox2||oy1||oy2)
    //    if (x1<0||x1>=xdim || y2<0||y2>=ydim)
    //        attach_here();

    d.x = klabs(x2-x1)+1;
    d.y = klabs(y2-y1)+1;

    if ((d.x >= d.y && x2 < x1) || (d.x < d.y && y2 < y1))
    {
        swaplong(&x1, &x2);
        swaplong(&y1, &y2);
    }

    int pinc, inc = 1;

    videoBeginDrawing(); //{{{

    intptr_t p = (y1*bytesperline)+x1+frameplace;

    if (d.x >= d.y)
    {
        pinc = (y2 > y1) ? bytesperline : -bytesperline;
    }
    else
    {
        pinc = (x2 > x1) ? 1 : -1;
        swaplong(&d.x, &d.y);
        inc = bytesperline;
    }

    int const trans = (col < 0);

    if (trans)
    {
        col = -col;

        if (drawlinepat == 0xffffffff)
        {
            for (bssize_t i=d.x, df=0; i>0; i--)
            {
                drawtranspixel((char *) p, col);
                df += d.y;
                if (df >= d.x) { df -= d.x; p += pinc; }
                p += inc;
            }
        }
        else
        {
            uint32_t patc = UINT_MAX;

            for (bssize_t i=d.x, df=0; i>0; i--)
            {
                if (drawlinepat & pow2ulong[(++patc)&31])
                    drawtranspixel((char *) p, col);
                df += d.y;
                if (df >= d.x) { df -= d.x; p += pinc; }
                p += inc;
            }
        }

        videoEndDrawing();   //}}}

        return 1;
    }

    if (inc == 1 && d.y == 1 && drawlinepat == 0xffffffff)
        clearbufbyte((void *) p, d.x, ((int32_t) col<<24)|((int32_t) col<<16)|((int32_t) col<<8)|col);
    else if (drawlinepat == 0xffffffff)
    {
        for (bssize_t i=d.x, df=0; i>0; i--)
        {
            drawpixel((char *) p, col);
            df += d.y;
            if (df >= d.x) { df -= d.x; p += pinc; }
            p += inc;
        }
    }
    else
    {
        uint32_t patc = UINT_MAX;

        for (bssize_t i=d.x, df=0; i>0; i--)
        {
            if (drawlinepat & pow2ulong[(++patc)&31])
                drawpixel((char *) p, col);
            df += d.y;
            if (df >= d.x) { df -= d.x; p += pinc; }
            p += inc;
        }
    }

    videoEndDrawing();   //}}}

    return 1;
}

static FORCE_INLINE void editorDraw2dLineMiddle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, char col)
{
    editorDraw2dLine(halfxdim16+x1, midydim16+y1, halfxdim16+x2, midydim16+y2, col);
}

// eccen: eccentricity of the ellipse,
//   16384: circle
//  <16384: shrink in y
//  >16384: grow in y
void editorDraw2dCircle(int32_t x1, int32_t y1, int32_t r, int32_t eccen, char col)
{
    if (eccen != 16384)
    {
        // JonoF's rough approximation of a circle
        int32_t l, spx, spy, lpx, lpy, px, py;

        spx = lpx = x1 + mulscale14(r, sintable[0]);
        spy = lpy = y1 + mulscale14(eccen, mulscale14(r, sintable[512]));

        for (l=64; l<2048; l+=64)
        {
            px = x1 + mulscale14(r, sintable[l]);
            py = y1 + mulscale14(eccen, mulscale14(r, sintable[(l+512)&2047]));

            editorDraw2dLine(lpx, lpy, px, py, col);

            lpx = px;
            lpy = py;
        }

        editorDraw2dLine(lpx, lpy, spx, spy, col);

        return;
    }

    if (r < 0) r = -r;
    if (x1+r < 0 || y1+r < 0 || x1-r >= xdim || y1-r >= ydim16) return;

    uint32_t const uxdim = xdim, uydim16 = ydim16;

    /*
    *      d
    *    6 | 7
    *   \  |  /
    *  5  \|/  8
    * c----+----a
    *  4  /|\  1
    *   /  |  \
    *    3 | 2
    *      b
    */

    videoBeginDrawing();
    intptr_t const p = (y1*bytesperline)+x1+frameplace;

    uint32_t patc = UINT_MAX;

    if (drawlinepat == 0xffffffff || drawlinepat & pow2ulong[(++patc)&31])
    {
        if ((uint32_t) y1 < uydim16 && (uint32_t) (x1+r) < uxdim)
            drawpixel((char *) (p+r), col);    // a
        if ((uint32_t) x1 < uxdim   && (uint32_t) (y1+r) < uydim16)
            drawpixel((char *) (p+(r*bytesperline)), col);    // b
        if ((uint32_t) y1 < uydim16 && (uint32_t) (x1-r) < uxdim)
            drawpixel((char *) (p-r), col);    // c
        if ((uint32_t) x1 < uxdim   && (uint32_t) (y1-r) < uydim16)
            drawpixel((char *) (p-(r*bytesperline)), col);    // d
    }

    int32_t xp = 0, yp = r;
    int32_t d = 1 - r, de = 2, dse = 5 - (r << 1);

    if (drawlinepat != 0xffffffff)
    {
        do
        {
            if (d < 0)
            {
                d += de;
                dse += 2;
            }
            else
            {
                d += dse;
                dse += 4;
                yp--;
            }

            xp++;
            de += 2;

            int32_t const ypbpl = yp*bytesperline;
            int32_t const xpbpl = xp*bytesperline;

            if (drawlinepat & pow2ulong[(++patc) & 31])
            {
                if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
                    drawpixel_safe((char *) (p + yp + xpbpl), col);  // 1
                if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
                    drawpixel_safe((char *) (p + xp + ypbpl), col);  // 2
                if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
                    drawpixel_safe((char *) (p - xp + ypbpl), col);  // 3
                if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
                    drawpixel_safe((char *) (p - yp + xpbpl), col);  // 4
                if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
                    drawpixel_safe((char *) (p - yp - xpbpl), col);  // 5
                if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
                    drawpixel_safe((char *) (p - xp - ypbpl), col);  // 6
                if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
                    drawpixel_safe((char *) (p + xp - ypbpl), col);  // 7
                if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
                    drawpixel_safe((char *) (p + yp - xpbpl), col);  // 8
            }
        } while (yp > xp);

        videoEndDrawing();
        return;
    }

    do
    {
        if (d < 0)
        {
            d += de;
            dse += 2;
        }
        else
        {
            d += dse;
            dse += 4;
            yp--;
        }

        xp++;
        de += 2;

        int32_t const ypbpl = yp*bytesperline;
        int32_t const xpbpl = xp*bytesperline;

        if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
            drawpixel_safe((char *) (p + yp + xpbpl), col);  // 1
        if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
            drawpixel_safe((char *) (p + xp + ypbpl), col);  // 2
        if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 + yp) < uydim16)
            drawpixel_safe((char *) (p - xp + ypbpl), col);  // 3
        if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 + xp) < uydim16)
            drawpixel_safe((char *) (p - yp + xpbpl), col);  // 4
        if ((uint32_t) (x1 - yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
            drawpixel_safe((char *) (p - yp - xpbpl), col);  // 5
        if ((uint32_t) (x1 - xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
            drawpixel_safe((char *) (p - xp - ypbpl), col);  // 6
        if ((uint32_t) (x1 + xp) < uxdim && (uint32_t) (y1 - yp) < uydim16)
            drawpixel_safe((char *) (p + xp - ypbpl), col);  // 7
        if ((uint32_t) (x1 + yp) < uxdim && (uint32_t) (y1 - xp) < uydim16)
            drawpixel_safe((char *) (p + yp - xpbpl), col);  // 8
    } while (yp > xp);

    videoEndDrawing();
}

//
// clear2dscreen
//
void clear2dscreen(void)
{
    int32_t const clearsz = (ydim16 <= ydim - STATUS2DSIZ2) ? ydim - STATUS2DSIZ2 : ydim;
    videoBeginDrawing();  //{{{
    Bmemset((char *) frameplace, 0, bytesperline*clearsz);
    videoEndDrawing();   //}}}
}

////////// editor side view //////////

int32_t scalescreeny(int32_t sy) { return (m32_sideview) ? mulscale14(sy, m32_sidesin) : sy; }

// return screen coordinates for BUILD coords x and y (relative to current position)
void editorGet2dScreenCoordinates(int32_t *xres, int32_t *yres, int32_t x, int32_t y, int32_t zoome)
{
    vec2_t coord = { x, y };

    if (m32_sideview)
        rotatevec(coord, m32_sideang, &coord);

    *xres = mulscale14(coord.x, zoome);
    *yres = scalescreeny(mulscale14(coord.y, zoome));
}

#if 0
void invscreencoords(int32_t *dx, int32_t *dy, int32_t sx, int32_t sy, int32_t zoome)
{
    if (m32_sidesin==0 || zoome==0) { *dx=0; *dy=0; return; }

    sy = divscale14(divscale14(sy, m32_sidesin), zoome);
    sx = divscale14(sx, zoome);

    rotatepoint(0, 0, sx, sy, -m32_sideang, dx, dy);
}
#endif

// invscreencoords with sx==0 and sy==getscreenvdisp(dz, zoom)
int32_t getinvdisplacement(int32_t *dx, int32_t *dy, int32_t dz)
{
    if (m32_sidesin==0)
        return 1;

    dz = (((int64_t) dz * (int64_t) m32_sidecos)/(int64_t) m32_sidesin)>>4;

    vec2_t v[2] = { { 0, dz },{ *dx, *dy } };

    rotatevec(v[0], -m32_sideang, &v[1]);

    *dx = v[1].x;
    *dy = v[1].y;

    return 0;
}

// return vertical screen coordinate displacement for BUILD z coord
int32_t getscreenvdisp(int32_t bz, int32_t zoome)
{
    return mulscale32(bz, zoome*m32_sidecos);
}

void editorSetup2dSideView(void)
{
    if (m32_sideview)
    {
        m32_viewplane.x = 0;
        m32_viewplane.y = -512;

        m32_sidesin = sintable[m32_sideelev&2047];
        m32_sidecos = sintable[(m32_sideelev+512)&2047];

        rotatevec(m32_viewplane.xy, -m32_sideang, &m32_viewplane.xy);
        m32_viewplane.x = mulscale14(m32_viewplane.x, m32_sidecos);
        m32_viewplane.y = mulscale14(m32_viewplane.y, m32_sidecos);
        m32_viewplane.z = m32_sidesin>>5;
    }
}

static void editorGet2dSideViewDistance(int16_t sw, int16_t sect)
{
    vec3_t *p;
    vec3_t v;

    if (sw<MAXWALLS)
    {
        v.x = (wall[sw].x + wall[wall[sw].point2].x)>>1;
        v.y = (wall[sw].y + wall[wall[sw].point2].y)>>1;
        v.z = getflorzofslope(sect, v.x, v.y);
        p = &v;
    }
    else
        p = &sprite[sw-MAXWALLS].xyz;

    m32_sidedist[sw] = p->x*m32_viewplane.x + p->y*m32_viewplane.y + (p->z>>4)*m32_viewplane.z;
}

static int editorCompare2dSideViewPoints(const void *sw1, const void *sw2)
{
    int32_t dist1 = m32_sidedist[B_UNBUF16(sw1)];
    int32_t dist2 = m32_sidedist[B_UNBUF16(sw2)];

    if (dist2>dist1)
        return 1;
    else if (dist1>dist2)
        return -1;

    //    if (*sw1<MAXWALLS && *sw2<MAXWALLS)
    //        return (wall[*sw2].nextwall>=0) - (wall[*sw1].nextwall>=0);

    return 0;
}

//
// draw2dgrid
//
void editorDraw2dGrid(int32_t posxe, int32_t posye, int32_t posze, int16_t cursectnum, int16_t ange, int32_t zoome, int16_t gride)
{
    int64_t i, xp1, yp1, xp2=0, yp2, tempy;

    UNREFERENCED_PARAMETER(ange);

    if (gride <= 0)
        return;

    videoBeginDrawing();	//{{{

    if (m32_sideview)
    {
        int32_t sx1, sy1, sx2, sy2, dx=0, dy=0;
        int32_t xinc=0, yinc=2048>>gride, yofs;

        //        yofs = getscreenvdisp((yinc-posze)&((yinc<<4)-1), zoome);
        if (cursectnum<0 || cursectnum>=numsectors)
            yofs = getscreenvdisp(-posze, zoome);
        else
            yofs = getscreenvdisp(getflorzofslope(cursectnum, posxe, posye)-posze, zoome);

        while (scalescreeny(mulscale14(yinc, zoome))==0 && gride>2)
        {
            gride--;
            yinc = 2048>>gride;
        }

        xp2 = xp1 = ((posxe + (1024 >> gride)) & -(((int64_t)(1)) << (11 - gride)));
        yp2 = yp1 = ((posye + (1024 >> gride)) & -(((int64_t)(1)) << (11 - gride)));

        do
        {
            if (xinc==0)
            {
                editorGet2dScreenCoordinates(&sx1, &sy1, -editorgridextent-posxe, yp2-posye, zoome);
                if (yp2 == yp1)
                {
                    editorGet2dScreenCoordinates(&sx2, &sy2, editorgridextent-posxe, yp2-posye, zoome);
                    dx = sx2-sx1;
                    dy = sy2-sy1;
                }
                yp2 += yinc;
            }
            else  // if (yinc==0)
            {
                editorGet2dScreenCoordinates(&sx1, &sy1, xp2-posxe, -editorgridextent-posye, zoome);
                if (xp2 == xp1)
                {
                    editorGet2dScreenCoordinates(&sx2, &sy2, xp2-posxe, editorgridextent-posye, zoome);
                    dx = sx2-sx1;
                    dy = sy2-sy1;
                }
                xp2 += xinc;
            }

            i = editorDraw2dLine(halfxdim16+sx1, midydim16+sy1+yofs, halfxdim16+sx1+dx, midydim16+sy1+dy+yofs, editorcolors[25]);
            if (i==0 || (xp2<-editorgridextent || xp2>editorgridextent ||
                yp2<-editorgridextent || yp2>editorgridextent))
            {
                xp2 = xp1;
                yp2 = yp1;

                i = 1;

                if (yinc>0)
                    yinc *= -1;
                else if (yinc<0)
                {
                    xinc = -yinc;
                    yinc = 0;
                }
                else if (xinc>0)
                    xinc *= -1;
                else // if (xinc<0)
                    i = 0;
            }
        } while (i);
    }
    else
    {
        // vertical lines
        yp1 = midydim16-mulscale14(posye+editorgridextent, zoome);
        if (yp1 < 0) yp1 = 0;

        yp2 = midydim16-mulscale14(posye-editorgridextent, zoome);
        if (yp2 >= ydim16) yp2 = ydim16-1;

        if ((yp1 < ydim16) && (yp2 >= 0) && (yp2 >= yp1))
        {
            xp1 = halfxdim16-mulscale14(posxe+editorgridextent, zoome);

            for (i=-editorgridextent; i<=editorgridextent; i+=(2048>>gride))
            {
                xp2 = xp1;
                xp1 = halfxdim16-mulscale14(posxe-i, zoome);

                if (xp1 >= xdim)
                    break;

                if (xp1 >= 0)
                {
                    if (xp1 != xp2)
                        editorDraw2dLine(xp1, yp1, xp1, yp2, editorcolors[25]);
                }
            }
            if (i >= editorgridextent && xp1 < xdim)
                xp2 = xp1;
            if (xp2 >= 0 && xp2 < xdim)
                editorDraw2dLine(xp2, yp1, xp2, yp2, editorcolors[25]);
        }

        // horizontal lines
        xp1 = mulscale14(posxe+editorgridextent, zoome);
        xp2 = mulscale14(posxe-editorgridextent, zoome);
        tempy = 0x80000000l;

        for (i=-editorgridextent; i<=editorgridextent; i+=(2048>>gride))
        {
            yp1 = ((posye-i)*zoome)>>14;
            if (yp1 != tempy)
            {
                if ((yp1 > midydim16-ydim16) && (yp1 <= midydim16))
                {
                    editorDraw2dLineMiddle(-xp1, -yp1, -xp2, -yp1, editorcolors[25]);
                    tempy = yp1;
                }
            }
        }
    }

    videoEndDrawing();   //}}}
}

static void editorDraw2dWall(int32_t i, int32_t posxe, int32_t posye, int32_t posze, int32_t zoome, int32_t grayp)
{
    const walltype *const wal = &wall[i];

    int32_t j = wal->nextwall;
    int32_t cstat = 0;
#if 0
    if (editstatus == 0)
    {
        if ((show2dwall[i>>3]&pow2char[i&7]) == 0) return;
        if ((j >= 0) && (i > j))
            if ((show2dwall[j>>3]&pow2char[j&7]) > 0) return;
    }
    else
#endif
    {
        if (!m32_sideview && !(grayp&2) && (j >= 0) && (i > j)) return;
    }

    char col;

    if (grayp&1)
        col = editorcolors[8];
    else if (j < 0)
    {
        col = (i == linehighlight) ? editorcolors[15] - M32_THROB : editorcolors[15];
        cstat = wal->cstat;
    }
    else
    {
        if ((unsigned) wal->nextwall < MAXWALLS && ((wal->cstat^wall[j].cstat)&1))
            col = editorcolors[2];
        else if (bloodhack ? (wal->cstat&64) != 0 : (wal->cstat&1) != 0)
            col = editorcolors[5];
        else col = editorcolors[4];

        cstat = wal->cstat;
        if (i != linehighlight && (unsigned)wal->nextwall < MAXWALLS)
        {
            if (wal->nextwall == linehighlight)
                cstat = wall[wal->nextwall].cstat;
            else
                cstat |= wall[wal->nextwall].cstat;
        }

        if (i == linehighlight || (linehighlight >= 0 && i == wall[linehighlight].nextwall))
            col += M32_THROB>>2;
    }

    if (bloodhack && (cstat&0xc000))
    {
        if (cstat&0x8000)
            col = editorcolors[10];
        else if (cstat&0x4000)
            col = editorcolors[9];
        if (i == linehighlight || (linehighlight >= 0 && i == wall[linehighlight].nextwall))
            col -= M32_THROB>>3;
    }

    int const p2 = wal->point2;

    int32_t x1, y1, x2, y2;
    editorGet2dScreenCoordinates(&x1, &y1, wal->x-posxe, wal->y-posye, zoome);
    editorGet2dScreenCoordinates(&x2, &y2, wall[p2].x-posxe, wall[p2].y-posye, zoome);

    int64_t const dx = wal->x-wall[p2].x;
    int64_t const dy = wal->y-wall[p2].y;
    int64_t const dist = dx*dx + dy*dy;

    int const bothSidesHighlighted = bitmap_test(show2dwall, i) && bitmap_test(show2dwall, p2);

    if (dist > INT32_MAX)
    {
        col=editorcolors[9];
        if (i == linehighlight || (linehighlight >= 0 && i == wall[linehighlight].nextwall))
            col -= M32_THROB>>3;
    }
    else if ((showfirstwall && searchsector>=0 && (sector[searchsector].wallptr == i ||
        sector[searchsector].wallptr == wal->nextwall)) ||
        bothSidesHighlighted)
    {
        col = editorcolors[14];
        if (i == linehighlight || (linehighlight >= 0 && i == wall[linehighlight].nextwall) || bothSidesHighlighted)
            col -= M32_THROB>>1;
    }
    else if (circlewall >= 0 && (i == circlewall || wal->nextwall == circlewall))
        col = editorcolors[14];

    int32_t fz=0, fzn=0;

    if (m32_sideview)
    {
        // draw vertical line to neighboring wall
        int32_t const sect = sectorofwall(i);

        fz = getflorzofslope(sect, wal->x, wal->y);
        int32_t fz2 = getflorzofslope(sect, wall[p2].x, wall[p2].y);

        int32_t const dz = getscreenvdisp(fz-posze, zoome);
        int32_t const dz2 = getscreenvdisp(fz2-posze, zoome);

        y1 += dz;
        y2 += dz2;

        if (wal->nextwall>=0)
        {
            fzn = getflorzofslope(wal->nextsector, wal->x, wal->y);
            //            if (i < wall[j].point2)
            editorDraw2dLineMiddle(x1, y1, x1, y1+getscreenvdisp(fzn-fz, zoome), col);
        }
#ifdef YAX_ENABLE
        {
            int16_t const nw = yax_getnextwall(i, YAX_CEILING);

            if (nw >= 0)
            {
                int32_t const odrawlinepat = drawlinepat;
                fz2 = getflorzofslope(sectorofwall(nw), wall[nw].x, wall[nw].y);
                drawlinepat = 0x11111111;
                editorDraw2dLineMiddle(x1, y1, x1, y1+getscreenvdisp(fz2-fz, zoome), col);
                drawlinepat = odrawlinepat;
            }
        }
#endif

        m32_wallscreenxy[i][0] = halfxdim16+x1;
        m32_wallscreenxy[i][1] = midydim16+y1;
    }

    if (bloodhack ? cstat&1 : wal->cstat&64)  // if hitscan bit set
    {
        int32_t const one=(klabs(x2-x1) >= klabs(y2-y1)), no=!one;

        editorDraw2dLineMiddle(x1+no, y1+one, x2+no, y2+one, col);
        editorDraw2dLineMiddle(x1-no, y1-one, x2-no, y2-one, col);
    }

    editorDraw2dLineMiddle(x1, y1, x2, y2, col);

    // Draw height indicators at center of walls if requested and if not in
    // side-view mode.
    // XXX: This does not take sloping into account.
    if (showheightindicators && !m32_sideview)
    {
        int32_t dax, day;
        int32_t const k = getangle(x1-x2, y1-y2);

        editorGet2dScreenCoordinates(&dax, &day,
            ((wal->x+wall[wal->point2].x)>>1)-posxe,
            ((wal->y+wall[wal->point2].y)>>1)-posye, zoome);

        if (wal->nextsector >= 0)
        {
            int32_t const z1 = sector[sectorofwall(i)].floorz;
            int32_t const z2 = sector[wal->nextsector].floorz;

            if (z1 != z2 || showheightindicators == 2)
            {
                // Red walls. Show them on equal-height walls ONLY with setting 2.
                int32_t const bb = (z2 < z1);
                int32_t const dx = mulscale11(sintable[(k+1024 + 1024*bb)&2047], min(4096, zoome)) / 2560;
                int32_t const dy = scalescreeny(mulscale11(sintable[(k+512 + 1024*bb)&2047], min(4096, zoome)) / 2560);

                editorDraw2dLineMiddle(dax, day, dax+dx, day+dy, col);
            }
        }
        else if (showheightindicators == 2)
        {
            // Show them on white walls ONLY with setting 2.
            int32_t const dx = mulscale11(sintable[(k+2048)&2047], min(4096, zoome)) / 2560;
            int32_t const dy = scalescreeny(mulscale11(sintable[(k+1536)&2047], min(4096, zoome)) / 2560);

            editorDraw2dLineMiddle(dax, day, dax+dx, day+dy, col);
        }
    }

    if ((zoome >= 256 && editstatus == 1) || bitmap_test(show2dwall, i))
        if ((halfxdim16+x1 >= 2) && (halfxdim16+x1 <= xdim-3) &&
            (midydim16+y1 >= 2) && (midydim16+y1 <= ydim16-3))
        {
            int32_t pointsize = 2;

            col = editorcolors[15];

            if (i == pointhighlight || ((unsigned) pointhighlight < MAXWALLS &&
                (wal->x == wall[pointhighlight].x) && (wal->y == wall[pointhighlight].y)))
            {
                col = editorcolors[15] - (M32_THROB>>1);

                if ((int32_t) totalclock & 16)
                    pointsize++;
            }

            if (bitmap_test(show2dwall, i))
                col = editorcolors[14] - (M32_THROB>>1);

            if (m32_sideview)
            {
                if (wal->nextwall >= 0)
                {
                    if (fz < fzn)
                        col = editorcolors[7];
                    else if (fz == fzn)
                        col = editorcolors[4];
                }
            }

            editorDraw2dCircle(halfxdim16+x1, midydim16+y1, pointsize, 16384, col);
        }
}

int32_t editorGet2dSpriteColor(int32_t spr)
{
    int const picnum = sprite[spr].picnum;
    int pal = sprite[spr].pal;
    int const tilecol = tilecols[picnum];

    if (palookup[pal] == NULL || (tilecol && palookup[pal][tilecol] == 0))
        pal = 0;

    if (tilecol) return palookup[pal][tilecol];

    if (!waloff[picnum]) tileLoad(picnum);
    if (!waloff[picnum]) return editorcolors[3];

    // Calculate 2D mode tile color.

    uint32_t cols[256];

    Bmemset(cols, 0, sizeof(cols));

    const uint8_t *const texbuf = (const uint8_t *) waloff[picnum];

    for (bssize_t i = 0; i < tilesiz[picnum].x * tilesiz[picnum].y; i++)
        cols[texbuf[i]]++;

    unsigned col = 0, cnt = 0;

    for (bssize_t i = 0; i < 240; i++)
        if (cols[i] > cnt)
            col = i, cnt = cols[i];

    while (col < 240 && curpalette[col+1].r > curpalette[col].r)
        col++;

    tilecols[picnum] = col - 4;

    return palookup[pal][tilecols[picnum]];
}

static void editorDraw2DBloodMarker(int x, int y, int col)
{
    editorDraw2dCircle(x, y, 4, 16384, col);
    editorDraw2dLine(x-2, y-2, x+2, y+2, col);
    editorDraw2dLine(x+2, y-2, x-2, y+2, col);
#if 0
    plotpixel(x-4, y-1, col);
    plotpixel(x-4, y-0, col);
    plotpixel(x-4, y+1, col);

    plotpixel(x-3, y-3, col);
    plotpixel(x-3, y-2, col);
    plotpixel(x-3, y+2, col);
    plotpixel(x-3, y+3, col);

    plotpixel(x-2, y-3, col);
    plotpixel(x-2, y-2, col);
    plotpixel(x-2, y+2, col);
    plotpixel(x-2, y+3, col);

    plotpixel(x-1, y-4, col);
    plotpixel(x-1, y-1, col);
    plotpixel(x-1, y+1, col);
    plotpixel(x-1, y+4, col);

    plotpixel(x-0, y-4, col);
    plotpixel(x-0, y-0, col);
    plotpixel(x-0, y+4, col);

    plotpixel(x+1, y-4, col);
    plotpixel(x+1, y-1, col);
    plotpixel(x+1, y+1, col);
    plotpixel(x+1, y+4, col);

    plotpixel(x+2, y-3, col);
    plotpixel(x+2, y-2, col);
    plotpixel(x+2, y+2, col);
    plotpixel(x+2, y+3, col);

    plotpixel(x+3, y-3, col);
    plotpixel(x+3, y-2, col);
    plotpixel(x+3, y+2, col);
    plotpixel(x+3, y+3, col);

    plotpixel(x+4, y-1, col);
    plotpixel(x+4, y-0, col);
    plotpixel(x+4, y+1, col);
#endif
}

static void editorDraw2dSpriteBloodMarker(int32_t j, int32_t posxe, int32_t posye, int32_t posze, int32_t zoome)
{
    int32_t x1, y1, x2, y2;
    int col;

    const spritetype *const spr = &sprite[j];

    int16_t const angofs = m32_sideview ? m32_sideang : 0;
    uint8_t const spritecol = sectorhighlight == spr->owner ? 15 : 14;

    // KEEPINSYNC build.c: drawspritelabel()
    if (spr->sectnum<0)
        col = editorcolors[4];  // red
    else
        col = editorcolors[spritecol];

    if (editstatus == 1)
    {
        if (pointhighlight >= 16384 &&
            (j+16384 == pointhighlight ||
            (!m32_sideview && (spr->x == sprite[pointhighlight-16384].x &&
                spr->y == sprite[pointhighlight-16384].y))))
        {
            if (spritecol >= 8 && spritecol <= 15)
                col -= bloodhack ? M32_THROB>>2 : M32_THROB>>1;
            else
                col += M32_THROB>>2;
        }
        else // if (highlightcnt > 0)
        {
            if (show2dsprite[j>>3]&pow2char[j&7])
                col = editorcolors[14] - (M32_THROB>>1);
        }
    }

    editorGet2dScreenCoordinates(&x1, &y1, spr->x-posxe, spr->y-posye, zoome);
    //   tempint = ((midydim16+y1)*bytesperline)+(halfxdim16+x1)+frameplace;

    if (m32_sideview)
        y1 += getscreenvdisp(spr->z-posze, zoome);

    int f = mulscale12(128, zoome);

    if ((halfxdim16+x1 >= -f) && (halfxdim16+x1 < xdim+f) &&
        (midydim16+y1 >= -f) && (midydim16+y1 < ydim16+f))
    {
        if (spr->statnum == 10)
        {
            switch (spr->type)
            {
            case 3:
            case 4:
                editorDraw2DBloodMarker(halfxdim16+x1, midydim16+y1, col);
                break;

            case 5:
            case 6:
                editorDraw2DBloodMarker(halfxdim16+x1, midydim16+y1, col);
                x2 = mulscale11(sintable[(spr->ang+angofs+2560)&2047], zoome) / 768;
                y2 = mulscale11(sintable[(spr->ang+angofs+2048)&2047], zoome) / 768;
                y2 = scalescreeny(y2);

                editorDraw2dLineMiddle(x1, y1, x1+x2, y1+y2, col);
                break;
            }
        }
        else
            editorDraw2DBloodMarker(halfxdim16+x1, midydim16+y1, col);
    }
}

static void editorDraw2dSprite(int32_t j, int32_t posxe, int32_t posye, int32_t posze, int32_t zoome)
{
    int32_t x1, y1, x2, y2;
    int col;

    auto const spr = &sprite[j];
    int16_t const blocking = (spr->cstat&1), hitblocking = (spr->cstat&256);
    int16_t const flooraligned = (spr->cstat&48) >= 32, wallaligned = (spr->cstat&48) == 16;

    int16_t const angofs = m32_sideview ? m32_sideang : 0;
    uint8_t spritecol = spritecol2d[spr->picnum][blocking];

    if (bloodhack)
    {
        if (spr->statnum == 10 || spr->statnum == 12)
        {
            editorDraw2dSpriteBloodMarker(j, posxe, posye, posze, zoome);
            return;
        }
        if (spr->cstat & 256)
            spritecol = 5;
        if (spr->cstat & 0x8000)
            spritecol = 8;
        if (spr->cstat & 0x2000)
            spritecol = 9;
        if (spr->cstat & 0x4000)
            spritecol = 10;
    }

    // KEEPINSYNC build.c: drawspritelabel()
    if (spr->sectnum<0)
        col = editorcolors[4];  // red
    else
        col = spritecol ? editorcolors[spritecol] : blocking ? editorcolors[5] : editorGet2dSpriteColor(j);

    if (editstatus == 1)
    {
        if (pointhighlight >= 16384 &&
            (j+16384 == pointhighlight ||
            (!m32_sideview && (spr->x == sprite[pointhighlight-16384].x &&
                spr->y == sprite[pointhighlight-16384].y))))
        {
            if (spritecol >= 8 && spritecol <= 15)
                col -= bloodhack ? M32_THROB>>2 : M32_THROB>>1;
            else
                col += M32_THROB>>2;
        }
        else // if (highlightcnt > 0)
        {
            if (bitmap_test(show2dsprite, j))
                col = editorcolors[14] - (M32_THROB>>1);
        }
    }

    editorGet2dScreenCoordinates(&x1, &y1, spr->x-posxe, spr->y-posye, zoome);
    //   tempint = ((midydim16+y1)*bytesperline)+(halfxdim16+x1)+frameplace;

    if (m32_sideview)
        y1 += getscreenvdisp(spr->z-posze, zoome);

    int f = mulscale12(128, zoome);

    if ((halfxdim16+x1 >= -f) && (halfxdim16+x1 < xdim+f) &&
        (midydim16+y1 >= -f) && (midydim16+y1 < ydim16+f))
    {
        if (zoome > 512 && spr->clipdist > 32)
            editorDraw2dCircle(halfxdim16+x1, midydim16+y1, mulscale14(spr->clipdist<<2, zoome), 16384, col);

        editorDraw2dCircle(halfxdim16+x1, midydim16+y1, 4, 16384, col);

        x2 = mulscale11(sintable[(spr->ang+angofs+2560)&2047], zoome) / 768;
        y2 = mulscale11(sintable[(spr->ang+angofs+2048)&2047], zoome) / 768;
        y2 = scalescreeny(y2);

        editorDraw2dLineMiddle(x1, y1, x1+x2, y1+y2, col);

        if (hitblocking)
        {
            editorDraw2dLineMiddle(x1, y1+1, x1+x2, y1+y2+1, col);
            editorDraw2dLineMiddle(x1, y1-1, x1+x2, y1+y2-1, col);
            editorDraw2dLineMiddle(x1-1, y1, x1+x2-1, y1+y2, col);
            editorDraw2dLineMiddle(x1+1, y1, x1+x2+1, y1+y2, col);
        }

        if (flooraligned)
        {
            int32_t heinum = spriteGetSlope(j);
            int32_t ratio = ksqrt(heinum * heinum + 16777216);
            int32_t ratioz = divscale12(heinum, ratio);
            int32_t yspan = mulscale6(tilesiz[spr->picnum].y, spr->yrepeat);
            int32_t fx = mulscale10(mulscale6(tilesiz[spr->picnum].x, spr->xrepeat), zoome) >> 1;
            int32_t fy = divscale12(mulscale10(yspan, zoome) >> 1, ratio);
            int32_t fz = getscreenvdisp(mulscale4(yspan, ratioz) >> 1, zoome);
            int32_t co[4][3], ii, in;
            int32_t sinang = sintable[(spr->ang+angofs+1536)&2047];
            int32_t cosang = sintable[(spr->ang+angofs+1024)&2047];
            int32_t r, s;

            co[0][0] = co[3][0] = -fx;
            co[0][1] = co[1][1] = -fy;
            co[0][2] = co[1][2] = -fz;
            co[1][0] = co[2][0] = fx;
            co[2][1] = co[3][1] = fy;
            co[2][2] = co[3][2] = fz;

            for (ii=3; ii>=0; ii--)
            {
                r = mulscale14(cosang, co[ii][0]) - mulscale14(sinang, co[ii][1]);
                s = mulscale14(sinang, co[ii][0]) + mulscale14(cosang, co[ii][1]);
                s = scalescreeny(s);
                if (m32_sideview)
                    s += co[ii][2];
                co[ii][0] = r;
                co[ii][1] = s;
            }
            drawlinepat = 0xcfcfcfcf;
            for (ii=3; ii>=0; ii--)
            {
                in = (ii+1)&3;
                editorDraw2dLineMiddle(x1+co[ii][0], y1-co[ii][1], x1+co[in][0], y1-co[in][1], col);
                if (hitblocking)
                {
                    editorDraw2dLineMiddle(x1+co[ii][0], y1-co[ii][1]+1, x1+co[in][0], y1-co[in][1]+1, col);
                    editorDraw2dLineMiddle(x1+co[ii][0], y1-co[ii][1]-1, x1+co[in][0], y1-co[in][1]-1, col);
                    editorDraw2dLineMiddle(x1+co[ii][0]+1, y1-co[ii][1], x1+co[in][0]+1, y1-co[in][1], col);
                    editorDraw2dLineMiddle(x1+co[ii][0]-1, y1-co[ii][1], x1+co[in][0]-1, y1-co[in][1], col);
                }
                editorDraw2dLineMiddle(x1, y1, x1 + co[in][0], y1 - co[in][1], col);
            }
            drawlinepat = 0xffffffff;
        }
        else if (wallaligned)
        {
            int32_t fx = mulscale6(tilesiz[spr->picnum].x, spr->xrepeat);
            int32_t one=(((spr->ang+angofs+256)&512) == 0), no=!one;

            x2 = mulscale11(sintable[(spr->ang+angofs+2560)&2047], zoome) / 6144;
            y2 = mulscale11(sintable[(spr->ang+angofs+2048)&2047], zoome) / 6144;
            y2 = scalescreeny(y2);

            editorDraw2dLineMiddle(x1, y1, x1+x2, y1+y2, col);
            if (!(spr->cstat&64))  // not 1-sided
            {
                editorDraw2dLineMiddle(x1, y1, x1-x2, y1-y2, col);
                if (hitblocking)
                {
                    editorDraw2dLineMiddle(x1-no, y1-one, x1-x2-no, y1-y2-one, col);
                    editorDraw2dLineMiddle(x1+no, y1+one, x1-x2+no, y1-y2+one, col);
                }
            }

            if (hitblocking)
            {
                editorDraw2dLineMiddle(x1-no, y1-one, x1+x2-no, y1+y2-one, col);
                editorDraw2dLineMiddle(x1+no, y1+one, x1+x2+no, y1+y2+one, col);
            }

            x2 = mulscale13(sintable[(spr->ang+angofs+1024)&2047], zoome) * fx / 4096;
            y2 = mulscale13(sintable[(spr->ang+angofs+512)&2047], zoome) * fx / 4096;
            y2 = scalescreeny(y2);

            editorDraw2dLineMiddle(x1, y1, x1-x2, y1-y2, col);
            editorDraw2dLineMiddle(x1, y1, x1+x2, y1+y2, col);

            if (hitblocking)
            {
                editorDraw2dLineMiddle(x1+1, y1, x1+x2+1, y1+y2, col);
                editorDraw2dLineMiddle(x1-1, y1, x1-x2-1, y1-y2, col);
                editorDraw2dLineMiddle(x1-1, y1, x1+x2-1, y1+y2, col);
                editorDraw2dLineMiddle(x1+1, y1, x1-x2+1, y1-y2, col);

                editorDraw2dLineMiddle(x1, y1-1, x1+x2, y1+y2-1, col);
                editorDraw2dLineMiddle(x1, y1+1, x1-x2, y1-y2+1, col);
                editorDraw2dLineMiddle(x1, y1+1, x1+x2, y1+y2+1, col);
                editorDraw2dLineMiddle(x1, y1-1, x1-x2, y1-y2-1, col);
            }
        }
    }
}

//
// draw2dscreen
//

static int8_t tempbuf[(MAXWALLS+7)>>3];

void editorDraw2dScreen(const vec3_t *pos, int16_t cursectnum, int16_t ange, int32_t zoome, int16_t gride)
{
    int32_t i, x1, y1;
    int16_t angofs = m32_sideview ? m32_sideang : 0;

    int32_t posxe=pos->x, posye=pos->y, posze=pos->z;
    uint8_t *graybitmap = (uint8_t *) tempbuf;
    int32_t alwaysshowgray = get_alwaysshowgray();

    if (in3dmode()) return;

    editorSetup2dSideView();

    videoBeginDrawing(); //{{{

    if (editstatus == 0)
    {
        //        faketimerhandler();
        clear2dscreen();

        //        faketimerhandler();
        editorDraw2dGrid(posxe, posye, posze, cursectnum, ange, zoome, gride);
    }

    faketimerhandler();

    m32_swcnt = 0;

    if (numgraysects==0)
        Bmemset(graybitmap, 0, (numwalls+7)>>3);
    else
    {
        for (i=0; i<numwalls; i++)
        {
            int32_t j = wall[i].nextwall;
            if (bitmap_test(graywallbitmap, i) && (j < 0 || bitmap_test(graywallbitmap, j)))
                bitmap_set(graybitmap, i);
            else
                bitmap_clear(graybitmap, i);
        }
    }

    if (!m32_sideview)
    {
#ifndef YAX_ENABLE
        for (i=numwalls-1; i>=0; i--)
            editorDraw2dWall(i, posxe, posye, posze, zoome, 0);
#else
        if (alwaysshowgray)
            for (i=numwalls-1; i>=0; i--)
                if (bitmap_test(graybitmap, i))
                    editorDraw2dWall(i, posxe, posye, posze, zoome, 1+2);

        for (i=numwalls-1; i>=0; i--)
            if (!bitmap_test(graybitmap, i))
                editorDraw2dWall(i, posxe, posye, posze, zoome, 2);
#endif
    }
    else
    {
        int32_t j = 0;

        for (i=0; i<numsectors; i++)
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
            {
                m32_wallsprite[m32_swcnt++] = j;
                editorGet2dSideViewDistance(j, i);
            }

        // j = sector[numsectors-1].wallptr + sector[numsectors-1].wallnum
        for (; j < numwalls; j++)  // new walls ...
        {
            m32_wallsprite[m32_swcnt++] = j;
            editorGet2dSideViewDistance(j, 0);
        }
    }

    faketimerhandler();

    if (zoome >= 256 || highlightcnt>0)
        for (bssize_t j=0; j<MAXSPRITES; j++)
            if (sprite[j].statnum<MAXSTATUS)
            {
                // if sprite is highlighted, always draw it
                if (!bitmap_test(show2dsprite, j))
                {
                    if (!m32_sideview && sprite[j].sectnum >= 0)
                        YAX_SKIPSECTOR(sprite[j].sectnum);

                    if (zoome<256)
                        continue;
                }

                if (!m32_sideview)
                    editorDraw2dSprite(j, posxe, posye, posze, zoome);
                else
                {
                    m32_wallsprite[m32_swcnt++] = MAXWALLS+j;
                    editorGet2dSideViewDistance(MAXWALLS+j, -1);
                }
            }

    faketimerhandler();

    if (m32_sideview)
    {
        qsort(m32_wallsprite, m32_swcnt, sizeof(int16_t), &editorCompare2dSideViewPoints);

        for (i=0; i<m32_swcnt; i++)  // shouldn't it go the other way around?
        {
            int32_t j = m32_wallsprite[i];
            if (j<MAXWALLS)
            {
                if (alwaysshowgray || !bitmap_test(graybitmap, j))
                    editorDraw2dWall(j, posxe, posye, posze, zoome, !!bitmap_test(graybitmap, j));
            }
            else
            {
                if (!alwaysshowgray && sprite[j-MAXWALLS].sectnum>=0)
                    YAX_SKIPSECTOR(sprite[j-MAXWALLS].sectnum);

                editorDraw2dSprite(j-MAXWALLS, posxe, posye, posze, zoome);
            }
        }

        faketimerhandler();
    }

#if 0
    {
        int32_t xx, yy, xx2, yy2;
        screencoords(&xx, &yy, -posxe, -posye, zoome);
        screencoords(&xx2, &yy2, (m32_viewplane.x)-posxe, (m32_viewplane.y)-posye, zoome);
        if (m32_sideview)
            yy2 += getscreenvdisp((m32_viewplane.z<<4)-posze, zoome);

        drawcircle16(halfxdim16+xx, midydim16+yy, 2, 16384, editorcolors[4]); //red
        drawcircle16(halfxdim16+xx2, midydim16+yy2, 2, 16384, editorcolors[14]); //yellow
        drawline16mid(xx, yy, xx2, yy2, editorcolors[15]);
    }
#endif

    x1 = mulscale11(sintable[(ange+angofs+2560)&2047], zoome) / 768; //Draw white arrow
    y1 = mulscale11(sintable[(ange+angofs+2048)&2047], zoome) / 768;

    i = scalescreeny(x1);
    int32_t j = scalescreeny(y1);

    editorDraw2dLineMiddle(x1, j, -x1, -j, editorcolors[15]);
    editorDraw2dLineMiddle(x1, j, +y1, -i, editorcolors[15]);
    editorDraw2dLineMiddle(x1, j, -y1, +i, editorcolors[15]);

    videoEndDrawing();   //}}}
}

//
// setpolymost2dview
//  Sets OpenGL for 2D drawing
//
void polymostSet2dView(void)
{
#ifdef USE_OPENGL
    if (videoGetRenderMode() < REND_POLYMOST) return;

    glViewport(0, 0, xdim, ydim);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, xdim, ydim, 0, -1, 1);

    if (videoGetRenderMode() == REND_POLYMER)
    {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    }

    polymost2d = 1;

    buildgl_setDisabled(GL_DEPTH_TEST);
    buildgl_setDisabled(GL_BLEND);
#endif
}

repo_name: orochi/nblood

license: mit


code:
/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
       Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
       Non-NIB-Code & other changes: Max Horn <max@quendi.de>

    Feel free to customize this file to suit your needs

    Modified for EDuke32
*/

#import <Foundation/Foundation.h>
#include <TargetConditionals.h>

#if TARGET_OS_MAC

#include "compat.h"

#import <AppKit/AppKit.h>

#include "sdl_inc.h"

#import <Cocoa/Cocoa.h>

#include <sys/param.h> /* for MAXPATHLEN */

/* For some reason, Apple removed setAppleMenu from the headers in 10.4,
 but the method still is there and works. To avoid warnings, we declare
 it ourselves here. */
@interface NSApplication(SDL_Missing_Methods)
- (void)setAppleMenu:(NSMenu *)menu;
@end

/* Use this flag to determine whether we use CPS (docking) or not */
#define		SDL_USE_CPS
#ifdef SDL_USE_CPS

#ifdef __cplusplus
extern "C" {
#endif

/* Portions of CPS.h */
typedef struct CPSProcessSerNum
{
	UInt32		lo;
	UInt32		hi;
} CPSProcessSerNum;

extern OSErr	CPSGetCurrentProcess( CPSProcessSerNum *psn);
extern OSErr 	CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
extern OSErr	CPSSetFrontProcess( CPSProcessSerNum *psn);

#ifdef __cplusplus
}
#endif

#endif /* SDL_USE_CPS */

static int    gArgc;
static char  **gArgv;
static BOOL   gFinderLaunch;
static BOOL   gCalledAppMainline = FALSE;

static id nsapp;

static NSString *getApplicationName(void)
{
    const NSDictionary *dict;
    NSString *appName = 0;

    /* Determine the application name */
    dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
    if (dict)
        appName = [dict objectForKey: @"CFBundleName"];

    if (![appName length])
        appName = [[NSProcessInfo processInfo] processName];

    return appName;
}

@interface NSApplication (SDLApplication)
@end

@implementation NSApplication (SDLApplication)
/* Invoked from the Quit menu item */
- (void)terminateCall:(id)sender
{
    /* Post a SDL_QUIT event */
    SDL_Event event;
    event.type = SDL_QUIT;
    SDL_PushEvent(&event);

    UNREFERENCED_PARAMETER(sender);
}
@end

@interface SDLMain : NSObject <NSFileManagerDelegate>
@end

/* The main class of the application, the application's delegate */
@implementation SDLMain

/* Set the working directory to the .app's parent directory */
- (void) setupWorkingDirectory:(BOOL)shouldChdir
{
    if (shouldChdir)
    {
        char parentdir[MAXPATHLEN];
        CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
        CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
        if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
            chdir(parentdir);   /* chdir to the binary app's parent */
        }
        CFRelease(url);
        CFRelease(url2);
    }
}

static void setApplicationMenu(void)
{
    /* warning: this code is very odd */
    NSMenu *appleMenu;
    NSMenuItem *menuItem;
    NSString *title;
    NSString *appName;

    appName = getApplicationName();
    appleMenu = [[NSMenu alloc] initWithTitle:@""];

    /* Add menu items */
    title = [@"About " stringByAppendingString:appName];
    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];

    [appleMenu addItem:[NSMenuItem separatorItem]];

    title = [@"Hide " stringByAppendingString:appName];
    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];

    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];

    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];

    [appleMenu addItem:[NSMenuItem separatorItem]];

    title = [@"Quit " stringByAppendingString:appName];
    [appleMenu addItemWithTitle:title action:@selector(terminateCall:) keyEquivalent:@"q"];

    /* Put menu into the menubar */
    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
    [menuItem setSubmenu:appleMenu];
    [[nsapp mainMenu] addItem:menuItem];

    /* Tell the application object that this is now the application menu */
    [nsapp setAppleMenu:appleMenu];

    /* Finally give up our references to the objects */
    [appleMenu release];
    [menuItem release];
}

/* Create a window menu */
static void setupWindowMenu(void)
{
    NSMenu      *windowMenu;
    NSMenuItem  *windowMenuItem;
    NSMenuItem  *menuItem;

    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];

    /* "Minimize" item */
    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
    [windowMenu addItem:menuItem];
    [menuItem release];

    /* Put menu into the menubar */
    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
    [windowMenuItem setSubmenu:windowMenu];
    [[nsapp mainMenu] addItem:windowMenuItem];

    /* Tell the application object that this is now the window menu */
    [nsapp setWindowsMenu:windowMenu];

    /* Finally give up our references to the objects */
    [windowMenu release];
    [windowMenuItem release];
}

/* Replacement for NSApplicationMain */
static void CustomApplicationMain (int argc, char **argv)
{
    NSAutoreleasePool	*pool = [[NSAutoreleasePool alloc] init];
    SDLMain				*sdlMain;

    /* Ensure the application object is initialised */
    nsapp = [NSApplication sharedApplication];

#ifdef SDL_USE_CPS
    {
        CPSProcessSerNum PSN;
        /* Tell the dock about us */
        if (!CPSGetCurrentProcess(&PSN))
            if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
                if (!CPSSetFrontProcess(&PSN))
                    [NSApplication sharedApplication];
    }
#endif /* SDL_USE_CPS */

    /* Set up the menubar */
    [nsapp setMainMenu:[[NSMenu alloc] init]];
    setApplicationMenu();
    setupWindowMenu();

    /* Create SDLMain and make it the app delegate */
    sdlMain = [[SDLMain alloc] init];
    [nsapp setDelegate:sdlMain];

    /* Start the main event loop */
    [nsapp run];

    [sdlMain release];
    [pool release];

    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(argv);
}

/*
 * Catch document open requests...this lets us notice files when the app
 *  was launched by double-clicking a document, or when a document was
 *  dragged/dropped on the app's icon. You need to have a
 *  CFBundleDocumentsType section in your Info.plist to get this message,
 *  apparently.
 *
 * Files are added to gArgv, so to the app, they'll look like command line
 *  arguments. Previously, apps launched from the finder had nothing but
 *  an argv[0].
 *
 * This message may be received multiple times to open several docs on launch.
 *
 * This message is ignored once the app's mainline has been called.
 */
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
    const char *temparg;
    size_t arglen;
    char *arg;
    char **newargv;

    if (!gFinderLaunch)  /* MacOS is passing command line args. */
        return FALSE;

    if (gCalledAppMainline)  /* app has started, ignore this document. */
        return FALSE;

    temparg = [filename UTF8String];
    arglen = SDL_strlen(temparg) + 1;
    arg = (char *) SDL_malloc(arglen);
    if (arg == NULL)
        return FALSE;

    newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
    if (newargv == NULL)
    {
        SDL_free(arg);
        return FALSE;
    }
    gArgv = newargv;

    SDL_strlcpy(arg, temparg, arglen);
    gArgv[gArgc++] = arg;
    gArgv[gArgc] = NULL;

    UNREFERENCED_PARAMETER(theApplication);

    return TRUE;
}

/* Called when the internal event loop has just started running */
- (void) applicationDidFinishLaunching: (NSNotification *) note
{
    int status;

    /* Set the working directory to the .app's parent directory */
    [self setupWorkingDirectory:gFinderLaunch];

    /* Hand off to main application code */
    gCalledAppMainline = TRUE;
    status = SDL_main (gArgc, gArgv);

    UNREFERENCED_PARAMETER(note);

    /* We're done, thank you for playing */
    exit(status);
}
@end

@implementation NSString (ReplaceSubString)

- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
{
    unsigned int bufferSize;
    unsigned int selfLen = [self length];
    unsigned int aStringLen = [aString length];
    unichar *buffer;
    NSRange localRange;
    NSString *result;

    bufferSize = selfLen + aStringLen - aRange.length;
    buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));

    /* Get first part into buffer */
    localRange.location = 0;
    localRange.length = aRange.location;
    [self getCharacters:buffer range:localRange];

    /* Get middle part into buffer */
    localRange.location = 0;
    localRange.length = aStringLen;
    [aString getCharacters:(buffer+aRange.location) range:localRange];

    /* Get last part into buffer */
    localRange.location = aRange.location + aRange.length;
    localRange.length = selfLen - localRange.location;
    [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];

    /* Build output string */
    result = [NSString stringWithCharacters:buffer length:bufferSize];

    NSDeallocateMemoryPages(buffer, bufferSize);

    return result;
}

@end

#ifdef main
#  undef main
#endif

/* Main entry point to executable - should *not* be SDL_main! */
int main (int argc, char **argv)
{
    /* Copy the arguments into a global variable */
    /* This is passed if we are launched by double-clicking */
    if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
        gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
        gArgv[0] = argv[0];
        gArgv[1] = NULL;
        gArgc = 1;
        gFinderLaunch = YES;
    } else {
        int i;
        gArgc = argc;
        gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
        for (i = 0; i <= argc; i++)
            gArgv[i] = argv[i];
        gFinderLaunch = NO;
    }

    CustomApplicationMain (argc, argv);

    return 0;
}

#endif


code:
// A.ASM replacement using C
// Mainly by Ken Silverman, with things melded with my port by
// Jonathon Fowler (jf@jonof.id.au)
//
// "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 (jf@jonof.id.au)
// by the EDuke32 team (development@voidpoint.com)

#include "a.h"
#include "pragmas.h"

#ifdef ENGINE_USING_A_C

#define BITSOFPRECISION 3
#define BITSOFPRECISIONPOW 8

// Compile code to saturate vplc for sprites to prevent stray lines at the
// bottom of non-y-flipped ones?
#define USE_SATURATE_VPLC
// Also for translucent masks?
//#define USE_SATURATE_VPLC_TRANS

extern intptr_t asm1, asm2, asm3, asm4;
extern int32_t globalx3, globaly3;

static int32_t bpl, transmode = 0;
static char *gbuf;
static int32_t glogx, glogy;
int32_t gpinc;
static int32_t gbxinc, gbyinc;
static char *gpal, *ghlinepal, *gtrans;
static char *gpal2;

//Global variable functions
void setvlinebpl(int32_t dabpl) { bpl = dabpl;}
void fixtransluscence(intptr_t datransoff)
{
    gtrans = (char *)datransoff;
}
void settransnormal(void) { transmode = 0; }
void settransreverse(void) { transmode = 1; }

///// Ceiling/floor horizontal line functions /////

void sethlinesizes(int32_t logx, int32_t logy, intptr_t bufplc)
{ glogx = logx; glogy = logy; gbuf = (char *)bufplc; }
void setpalookupaddress(char *paladdr) { ghlinepal = paladdr; }
void setuphlineasm4(int32_t bxinc, int32_t byinc) { gbxinc = bxinc; gbyinc = byinc; }
void hlineasm4(bssize_t cnt, int32_t skiploadincs, int32_t paloffs, uint32_t by, uint32_t bx, intptr_t p)
{
    Bassert(gbuf);

    if (!skiploadincs) { gbxinc = asm1; gbyinc = asm2; }

    const char *const A_C_RESTRICT palptr = &ghlinepal[paloffs];
    const char *const A_C_RESTRICT buf = gbuf;
    const vec2_t inc = { gbxinc, gbyinc };
    const vec2_t log = { glogx, glogy };
    const vec2_t log32 = { 32-log.x, 32-log.y };
    char *pp = (char *)p;

#ifdef CLASSIC_SLICE_BY_4
    for (; cnt>=4; cnt-=4, pp-=4)
    {
#if 1
        *pp = palptr[buf[((bx>>log32.x)<<log.y)+(by>>log32.y)]];
        *(pp-1) = palptr[buf[(((bx-inc.x)>>log32.x)<<log.y)+((by-inc.y)>>log32.y)]];
        *(pp-2) = palptr[buf[(((bx-(inc.x<<1))>>log32.x)<<log.y)+((by-(inc.y<<1))>>log32.y)]];
        *(pp-3) = palptr[buf[(((bx-(inc.x*3))>>log32.x)<<log.y)+((by-(inc.y*3))>>log32.y)]];
#else
        *(int32_t *)(pp-3) = palptr[buf[(((bx-(inc.x*3))>>log32.x)<<log.y)+((by-(inc.y*3))>>log32.y)]] +
            (palptr[buf[(((bx-(inc.x<<1))>>log32.x)<<log.y)+((by-(inc.y<<1))>>log32.y)]]<<8) +
            (palptr[buf[(((bx-inc.x)>>log32.x)<<log.y)+((by-inc.y)>>log32.y)]]<<16) +
            (palptr[buf[((bx>>log32.x)<<log.y)+(by>>log32.y)]]<<24);
#endif
        bx -= inc.x<<2;
        by -= inc.y<<2;
    }
#endif

    for (; cnt>=0; cnt--, pp--)
    {
        *pp = palptr[buf[((bx>>log32.x)<<log.y)+(by>>log32.y)]];
        bx -= inc.x;
        by -= inc.y;
    }
}

///// Sloped ceiling/floor vertical line functions /////
void slopevlin(intptr_t p, int32_t i, intptr_t slopaloffs, bssize_t cnt, int32_t bx, int32_t by)
{
    intptr_t * A_C_RESTRICT slopalptr;
    int32_t bz, bzinc;
    uint32_t u, v;

    bz = asm3; bzinc = (asm1>>3);
    slopalptr = (intptr_t *)slopaloffs;
    for (; cnt>0; cnt--)
    {
        i = (sloptable[(bz>>6)+HALFSLOPTABLESIZ]); bz += bzinc;
        u = bx+(inthi_t)globalx3*i;
        v = by+(inthi_t)globaly3*i;
        (*(char *)p) = *(char *)(((intptr_t)slopalptr[0])+gbuf[((u>>(32-glogx))<<glogy)+(v>>(32-glogy))]);
        slopalptr--;
        p += gpinc;
    }
}

///// Wall,face sprite/wall sprite vertical line functions /////

extern int32_t globaltilesizy;

static inline uint32_t ourmulscale32(uint32_t a, uint32_t b)
{
    return ((uint64_t)a*b)>>32;
}

static inline int32_t getpix(int32_t logy, const char *buf, uint32_t vplc)
{
    return logy ? buf[vplc>>logy] : buf[ourmulscale32(vplc,globaltilesizy)];
}

void setupvlineasm(int32_t neglogy) { glogy = neglogy; }
// cnt+1 loop iterations!
int32_t vlineasm1(int32_t vinc, intptr_t paloffs, bssize_t cnt, uint32_t vplc, intptr_t bufplc, intptr_t p)
{
    const char *const A_C_RESTRICT buf = (char *)bufplc;
    const char *const A_C_RESTRICT pal = (char *)paloffs;
    const int32_t logy = glogy, ourbpl = bpl;
    char *pp = (char *)p;

    cnt++;

    if (logy)
    {
#ifdef CLASSIC_SLICE_BY_4
        for (; cnt>=4; cnt-=4)
        {
            *pp = pal[buf[vplc>>logy]];
            *(pp+ourbpl) = pal[buf[(vplc+vinc)>>logy]];
            *(pp+(ourbpl<<1)) = pal[buf[(vplc+(vinc<<1))>>logy]];
            *(pp+(ourbpl*3)) = pal[buf[(vplc+(vinc*3))>>logy ]];
            pp += ourbpl<<2;
            vplc += vinc<<2;
        }
#endif
        while (cnt--)
        {
            *pp = pal[buf[vplc>>logy]];
            pp += ourbpl;
            vplc += vinc;
        }
    }
    else
    {
#ifdef CLASSIC_SLICE_BY_4
        for (; cnt>=4; cnt-=4)
        {
            *pp = pal[buf[ourmulscale32(vplc, globaltilesizy)]];
            *(pp+ourbpl) = pal[buf[ourmulscale32((vplc+vinc),globaltilesizy)]];
            *(pp+(ourbpl<<1)) = pal[buf[ourmulscale32((vplc+(vinc<<1)), globaltilesizy)]];
            *(pp+(ourbpl*3)) = pal[buf[ourmulscale32((vplc+(vinc*3)), globaltilesizy)]];
            pp += ourbpl<<2;
            vplc += vinc<<2;
        }
#endif
        while (cnt--)
        {
            *pp = pal[buf[ourmulscale32(vplc,globaltilesizy)]], pp += ourbpl;
            vplc += vinc;
        }
    }
    return vplc;
}

extern intptr_t palookupoffse[4];
extern uint32_t vplce[4];
extern int32_t vince[4];
extern intptr_t bufplce[4];

#if (EDUKE32_GCC_PREREQ(4,7) || __has_extension(attribute_ext_vector_type)) && defined BITNESS64
// XXX: The "Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)"
// does not compile us with USE_VECTOR_EXT. Maybe a newer one does?
# if !defined __clang__
#  define USE_VECTOR_EXT
# endif
#endif

#ifdef USE_VECTOR_EXT
typedef uint32_t uint32_vec4 __attribute__ ((vector_size (16)));
#endif

#ifdef USE_SATURATE_VPLC
# define saturate_vplc(vplc, vinc) vplc |= g_saturate & -(vplc < (uint32_t)vinc)
// NOTE: the vector types yield -1 for logical "true":
# define saturate_vplc_vec(vplc, vinc) vplc |= g_saturate & (vplc < vinc)
# ifdef USE_SATURATE_VPLC_TRANS
#  define saturate_vplc_trans(vplc, vinc) saturate_vplc(vplc, vinc)
# else
#  define saturate_vplc_trans(vplc, vinc)
# endif
#else
# define saturate_vplc(vplc, vinc)
# define saturate_vplc_vec(vplc, vinc)
# define saturate_vplc_trans(vplc, vinc)
#endif

#ifdef CLASSIC_NONPOW2_YSIZE_WALLS
// cnt >= 1
static void vlineasm4nlogy(bssize_t cnt, char *p, char *const A_C_RESTRICT * pal, char *const A_C_RESTRICT * buf,
# ifdef USE_VECTOR_EXT
    uint32_vec4 vplc, const uint32_vec4 vinc)
# else
    uint32_t * vplc, const int32_t *vinc)
# endif
{
    const int32_t ourbpl = bpl;

    do
    {
        p[0] = pal[0][buf[0][ourmulscale32(vplc[0], globaltilesizy)]];
        p[1] = pal[1][buf[1][ourmulscale32(vplc[1], globaltilesizy)]];
        p[2] = pal[2][buf[2][ourmulscale32(vplc[2], globaltilesizy)]];
        p[3] = pal[3][buf[3][ourmulscale32(vplc[3], globaltilesizy)]];

# if defined USE_VECTOR_EXT
        vplc += vinc;
# else
        vplc[0] += vinc[0];
        vplc[1] += vinc[1];
        vplc[2] += vinc[2];
        vplc[3] += vinc[3];
# endif
        p += ourbpl;
    } while (--cnt);

    Bmemcpy(&vplce[0], &vplc[0], sizeof(uint32_t) * 4);
}
#endif

// cnt >= 1
void vlineasm4(bssize_t cnt, char *p)
{
    char * const A_C_RESTRICT pal[4] = {(char *)palookupoffse[0], (char *)palookupoffse[1], (char *)palookupoffse[2], (char *)palookupoffse[3]};
    char * const A_C_RESTRICT buf[4] = {(char *)bufplce[0], (char *)bufplce[1], (char *)bufplce[2], (char *)bufplce[3]};
#ifdef USE_VECTOR_EXT
    uint32_vec4 vinc = {(uint32_t)vince[0], (uint32_t)vince[1], (uint32_t)vince[2], (uint32_t)vince[3]};
    uint32_vec4 vplc = {vplce[0], vplce[1], vplce[2], vplce[3]};
#else
    const int32_t vinc[4] = {vince[0], vince[1], vince[2], vince[3]};
    uint32_t vplc[4] = {vplce[0], vplce[1], vplce[2], vplce[3]};
#endif
    const int32_t logy = glogy, ourbpl = bpl;

#ifdef CLASSIC_NONPOW2_YSIZE_WALLS
    if (EDUKE32_PREDICT_FALSE(!logy))
    {
        // This should only happen when 'globalshiftval = 0' has been set in engine.c.
        vlineasm4nlogy(cnt, p, pal, buf, vplc, vinc);
        return;
    }
#else
    assert(logy);
#endif

    // just fucking shoot me
#ifdef CLASSIC_SLICE_BY_4
    for (; cnt>=4;cnt-=4)
    {
        p[0]                = pal[0][buf[0][ vplc[0]>>logy ]];
        p[1]                = pal[1][buf[1][ vplc[1]>>logy ]];
        p[2]                = pal[2][buf[2][ vplc[2]>>logy ]];
        p[3]                = pal[3][buf[3][ vplc[3]>>logy ]];
        (p+ourbpl)[0]       = pal[0][buf[0][ (vplc[0]+vinc[0])>>logy ]];
        (p+ourbpl)[1]       = pal[1][buf[1][ (vplc[1]+vinc[1])>>logy ]];
        (p+ourbpl)[2]       = pal[2][buf[2][ (vplc[2]+vinc[2])>>logy ]];
        (p+ourbpl)[3]       = pal[3][buf[3][ (vplc[3]+vinc[3])>>logy ]];
        (p+(ourbpl<<1))[0]  = pal[0][buf[0][ (vplc[0]+(vinc[0]<<1))>>logy ]];
        (p+(ourbpl<<1))[1]  = pal[1][buf[1][ (vplc[1]+(vinc[1]<<1))>>logy ]];
        (p+(ourbpl<<1))[2]  = pal[2][buf[2][ (vplc[2]+(vinc[2]<<1))>>logy ]];
        (p+(ourbpl<<1))[3]  = pal[3][buf[3][ (vplc[3]+(vinc[3]<<1))>>logy ]];
        (p+(ourbpl*3))[0]   = pal[0][buf[0][ (vplc[0]+(vinc[0]*3))>>logy ]];
        (p+(ourbpl*3))[1]   = pal[1][buf[1][ (vplc[1]+(vinc[1]*3))>>logy ]];
        (p+(ourbpl*3))[2]   = pal[2][buf[2][ (vplc[2]+(vinc[2]*3))>>logy ]];
        (p+(ourbpl*3))[3]   = pal[3][buf[3][ (vplc[3]+(vinc[3]*3))>>logy ]];

#if defined USE_VECTOR_EXT
        vplc += vinc<<2;
#else
        vplc[0] += vinc[0]<<2;
        vplc[1] += vinc[1]<<2;
        vplc[2] += vinc[2]<<2;
        vplc[3] += vinc[3]<<2;
#endif
        p += ourbpl<<2;
    }
#endif

    while (cnt--)
    {
        p[0] = pal[0][buf[0][vplc[0]>>logy]];
        p[1] = pal[1][buf[1][vplc[1]>>logy]];
        p[2] = pal[2][buf[2][vplc[2]>>logy]];
        p[3] = pal[3][buf[3][vplc[3]>>logy]];

#if defined USE_VECTOR_EXT
        vplc += vinc;
#else
        vplc[0] += vinc[0];
        vplc[1] += vinc[1];
        vplc[2] += vinc[2];
        vplc[3] += vinc[3];
#endif
        p += ourbpl;
    }

    Bmemcpy(&vplce[0], &vplc[0], sizeof(uint32_t) * 4);
}

#ifdef USE_SATURATE_VPLC
static int32_t g_saturate;  // -1 if saturating vplc is requested, 0 else
# define set_saturate(dosaturate) g_saturate = -(int)!!dosaturate
#else
# define set_saturate(dosaturate) UNREFERENCED_PARAMETER(dosaturate)
#endif

void setupmvlineasm(int32_t neglogy, int32_t dosaturate)
{
    glogy = neglogy;
    set_saturate(dosaturate);
}

// cnt+1 loop iterations!
int32_t mvlineasm1(int32_t vinc, intptr_t paloffs, bssize_t cnt, uint32_t vplc, intptr_t bufplc, intptr_t p)
{
    char ch;

    const char *const A_C_RESTRICT buf = (char *)bufplc;
    const char *const A_C_RESTRICT pal = (char *)paloffs;
    const int32_t logy = glogy, ourbpl = bpl;
    char *pp = (char *)p;

    cnt++;

    if (!logy)
    {
        do
        {
            ch = buf[ourmulscale32(vplc,globaltilesizy)];
            if (ch != 255) *pp = pal[ch];
            pp += ourbpl;
            vplc += vinc;
            saturate_vplc(vplc, vinc);
        }
        while (--cnt);

        return vplc;
    }

    do
    {

        if (buf[vplc>>logy] != 255)
            *pp = pal[buf[vplc>>logy]];
        pp += ourbpl;
        vplc += vinc;
        saturate_vplc(vplc, vinc);
    }
    while (--cnt);

    return vplc;
}

// cnt >= 1
void mvlineasm4(bssize_t cnt, char *p)
{
    char *const A_C_RESTRICT pal[4] = {(char *)palookupoffse[0], (char *)palookupoffse[1], (char *)palookupoffse[2], (char *)palookupoffse[3]};
    char *const A_C_RESTRICT buf[4] = {(char *)bufplce[0], (char *)bufplce[1], (char *)bufplce[2], (char *)bufplce[3]};
#ifdef USE_VECTOR_EXT
    uint32_vec4 vinc = {(uint32_t)vince[0], (uint32_t)vince[1], (uint32_t)vince[2], (uint32_t)vince[3]};
    uint32_vec4 vplc = {vplce[0], vplce[1], vplce[2], vplce[3]};
#else
    const int32_t vinc[4] = {vince[0], vince[1], vince[2], vince[3]};
    uint32_t vplc[4] = {vplce[0], vplce[1], vplce[2], vplce[3]};
#endif
    const int32_t logy = glogy, ourbpl = bpl;
    char ch;

    if (logy)
    {
        do
        {
            ch = buf[0][vplc[0]>>logy];
            if (ch != 255) p[0] = pal[0][ch];
            ch = buf[1][vplc[1]>>logy];
            if (ch != 255) p[1] = pal[1][ch];
            ch = buf[2][vplc[2]>>logy];
            if (ch != 255) p[2] = pal[2][ch];
            ch = buf[3][vplc[3]>>logy];
            if (ch != 255) p[3] = pal[3][ch];

#if !defined USE_VECTOR_EXT
            vplc[0] += vinc[0];
            vplc[1] += vinc[1];
            vplc[2] += vinc[2];
            vplc[3] += vinc[3];
            saturate_vplc(vplc[0], vinc[0]);
            saturate_vplc(vplc[1], vinc[1]);
            saturate_vplc(vplc[2], vinc[2]);
            saturate_vplc(vplc[3], vinc[3]);
#else
            vplc += vinc;
            saturate_vplc_vec(vplc, vinc);
#endif
            p += ourbpl;
        }
        while (--cnt);
    }
    else
    {
        do
        {
            ch = buf[0][ourmulscale32(vplc[0],globaltilesizy)];
            if (ch != 255) p[0] = pal[0][ch];
            ch = buf[1][ourmulscale32(vplc[1],globaltilesizy)];
            if (ch != 255) p[1] = pal[1][ch];
            ch = buf[2][ourmulscale32(vplc[2],globaltilesizy)];
            if (ch != 255) p[2] = pal[2][ch];
            ch = buf[3][ourmulscale32(vplc[3],globaltilesizy)];
            if (ch != 255) p[3] = pal[3][ch];

#if !defined USE_VECTOR_EXT
            vplc[0] += vinc[0];
            vplc[1] += vinc[1];
            vplc[2] += vinc[2];
            vplc[3] += vinc[3];
            saturate_vplc(vplc[0], vinc[0]);
            saturate_vplc(vplc[1], vinc[1]);
            saturate_vplc(vplc[2], vinc[2]);
            saturate_vplc(vplc[3], vinc[3]);
#else
            vplc += vinc;
            saturate_vplc_vec(vplc, vinc);
#endif
            p += ourbpl;
        }
        while (--cnt);
    }

    Bmemcpy(&vplce[0], &vplc[0], sizeof(uint32_t) * 4);
}

void setuptvlineasm(int32_t neglogy, int32_t dosaturate)
{
    glogy = neglogy;
    set_saturate(dosaturate);
}

// cnt+1 loop iterations!
int32_t tvlineasm1(int32_t vinc, intptr_t paloffs, bssize_t cnt, uint32_t vplc, intptr_t bufplc, intptr_t p)
{
    char ch;

    const char *const A_C_RESTRICT buf = (char *)bufplc;
    const char *const A_C_RESTRICT pal = (char *)paloffs;
    const char *const A_C_RESTRICT trans = (char *)gtrans;
    const int32_t logy = glogy, ourbpl = bpl, transm = transmode;
    char *pp = (char *)p;

    cnt++;

    uint8_t const shift = transm<<3;

    do
    {
        ch = getpix(logy, buf, vplc);
        if (ch != 255) *pp = trans[((*pp)<<(8-shift))|(pal[ch]<<shift)];
        pp += ourbpl;
        vplc += vinc;
        saturate_vplc_trans(vplc, vinc);
    }
    while (--cnt);

    return vplc;
}

void setuptvlineasm2(int32_t neglogy, intptr_t paloffs1, intptr_t paloffs2)
{
    glogy = neglogy;
    gpal = (char *)paloffs1;
    gpal2 = (char *)paloffs2;
}

// Pass: asm1=vinc2, asm2=pend
// Return: asm1=vplc1, asm2=vplc2
void tvlineasm2(uint32_t vplc2, int32_t vinc1, intptr_t bufplc1, intptr_t bufplc2, uint32_t vplc1, intptr_t p)
{
    char ch;

    bssize_t cnt = tabledivide32(asm2-p-1, bpl);  // >= 1
    const int32_t vinc2 = asm1;

    const char *const A_C_RESTRICT buf1 = (char *)bufplc1;
    const char *const A_C_RESTRICT buf2 = (char *)bufplc2;
    const int32_t logy = glogy, ourbpl = bpl, transm = transmode;

    char *pp = (char *)p;

    cnt++;

    uint8_t const shift = transm<<3;

    do
    {
        ch = getpix(logy, buf1, vplc1);
        if (ch != 255) pp[0] = gtrans[(pp[0]<<(8-shift))|(gpal[ch]<<shift)];
        vplc1 += vinc1;
        saturate_vplc_trans(vplc1, vinc1);

        ch = getpix(logy, buf2, vplc2);
        if (ch != 255) pp[1] = gtrans[(pp[1]<<(8-shift))|(gpal2[ch]<<shift)];
        vplc2 += vinc2;
        saturate_vplc_trans(vplc2, vinc2);

        pp += ourbpl;
    }
    while (--cnt > 0);

    asm1 = vplc1;
    asm2 = vplc2;
}

//Floor sprite horizontal line functions
void msethlineshift(int32_t logx, int32_t logy) { glogx = logx; glogy = logy; }
// cntup16>>16 + 1 iterations
void mhline(intptr_t bufplc, uint32_t bx, int32_t cntup16, int32_t junk, uint32_t by, intptr_t p)
{
    char ch;

    const int32_t xinc = asm1, yinc = asm2;

    UNREFERENCED_PARAMETER(junk);

    gbuf = (char *)bufplc;
    gpal = (char *)asm3;

    cntup16>>=16;
    cntup16++;
    do
    {
        ch = gbuf[((bx>>(32-glogx))<<glogy)+(by>>(32-glogy))];
        if (ch != 255) *((char *)p) = gpal[ch];
        bx += xinc;
        by += yinc;
        p++;
    }
    while (--cntup16);
}

void tsethlineshift(int32_t logx, int32_t logy) { glogx = logx; glogy = logy; }
// cntup16>>16 + 1 iterations
void thline(intptr_t bufplc, uint32_t bx, int32_t cntup16, int32_t junk, uint32_t by, intptr_t p)
{
    char ch;

    const int32_t xinc = asm1, yinc = asm2;

    UNREFERENCED_PARAMETER(junk);

    gbuf = (char *)bufplc;
    gpal = (char *)asm3;

    cntup16>>=16;
    cntup16++;

    uint8_t const shift = transmode<<3;

    do
    {
        ch = gbuf[((bx>>(32-glogx))<<glogy)+(by>>(32-glogy))];
        if (ch != 255) *((char *)p) = gtrans[((*((char *)p))<<(8-shift))|(gpal[ch]<<shift)];
        bx += xinc;
        by += yinc;
        p++;
    }
    while (--cntup16);
}

//Rotatesprite vertical line functions
void setupspritevline(intptr_t paloffs, int32_t bxinc, int32_t byinc, int32_t ysiz)
{
    gpal = (char *)paloffs;
    gbxinc = bxinc;
    gbyinc = byinc;
    glogy = ysiz;
}
void spritevline(int32_t bx, int32_t by, bssize_t cnt, intptr_t bufplc, intptr_t p)
{
    gbuf = (char *)bufplc;
    for (; cnt>1; cnt--)
    {
        (*(char *)p) = gpal[gbuf[(bx>>16)*glogy+(by>>16)]];
        bx += gbxinc;
        by += gbyinc;
        p += bpl;
    }
}

//Rotatesprite vertical line functions
void msetupspritevline(intptr_t paloffs, int32_t bxinc, int32_t byinc, int32_t ysiz)
{
    gpal = (char *)paloffs;
    gbxinc = bxinc;
    gbyinc = byinc;
    glogy = ysiz;
}
void mspritevline(int32_t bx, int32_t by, bssize_t cnt, intptr_t bufplc, intptr_t p)
{
    char ch;

    gbuf = (char *)bufplc;
    for (; cnt>1; cnt--)
    {
        ch = gbuf[(bx>>16)*glogy+(by>>16)];
        if (ch != 255) (*(char *)p) = gpal[ch];
        bx += gbxinc;
        by += gbyinc;
        p += bpl;
    }
}

void tsetupspritevline(intptr_t paloffs, int32_t bxinc, int32_t byinc, int32_t ysiz)
{
    gpal = (char *)paloffs;
    gbxinc = bxinc;
    gbyinc = byinc;
    glogy = ysiz;
}
void tspritevline(int32_t bx, int32_t by, bssize_t cnt, intptr_t bufplc, intptr_t p)
{
    char ch;

    gbuf = (char *)bufplc;

    uint8_t const shift = transmode<<3;

    for (; cnt>1; cnt--)
    {
        ch = gbuf[(bx>>16)*glogy+(by>>16)];
        if (ch != 255) *((char *)p) =  gtrans[((*((char *)p))<<(8-shift))+(gpal[ch]<<shift)];
        bx += gbxinc;
        by += gbyinc;
        p += bpl;
    }
}

void setupdrawslab(int32_t dabpl, intptr_t pal)
{
    bpl  = dabpl;
    gpal = (char *)pal;
}

void drawslab(int32_t dx, int32_t v, int32_t dy, int32_t vi, intptr_t vptr, intptr_t p)
{
    do
    {
        char const c = gpal[(int32_t)(*(char *)((v>>16)+vptr))];
        for (int x=0; x < dx; x++)
            ((char*)p)[x] = c;
        p += bpl;
        v += vi;
    }
    while (--dy);
}

#if 0
void stretchhline(intptr_t p0, int32_t u, bssize_t cnt, int32_t uinc, intptr_t rptr, intptr_t p)
{
    p0 = p-(cnt<<2);
    do
    {
        p--;
        *(char *)p = *(char *)((u>>16)+rptr); u -= uinc;
    }
    while (p > p0);
}
#endif

#endif
/*
 * vim:ts=4:
 */