/* ;=========================================================================== ; ; 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; } }
//========================================================================== /* ==================== = = 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; }
/* ====================== = = 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); } } }
/* =========================== = = 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); }