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