//==========================================================================
        /*
        ====================
        =
        = SC_ScaleShape
        =
        = Scales the shape centered on x,y to size scale (256=1:1, 512=2:1, etc)
        =
        = Clips to scalexl/scalexh, scaleyl/scaleyh
        = Returns true if something was drawn
        =
        = Must be called in write mode 2!
        =
        ====================
        */
        private bool SC_ScaleShape(short x, short y, ushort scale, memptr shape)
        {
            short scalechop = (short) (scale / SCALESTEP - 1);

            if(scalechop < 0)
                return false; // can't scale this size

            if(scalechop >= DISCREETSCALES)
                scalechop = DISCREETSCALES - 1;

            memptr basetoscreenptr = new memptr(basetableseg, basetables[scalechop]);
            memptr screentobaseptr = new memptr(screentableseg, screentables[scalechop]);

            //
            // figure bounding rectangle for scaled image
            //
            scaleshape scaleshape_shape = new scaleshape(shape);
            ushort fullwidth = (ushort) scaleshape_shape.width;
            ushort fullheight = (ushort) scaleshape_shape.height;

            ushort scalewidth = (ushort) (fullwidth * ((scalechop + 1) * SCALESTEP) / BASESCALE);
            ushort scaleheight = basetoscreenptr.GetUInt8(fullheight - 1);

            short xl = (short) (x - scalewidth / 2);
            short xh = (short) (xl + scalewidth - 1);
            short yl = (short) (y - scaleheight / 2);
            short yh = (short) (yl + scaleheight - 1);

            // off screen?
            if(xl > scalexh || xh < scalexl || yl > scaleyh || yh < scaleyl)
                return false;

            //
            // clip to sides of screen
            //
            short sxl;
            if(xl < scalexl)
                sxl = scalexl;
            else
                sxl = xl;

            short sxh;
            if(xh > scalexh)
                sxh = scalexh;
            else
                sxh = xh;

            //
            // clip both sides to zbuffer
            //
            short sx = sxl;
            while(sx <= sxh && zbuffer[sx] > scale) // as: re-ordered to prevent out of bounds read
                sx++;

            sxl = sx;

            sx = sxh;
            while(sx > sxl && zbuffer[sx] > scale) // as: re-ordered to prevent out of bounds read
                sx--;

            sxh = sx;

            if(sxl > sxh)
                return false; // behind a wall

            //
            // save block info for background erasing
            //
            ushort screencorner = (ushort) (screenofs + yl * linewidth);

            scaleblockdest = (ushort) (screencorner + sxl / 8);
            scaleblockwidth = (ushort) (sxh / 8 - sxl / 8 + 1);
            scaleblockheight = (ushort) (yh - yl + 1);

            //
            // start drawing
            //
            for(sx = sxl; sx <= sxh; sx++)
            {
                short shapex = screentobaseptr.GetUInt8(sx - xl);
                ushort shapeofs = scaleshape_shape.first(shapex);
                if(shapeofs != 0)
                {
                    short width = 1; // as: added for line drawing
                    ushort mask = masktable[sx];
                    if(scale > BASESCALE)
                    {
                        //
                        // make a multiple pixel scale pass if possible
                        //
                        while(((sx & 7) != 7) && (screentobaseptr.GetUInt8(sx + 1 - xl) == shapex))
                        {
                            sx++;
                            mask |= masktable[sx];
                            width++;
                        }
                    }

                    // Draw vertical spans
                    do
                    {
                        scaleseg shapeptr = new scaleseg(shape, shapeofs);

                        ushort yoffset = basetoscreenptr.GetUInt8(shapeptr.start); // pixels on screen to be skipped

                        short offset = 0;
                        if(width > 1)
                            offset = (short) (width - 1);

                        // as: added start x and width
                        ScaleLine(
                            basetoscreenptr.GetUInt8(shapeptr.length),
                            screentobaseptr,
                            shapeptr.PointerToData(0),
                            (ushort) (screencorner + ylookup[yoffset]),
                            sx - offset, width);

                        shapeofs = shapeptr.next;

                    } while(shapeofs != 0);
                }
            }

            return true;
        }
        /*
        ===========================
        =
        = MakeShape
        =
        = Takes a raw bit map of width bytes by height and creates a scaleable shape
        =
        = Returns the length of the shape in bytes
        =
        ===========================
        */
        private void SC_MakeShape(memptr src, short width, short height, ref memptr shapeseg)
        {
            short pixwidth = (short) (width * 8);

            memptr tempseg_memptr = new memptr(); // as: added
            MMGetPtr(ref tempseg_memptr, pixwidth * (height + 20)); // larger than needed buffer

            scaleshape tempseg = new scaleshape(tempseg_memptr);

            tempseg.width = pixwidth; // pixel dimensions
            tempseg.height = height;

            //
            // convert ega pixels to byte color values in a temp buffer
            //
            // Stored in a collumn format, not rows!
            //
            memptr byteseg = new memptr();
            MMGetPtr(ref byteseg, pixwidth * height);

            memptr byteptr = new memptr(byteseg);

            memptr plane0 = new memptr(src);
            memptr plane1 = new memptr(plane0, width * height);
            memptr plane2 = new memptr(plane1, width * height);
            memptr plane3 = new memptr(plane2, width * height);

            for(short x = 0; x < width; x++)
            {
                for(ushort b = 0; b < 8; b++)
                {
                    ushort shift = (ushort) (8 - b);
                    ushort offset = (ushort) x;

                    for(short y = 0; y < height; y++)
                    {
                        byte by0 = plane0.GetUInt8(offset);
                        byte by1 = plane1.GetUInt8(offset);
                        byte by2 = plane2.GetUInt8(offset);
                        byte by3 = plane3.GetUInt8(offset);
                        offset += (ushort) width;

                        ushort color = 0;

                        // as: converted from asm
                        color |= AsmRotate(by3, shift);
                        color <<= 1;
                        color |= AsmRotate(by2, shift);
                        color <<= 1;
                        color |= AsmRotate(by1, shift);
                        color <<= 1;
                        color |= AsmRotate(by0, shift);

                        byteptr.SetUInt8(0, (byte) color);
                        byteptr.Offset(1);
                    } // Y
                } // B
            } // X

            //
            // convert byte map to sparse scaling format
            //
            memptr saveptr = tempseg.PointerTofirst(pixwidth);

            // start filling in data after all pointers to line segments
            byteptr = new memptr(byteseg); // first pixel in byte array

            for(short x = 0; x < pixwidth; x++)
            {
                //
                // each vertical line can have 0 or more segments of pixels in it
                //
                short y = 0;
                memptr segptr = tempseg.PointerTofirst(x);
                segptr.SetUInt16(0, 0); // in case there are no segments on line
                do
                {
                    // scan for first pixel to be scaled
                    while(y < height && byteptr.GetUInt8(0) == BACKGROUND) // as: bugfix - re-ordered to prevent out of bounds read
                    {
                        byteptr.Offset(1);
                        y++;
                    }

                    if(y == height) // if not, the line is finished
                        continue;

                    //
                    // start a segment by pointing the last link (either shape.first[x] if it
                    // is the first segment, or a seg.next if not) to the current spot in
                    // the tempseg, setting segptr to this segments next link, and copying
                    // all the pixels in the segment
                    //
                    segptr.SetUInt16(0, _sys.FP_OFF(saveptr)); // pointer to start of this segment

                    short start = y;
                    short length = 0;

                    scaleseg scale_seg = new scaleseg(saveptr);

                    memptr dataptr = scale_seg.PointerToData(0);

                    //
                    // copy bytes in the segment to the shape
                    //
                    while(y < height && byteptr.GetUInt8(0) != BACKGROUND) // as: bugfix - re-ordered to prevent out of bounds read
                    {
                        length++;
                        dataptr.SetUInt8(0, byteptr.GetUInt8(0));
                        dataptr.Offset(1);
                        byteptr.Offset(1);
                        y++;
                    }

                    scale_seg.start = start;
                    scale_seg.length = length;
                    scale_seg.next = 0;

                    // get ready for next segment
                    segptr = new memptr(saveptr, scaleseg.FieldOffset_next);

                    saveptr = dataptr; // next free byte to be used

                } while(y < height);
            }

            //
            // allocate exact space needed and copy shape to it, then free buffers
            //
            MMGetPtr(ref shapeseg, _sys.FP_OFF(saveptr));
            Array.Copy(tempseg.Pointer.Buffer, shapeseg.Buffer, _sys.FP_OFF(saveptr));
            MMFreePtr(ref byteseg);
            MMFreePtr(ref tempseg_memptr);
        }