Ejemplo n.º 1
0
        /*
        ;===========================================================================
        ;
        ;                    SCALING GRAPHICS
        ;
        ;===========================================================================
        */
        /*
        ;================
        ;
        ; doline
        ;
        ; Big unwound scaling routine
        ;
        ;================

        ;==================================================
        ;
        ; void scaleline (int scale, unsigned picseg, unsigned maskseg,
        ;                 unsigned screen, unsigned width)
        ;
        ;==================================================
        */
        private void ScaleLine(ushort pixels, memptr scaleptr, memptr picptr, ushort screen, int x, int width)
        {
            // as: Functional Description:
            // This function modified the code in the subroutine doline to limit the number of pixels drawn to
            // the value specified by "pixels", after doline completed the previous code was then restored
            // Adapted for simpler display emulation
            //
            // dx = linewidth
            // es:di = Pointer to screen
            // ds:si = Pointer to scaling lookup table
            // as:bx = Pointer to picture
            // doline is called
            // doline is restored
            // return
            //
            // doline
            //      This function is up to 256 draw pixel operations, ScaleLine modifies the code depending upon the length of the
            //      line segment to draw writing a "mov ss, cx" followed by a "ret" instruction at the appropriate position
            //  cx <- ss : Save Stack Segment in CX
            //  { // This section repeated 256 times
            //      al <- [ds:si], si++ // This is the scaled pixel index (ds:si = pointer to scaling lookup table)
            //      al <- [ss:bx + al] // Read the pixel (ss:bx = pointer to picture)
            //      al <- [es:di] // Read video ram to latches, write pixel to screen
            //      di += dx // Next line down screen
            //  }
            //  ss <- cx : Restore Stack Segment from CX
            //  return

            int dstIndex = screen * Display.AddressScale + x;
            byte[] videoBuffer = _display.VideoBuffer;
            for(int i = 0; i < pixels; i++)
            {
                byte offset = scaleptr.GetUInt8(i);
                byte color = picptr.GetUInt8(offset);

                for(int j = 0; j < width; j++)
                    videoBuffer[dstIndex + j] = color;

                dstIndex += _display.Stride;
            }
        }
Ejemplo n.º 2
0
        //==========================================================================
        /*
        ====================
        =
        = 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;
        }
Ejemplo n.º 3
0
        /*
        ======================
        =
        = HuffExpand
        =
        ======================
        */
        public static void HuffExpand(byte[] sourceBuffer, int sourceIndex, byte[] destBuffer, int destIndex, int length, huffnode hufftable)
        {
            memptr source = new memptr(sourceBuffer, sourceIndex);
            memptr dest = new memptr(destBuffer, destIndex);

            ushort bit, _byte, code;
            huffnode nodeon, headptr;

            headptr = new huffnode(hufftable, 254); // head node is allways node 254

            // as: The disabled C code that was in this function appears to be the C version of the asm code
            // this came in handy during the conversion

            nodeon = new huffnode(headptr);

            // as: bugfix - refactored to prevent the out of bounds read that can occur occasionally with the final byte
            bit = 256;
            _byte = 0;
            while(length != 0)
            {
                if(bit == 256)
                {
                    bit = 1;
                    _byte = source.GetUInt8(0);
                    source.Offset(1);
                }

                if((_byte & bit) != 0)
                    code = nodeon.bit1;
                else
                    code = nodeon.bit0;

                bit <<= 1;

                if(code < 256)
                {
                    dest.SetUInt8(0, (byte) code);
                    dest.Offset(1);
                    nodeon = headptr;
                    length--;
                }
                else
                {
                    nodeon = new huffnode(hufftable, code - 256);
                }
            }
        }
Ejemplo n.º 4
0
        /*
        ===========================
        =
        = 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);
        }