MODULE Raster; (** non-portable *) (* eos, TF **) (** AUTHOR "eos"; PURPOSE "Raster operations"; *) (** Raster image bitmaps and basic image processing **) (* 19.9.1999 - spawned from GfxMaps 25.10.1999 - fixed bytes-per-row calculation in Create (need to make arguments LONG) 17.11.1999 - eliminated F8 format, replaced by D8 (implemented with module Colors) 19.11.1999 - fixed missing alpha component in computed palettes 16.05.2000 - module Raster as Oberon-independent part of Images 19.06.2000 - replaced DisplayFormat and InitDisplay by DisplayFormat() 25.02.2006 - raster operations with SSE2 added (student project by Myrto Zehnder) 28.02.2008 - added capabilities for 16-bit palette & grayscale images often used in scientific,medical imaging and professional photography (Patrick Hunziker) To do: - store in compressed format - add capabilities for RGB and multiplane images with >8 bits per color as used in scientific imaging and professional photography *) IMPORT SYSTEM, KernelLog, Machine, Streams, CLUTs, Displays; (* Interfacing with display hardware and foreign framebuffers may suffer a performance hit if their bit or byte ordering can't be made compatible with that of a built-in format and has to be converted manually. Predefined format A1 has the leftmost pixel in the least significant bit of a byte, and all hi/true color formats have their blue component at the lowest address, followed by green, red, and possibly alpha (which conforms to the specification of the transfer formats in Displays). As SYSTEM is imported, the module is not portable and has always to be compiled to native code. However, it should usually suffice to recompile the module on other platforms without changing any code. Assumptions: * CHR(l) = CHR(l MOD 100H) for all l: LONGINT * SIZEOF(LONGINT)=4 *) CONST b* = 0; g* = 1; r* = 2; a* = 3; (** index of blue, green, red, and alpha components in a Pixel **) (** format codes **) custom* = 0; a1* = 1; a8* = 2; d8* = 3; p8* = 4; bgr555* = 5; bgr565* = 6; bgr466* = 7; bgr888* = 8; bgra8888* = 9; p16* =10; (** components **) color* = 0; alpha* = 1; index* = 2; (** compositing operations (srcCopy = replace, srcOverDst = paint **) clear* = 0; srcCopy* = 1; dstCopy* = 2; srcOverDst* = 3; dstOverSrc* = 4; srcInDst* = 5; dstInSrc* = 6; srcWithoutDst* = 7; dstWithoutSrc* = 8; srcAtopDst* = 9; dstAtopSrc* = 10; srcXorDst* = 11; InvDst*=12; InvOverDst*=13; MAXCOL = 10000H; (*current implementation limitation for number of color indexes *) TYPE (** general pixels with red, green, blue, and alpha information in range 0..255; alpha is pre-multiplied into RGB **) Pixel* = ARRAY 4 OF CHAR; (** palette structure for indexed formats **) Palette* = OBJECT VAR col*: POINTER TO ARRAY OF Pixel; (** color table **) used*: LONGINT; (** number of valid entries in color table **) clut: CLUTs.CLUT; (* reverse color lookup structure *) PROCEDURE &New*; BEGIN NEW(col,256); used:=256 END New; (*initialized to 256 colors; for backwards compatibility*) PROCEDURE Init*(used:LONGINT); BEGIN SELF.used:=used; NEW(col,used) END Init; (*initialize to size # 256*) (*bugfix PH090122*) END Palette; (** image format **) Format0* = RECORD code*: SHORTINT; (** format code for quick format checks **) bpp*: SHORTINT; (** number of bits per pixel **) align*: SHORTINT; (** bytes per row must be multiple of this **) components*: SET; (** components that are stored in a pixel **) pal*: Palette; (** optional palette for indexed formats **) END; PackProc* = PROCEDURE (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); Format* = RECORD (Format0) pack*: PackProc; (** store supported pixel components at given address **) unpack*: PackProc; (** load supported pixel components from given address **) END; (** raster image **) Image* = OBJECT (* POINTER TO ImageDesc; ImageDesc* = RECORD *) VAR width*, height*: LONGINT; (** image dimensions **) fmt*: Format; (** pixel format **) bpr*: LONGINT; (** number of bytes per row (may be negative) **) adr*: ADDRESS; (** address of lower left pixel **) mem*: POINTER TO ARRAY OF CHAR; (** block where pixels are stored; mem#NIL implies adr=ADR(mem[0]) **) END Image; (** transfer mode **) Mode0* = RECORD src*, dst*: Format; (** source and destination format **) op*: LONGINT; (** compositing operation **) col*: Pixel; (** substitute color used when transfering from pure alpha formats to colored ones **) buf: Pixel; (* constant area for special-case moving *) map: POINTER TO ARRAY OF INTEGER; (* color map for transfer between indexed formats *) END; TransferProc* = PROCEDURE (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); Mode* = RECORD (Mode0) transfer*: TransferProc; (** procedure transfering pixels from source to destination **) END; PictureTransferParameters* = POINTER TO RECORD img* : Image; name* : ARRAY 128 OF CHAR; done* : BOOLEAN END; VAR A1*, A8*, D8*, BGR555*, BGR565*, BGR466*, BGR888*, BGRA8888*: Format; (** predefined formats **) PixelFormat*: Format; (** special formats **) Clamp*: ARRAY 500H OF CHAR; (** Clamp[200H+i] = CHR(min(max(i, 0), 0FFH)) **) Zero: Pixel; (* pixel with all components cleared *) Bit: ARRAY 100H, 8 OF BOOLEAN; (* Bit[b, i] means bit i in byte b is set *) Set, Clr: ARRAY 100H, 8 OF CHAR; (* Set/Clr[b, i] is byte b with bit i set/cleared *) (* d8display: Displays.Display; (* only one system-wide D8 display supported *) plugin: Plugins.Plugin; *) MMXenabled*,SSE2enabled* : BOOLEAN; (**--- Color/Pixel conversions ---**) (** set pixel to opaque RGB value **) PROCEDURE SetRGB* (VAR pix: Pixel; red, green, blue: LONGINT); CODE LDR R0, [FP, #pix] ; ADDRESSOF(pix[0]) LDRB R1, [FP, #blue] LDRB R2, [FP, #green] LDRB R3, [FP, #red] ANDS R5, R0, #3 ; R0 MOD 4 BNE unaligned_store ; aligned store ORR R1, R1, R2, LSL #8 ORR R1, R1, R3, LSL #16 ORR R1, R1, #0FF000000H STR R1, [R0, #0] B exit unaligned_store: MOV R4, #0FFH STRB R1, [R0, #0] STRB R2, [R0, #1] STRB R3, [R0, #2] STRB R4, [R0, #3] exit: (*BEGIN pix[b] := CHR(blue); pix[g] := CHR(green); pix[r] := CHR(red); pix[a] := 0FFX*) END SetRGB; (** set pixel to partly transparent RGB value **) PROCEDURE SetRGBA* (VAR pix: Pixel; red, green, blue, alpha: LONGINT); CODE LDR R0, [FP, #pix] ; ADDRESSOF(pix[0]) LDRB R1, [FP, #blue] LDRB R2, [FP, #green] LDRB R3, [FP, #red] LDRB R4, [FP, #alpha] CMP R4, #255 BEQ store ; if alpha =255 store colors as they are ; apply alpha to the colors MUL R1, R1, R4 ; blue * alpha MUL R2, R2, R4 ; green * alpha MUL R3, R3, R4 ; red * alpha LSR R1, R1, #8 ; (blue * alpha) DIV 256 LSR R2, R2, #8 ; (green * alpha) DIV 256 LSR R3, R3, #8 ; (red * alpha) DIV 256 store: ANDS R5, R0, #3 ; R0 MOD 4 BNE unaligned_store ; aligned store ORR R1, R1, R2, LSL #8 ORR R1, R1, R3, LSL #16 ORR R1, R1, R4, LSL #24 STR R1, [R0, #0] B exit unaligned_store: STRB R1, [R0, #0] STRB R2, [R0, #1] STRB R3, [R0, #2] STRB R4, [R0, #3] exit: (*BEGIN pix[b] := CHR(blue * alpha DIV 255); pix[g] := CHR(green * alpha DIV 255); pix[r] := CHR(red * alpha DIV 255); pix[a] := CHR(alpha)*) END SetRGBA; (** retrieve RGB and alpha values from pixel **) PROCEDURE GetRGBA* (pix: Pixel; VAR red, green, blue, alpha: LONGINT); BEGIN alpha := ORD(pix[a]); IF alpha = 0 THEN (* color has disappeared *) red := 255; green := 255; blue := 255 ELSE red := ORD(pix[r]); green := ORD(pix[g]); blue := ORD(pix[b]); IF alpha # 255 THEN (* un-multiply alpha *) red := 255 * red DIV alpha; IF red > 255 THEN red := 255 END; green := 255 * green DIV alpha; IF green > 255 THEN green := 255 END; blue := 255 * blue DIV alpha; IF blue > 255 THEN blue := 255 END END END END GetRGBA; (**--- Palettes ---**) (** return index of color in palette which approximates the requested color reasonably well **) PROCEDURE PaletteIndex* (pal: Palette; red, green, blue: LONGINT): LONGINT; BEGIN IF pal.used>256 THEN RETURN CLUTs.Match(pal.clut, ASH(red, 16) + ASH(green, 8) + blue) *pal.used DIV 256 (*PH090122*) ELSE RETURN CLUTs.Match(pal.clut, ASH(red, 16) + ASH(green, 8) + blue) END; END PaletteIndex; (** compute internal palette structures whenever palette colors have been modified **) PROCEDURE InitPalette* (pal: Palette; used, bits: LONGINT); VAR n, red, green, blue, alpha: LONGINT; BEGIN n := 0; IF used>pal.used THEN NEW(pal.col,used);END; pal.used:=used; WHILE n < used DO GetRGBA(pal.col[n], red, green, blue, alpha); CLUTs.Set(pal.clut, (*n*) n*255 DIV used, ASH(red, 16) + ASH(green, 8) + blue); INC(n) END; CLUTs.Init(pal.clut, MIN (used,256), bits); END InitPalette; (** (re)compute grayscale palette, typically used for pictures with >256 gray scale values**) PROCEDURE InitGrayPalette* (pal: Palette; used, bits: LONGINT); VAR n, gray: LONGINT; BEGIN n := 0; IF used>pal.used THEN NEW(pal.col,used); END; pal.used := used; WHILE n < used DO gray:= n*255 DIV used; SetRGBA(pal.col[n],gray,gray,gray,255); (*PH 090122*) CLUTs.Set(pal.clut, gray, ASH(gray, 16) + ASH(gray, 8) + gray); INC(n) END; CLUTs.Init(pal.clut, MIN(used,256), bits); END InitGrayPalette; (** copy palette contents **) PROCEDURE CopyPalette* (from, to: Palette); VAR n: LONGINT; BEGIN n := 0; IF to.used maxcols DO reduce() END; INC(x); bb := bb + img.fmt.bpp; INC(aa, bb DIV 8); bb := bb MOD 8 END ELSE x := 0; aa := adr; bb := img.fmt.bpp DIV 8; WHILE x < img.width DO img.fmt.unpack(img.fmt, aa, 0, pix); insert(root, 0, pix); WHILE colors > maxcols DO reduce() END; INC(x); INC(aa, bb) END END; INC(y); INC(adr, img.bpr) END; used := reservedcols; traverse(root); InitPalette(pal, used, bits) END ComputePalette; (**--- Formats ---**) (* A1 - one bit alpha, MSB leftmost *) PROCEDURE PackA1 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR b: CHAR; BEGIN SYSTEM.GET(adr, b); IF pix[a] >= 80X THEN SYSTEM.PUT(adr, Set[ORD(b), bit]) ELSE SYSTEM.PUT(adr, Clr[ORD(b), bit]) END END PackA1; PROCEDURE UnpackA1 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR b: CHAR; BEGIN SYSTEM.GET(adr, b); IF Bit[ORD(b), bit] THEN pix[a] := 0FFX ELSE pix := Zero END END UnpackA1; (* A8 - 8 bit alpha *) PROCEDURE PackA8 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN SYSTEM.PUT(adr, pix[a]) END PackA8; PROCEDURE UnpackA8 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR alpha: LONGINT; BEGIN SYSTEM.GET(adr, pix[a]); IF pix[a] = 0X THEN pix := Zero ELSIF pix[a] # 0FFX THEN alpha := ORD(pix[a]); pix[r] := CHR(ORD(pix[r]) * alpha DIV 255); pix[g] := CHR(ORD(pix[g]) * alpha DIV 255); pix[b] := CHR(ORD(pix[b]) * alpha DIV 255) END END UnpackA8; (* P8 - 8 bit indexed format with custom palette *) PROCEDURE PackP8 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN IF pix[a] # 0X THEN (* model alpha as brightness *) SYSTEM.PUT(adr, CHR(CLUTs.Match(fmt.pal.clut, ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))) END END PackP8; PROCEDURE UnpackP8 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR idx: CHAR; BEGIN SYSTEM.GET(adr, idx); pix := fmt.pal.col[ORD(idx)] END UnpackP8; (* D8 - 8 bit indexed format with display palette *) PROCEDURE PackD8 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN IF pix[a] # 0X THEN (* model alpha as brightness *) SYSTEM.PUT(adr, CHR(ColorToIndex(ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))) END END PackD8; PROCEDURE UnpackD8 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR idx: CHAR; col: LONGINT; BEGIN SYSTEM.GET(adr, idx); col := IndexToColor(ORD(idx)); pix[b] := CHR(col MOD 100H); pix[g] := CHR(ASH(col, -8) MOD 100H); pix[r] := CHR(ASH(col, -16) MOD 100H) END UnpackD8; (* P16 - 16 bit indexed format with custom palette *) PROCEDURE PackP16 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR val:LONGINT; BEGIN IF pix[a] # 0X THEN (* model alpha as brightness *) (*SYSTEM.PUT16(adr, PaletteIndex(fmt.pal, ORD(pix[r]), ORD(pix[g]), ORD(pix[b])))*) val:=CLUTs.Match(fmt.pal.clut, ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]),16)); IF fmt.pal.used>256 THEN val:=val*fmt.pal.used DIV 256 END; SYSTEM.PUT16(adr, SHORT(val)) END END PackP16; PROCEDURE UnpackP16 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN pix := fmt.pal.col[SYSTEM.GET16(adr) MOD 1000H] (*unsigned 16 bit entity*) END UnpackP16; (* BGR555 - 16 hi-color with 5 bit blue, 5 bit green and 5 bit red in ascending order *) PROCEDURE PackBGR555 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR int: LONGINT; BEGIN IF pix[a] # 0X THEN (* model alpha as brightness *) int := ASH(ORD(pix[b]), -3) + ASH(ASH(ORD(pix[g]), -3), 5) + ASH(ASH(ORD(pix[r]), -3), 10); SYSTEM.PUT(adr, CHR(int)); SYSTEM.PUT(adr+1, CHR(ASH(int, -8))) END END PackBGR555; PROCEDURE UnpackBGR555 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR lo, hi: CHAR; int: LONGINT; BEGIN SYSTEM.GET(adr, lo); SYSTEM.GET(adr+1, hi); int := ASH(ORD(hi), 8) + ORD(lo); pix[b] := CHR(ASH(int MOD 20H, 3) + 4); pix[g] := CHR(ASH(ASH(int, -5) MOD 20H, 3) + 4); pix[r] := CHR(ASH(ASH(int, -10) MOD 20H, 3) + 4); pix[a] := 0FFX END UnpackBGR555; (* BGR565 - 16 hi-color with 5 bit blue, 6 bit green and 5 bit red in ascending order *) PROCEDURE PackBGR565 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR int: LONGINT; BEGIN IF pix[a] # 0X THEN (* model alpha as brightness *) int := ASH(ORD(pix[b]), -3) + ASH(ASH(ORD(pix[g]), -2), 5) + ASH(ASH(ORD(pix[r]), -3), 11); SYSTEM.PUT(adr, CHR(int)); SYSTEM.PUT(adr+1, CHR(ASH(int, -8))) END END PackBGR565; PROCEDURE UnpackBGR565 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR lo, hi: CHAR; int: LONGINT; BEGIN SYSTEM.GET(adr, lo); SYSTEM.GET(adr+1, hi); int := ASH(ORD(hi), 8) + ORD(lo); pix[b] := CHR(ASH(int MOD 20H, 3) + 4); pix[g] := CHR(ASH(ASH(int, -5) MOD 40H, 2) + 2); pix[r] := CHR(ASH(ASH(int, -11) MOD 20H, 3) + 4); pix[a] := 0FFX END UnpackBGR565; (* BGR466 - 16 hi-color with 4 bit blue, 6 bit green and 6 bit red in ascending order *) PROCEDURE PackBGR466 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR int: LONGINT; BEGIN IF pix[a] # 0X THEN (* model alpha as brightness *) int := ASH(ORD(pix[b]), -4) + ASH(ASH(ORD(pix[g]), -2), 4) + ASH(ASH(ORD(pix[r]), -2), 10); SYSTEM.PUT(adr, CHR(int)); SYSTEM.PUT(adr+1, CHR(ASH(int, -8))) END END PackBGR466; PROCEDURE UnpackBGR466 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); VAR lo, hi: CHAR; int: LONGINT; BEGIN SYSTEM.GET(adr, lo); SYSTEM.GET(adr+1, hi); int := ASH(ORD(hi), 8) + ORD(lo); pix[b] := CHR(ASH(int MOD 10H, 4) + 8); pix[g] := CHR(ASH(ASH(int, -4) MOD 40H, 2) + 2); pix[r] := CHR(ASH(ASH(int, -10) MOD 40H, 2) + 2); pix[a] := 0FFX END UnpackBGR466; (* BGR888 - 24 bit true color with blue in lower, green in middle, and red in upper byte *) PROCEDURE PackBGR888 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN IF pix[a] # 0X THEN (* model alpha as brightness *) SYSTEM.MOVE(ADDRESSOF(pix[0]), adr, 3) END END PackBGR888; PROCEDURE UnpackBGR888 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN SYSTEM.MOVE(adr, ADDRESSOF(pix[0]), 3); pix[a] := 0FFX END UnpackBGR888; (* BGRA8888 - 32 bit true color with blue in lowest, green in lower middle, red in upper middle, and alpha in top byte *) PROCEDURE PackBGRA8888 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN SYSTEM.MOVE(ADDRESSOF(pix[0]), adr, 4) END PackBGRA8888; PROCEDURE UnpackBGRA8888 (VAR fmt: Format0; adr: ADDRESS; bit: LONGINT; VAR pix: Pixel); BEGIN SYSTEM.MOVE(adr, ADDRESSOF(pix[0]), 4) END UnpackBGRA8888; (** return image format for given Displays transfer format **) PROCEDURE DisplayFormat* (format: LONGINT): Format; BEGIN CASE format OF | Displays.index8: RETURN D8 | Displays.color565: RETURN BGR565 | Displays.color888: RETURN BGR888 | Displays.color8888: RETURN BGRA8888 END END DisplayFormat; (** initialize format **) PROCEDURE InitFormat* (VAR fmt: Format; code, bpp, align: SHORTINT; comps: SET; pal: Palette; pack, unpack: PackProc); BEGIN fmt.code := code; fmt.bpp := bpp; fmt.align := align; fmt.components := comps; fmt.pal := pal; fmt.pack := pack; fmt.unpack := unpack END InitFormat; (** initialize index formats with custom palette **) PROCEDURE InitPaletteFormat* (VAR fmt: Format; pal: Palette); BEGIN fmt.components := {index}; fmt.pal := pal; IF pal.used<=256 THEN fmt.align := 1; fmt.code := p8; fmt.bpp := 8; fmt.pack := PackP8; fmt.unpack := UnpackP8 ELSIF pal.used <= 10000H THEN fmt.align := 2; fmt.code := p16; fmt.bpp := 16; fmt.pack := PackP16; fmt.unpack := UnpackP16 ELSE HALT(199) END END InitPaletteFormat; (** return if two formats are the same **) PROCEDURE Same* (VAR fmt0, fmt1: Format): BOOLEAN; BEGIN RETURN (fmt0.pack = fmt1.pack) & (fmt0.unpack = fmt1.unpack) & (~(index IN fmt0.components) OR (fmt0.pal = fmt1.pal)) (* doesn't work if palette has been re-initialized *) END Same; (**--- Images ---**) (** initialize custom image **) PROCEDURE Init* (img: Image; width, height: LONGINT; VAR fmt: Format; bpr: LONGINT; adr: ADDRESS); BEGIN ASSERT((width > 0) & (height > 0), 100); img.width := width; img.height := height; img.fmt := fmt; img.bpr := bpr; img.adr := adr END Init; (** initialize custom image on byte buffer **) PROCEDURE InitBuf* (img: Image; width, height: LONGINT; VAR fmt: Format; bpr, offset: LONGINT; VAR buf: ARRAY OF CHAR); BEGIN ASSERT((0 <= offset) & (offset + height * ABS(bpr) <= LEN(buf)), 100); IF bpr >= 0 THEN Init(img, width, height, fmt, bpr, ADDRESSOF(buf[0])) ELSE Init(img, width, height, fmt, bpr, ADDRESSOF(buf[offset]) + LEN(buf) - bpr) END END InitBuf; (** initialize image on rectangular area within existing image (lower left corner must fall on byte boundary) **) PROCEDURE InitRect* (img, base: Image; x, y, w, h: LONGINT); BEGIN ASSERT((0 <= x) & (x + w <= base.width) & (0 <= y) & (y + h <= base.height), 100); ASSERT(x * base.fmt.bpp MOD 8 = 0, 101); Init(img, w, h, base.fmt, base.bpr, base.adr + y * base.bpr + x * base.fmt.bpp DIV 8) END InitRect; (** create image in requested format (allocating or reusing necessary memory) **) PROCEDURE Create* (img: Image; width, height: LONGINT; fmt: Format); VAR size: LONGINT; a0, a1: ADDRESS; BEGIN ASSERT((width > 0) & (height > 0), 100); img.width := width; img.height := height; img.fmt := fmt; img.bpr := (width * fmt.bpp + 7) DIV 8; IF fmt.align > 1 THEN img.bpr := (img.bpr + fmt.align - 1) DIV fmt.align * fmt.align END; size := height * img.bpr; INC(size, (-size) MOD 4); IF (img.mem = NIL) OR (size < LEN(img.mem^) DIV 2) OR (LEN(img.mem^) < size) THEN NEW(img.mem, size) ELSE a0 := ADDRESSOF(img.mem[0]); a1 := a0 + size; WHILE a0 # a1 DO SYSTEM.PUT32(a0,0); INC(a0, SIZEOF(LONGINT)) END END; img.adr := ADDRESSOF(img.mem[0]) END Create; PROCEDURE CreateWithBuffer*(img: Image; width, height: LONGINT; fmt: Format; mem: POINTER TO ARRAY OF CHAR; VAR adr: ADDRESS); VAR size: LONGINT; a0, a1: ADDRESS; BEGIN ASSERT((width > 0) & (height > 0), 100); img.width := width; img.height := height; img.fmt := fmt; img.bpr := (width * fmt.bpp + 7) DIV 8; IF fmt.align > 1 THEN img.bpr := (img.bpr + fmt.align - 1) DIV fmt.align * fmt.align END; size := height * img.bpr; INC(size, (-size) MOD 4); a0 := adr; a1 := adr + size; ASSERT(ADDRESSOF(mem[0]) <= a0); ASSERT(a1 <= ADDRESSOF(mem[LEN(mem)-1])); WHILE a0 # a1 DO SYSTEM.PUT32(a0,0); INC(a0, SIZEOF(LONGINT)) END; img.adr := adr; img.mem := mem; adr := a1; END CreateWithBuffer; (**--- Transfer Modes ---**) (** initialize transfer mode **) PROCEDURE InitMode* (VAR mode: Mode; op: SHORTINT); BEGIN mode.op := op; IF (mode.src.pal # NIL) & ((mode.map = NIL) OR (LEN(mode.map^) # mode.src.pal.used)) THEN NEW(mode.map, mode.src.pal.used) END; SetRGB(mode.col, 255, 255, 255); (* mode.col := SYSTEM.VAL(Pixel, -1); *) mode.src.pack := NIL; mode.dst.pack := NIL (* force re-evaluation of transfer procedure *) END InitMode; (** initialize transfer mode with color components for pure alpha sources **) PROCEDURE InitModeColor* (VAR mode: Mode; op: SHORTINT; red, green, blue: LONGINT); BEGIN mode.op := op; IF (mode.src.pal # NIL) & ((mode.map = NIL) OR (LEN(mode.map^) # mode.src.pal.used)) THEN NEW(mode.map, mode.src.pal.used) END; SetRGB(mode.col, red, green, blue); mode.src.pack := NIL; mode.dst.pack := NIL END InitModeColor; (** set new source color for transfer mode **) PROCEDURE SetModeColor* (VAR mode: Mode; red, green, blue: LONGINT); BEGIN SetRGB(mode.col, red, green, blue); IF (mode.src.pal # NIL) & ((mode.map = NIL) OR (LEN(mode.map^) # mode.src.pal.used)) THEN NEW(mode.map, mode.src.pal.used) END; mode.src.pack := NIL; mode.dst.pack := NIL END SetModeColor; (** blend source pixel into destination pixel according to compositing operation **) PROCEDURE Blend* (op: LONGINT; VAR src, dst: Pixel); VAR fs, fd, i: LONGINT; BEGIN CASE op OF | clear: fs := 0; fd := 0 | srcCopy: fs := 255; fd := 0 | dstCopy: fs := 0; fd := 255 | srcOverDst: fs := 255; fd := 255-ORD(src[a]) | dstOverSrc: fs := 255-ORD(dst[a]); fd := 255 | srcInDst: fs := ORD(dst[a]); fd := 0 | dstInSrc: fs := 0; fd := ORD(src[a]) | srcWithoutDst: fs := 255-ORD(dst[a]); fd := 0 | dstWithoutSrc: fs := 0; fd := 255-ORD(src[a]) | srcAtopDst: fs := ORD(dst[a]); fd := 255-ORD(src[a]) | dstAtopSrc: fs := 255-ORD(dst[a]); fd := ORD(src[a]) | srcXorDst: fs := 255-ORD(dst[a]); fd := 255-ORD(src[a]) END; IF fs + fd = 0 THEN FOR i := 0 TO 3 DO dst[i] := 0X END ELSIF fs = 0 THEN IF fd # 255 THEN FOR i := 0 TO 3 DO dst[i] := Clamp[200H + fd * ORD(dst[i]) DIV 255] END END ELSIF fd = 0 THEN IF fs = 255 THEN dst := src ELSE FOR i := 0 TO 3 DO dst[i] := Clamp[200H + fs * ORD(src[i]) DIV 255] END END ELSE dst[0] := Clamp[200H + (fs * ORD(src[0]) + fd * ORD(dst[0])) DIV 255]; dst[1] := Clamp[200H + (fs * ORD(src[1]) + fd * ORD(dst[1])) DIV 255]; dst[2] := Clamp[200H + (fs * ORD(src[2]) + fd * ORD(dst[2])) DIV 255]; dst[3] := Clamp[200H + (fs * ORD(src[3]) + fd * ORD(dst[3])) DIV 255] END END Blend; (*--- General Transfer ---*) PROCEDURE AnyBlendAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR spix, dpix: Pixel; BEGIN WHILE len > 0 DO spix := mode.col; dpix := mode.col; mode.src.unpack(mode.src, sadr, sbit, spix); mode.dst.unpack(mode.dst, dadr, dbit, dpix); Blend(mode.op, spix, dpix); mode.dst.pack(mode.dst, dadr, dbit, dpix); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END AnyBlendAny; (* --- invert --- *) PROCEDURE InvAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN WHILE len > 0 DO mode.dst.unpack(mode.dst, dadr, dbit, mode.buf); mode.buf[r]:=CHR(255-ORD(mode.buf[r])); mode.buf[g]:=CHR(255-ORD(mode.buf[g])); mode.buf[b]:=CHR(255-ORD(mode.buf[b])); mode.dst.pack(mode.dst, dadr, dbit, mode.buf); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END InvAny; (* --- alpha invert --- *) PROCEDURE InvOverAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix:Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, sbit, pix); IF pix[a]>=80X THEN mode.dst.unpack(mode.dst, dadr, dbit, mode.buf); mode.buf[r]:=CHR(255-ORD(mode.buf[r])); mode.buf[g]:=CHR(255-ORD(mode.buf[g])); mode.buf[b]:=CHR(255-ORD(mode.buf[b])); mode.dst.pack(mode.dst, dadr, dbit, mode.buf) END; sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END InvOverAny; (*--- clear ---*) PROCEDURE ClearAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR inc: LONGINT; BEGIN IF mode.dst.bpp MOD 8 = 0 THEN inc := mode.dst.bpp DIV 8; WHILE len > 0 DO mode.dst.pack(mode.dst, dadr, 0, Zero); INC(dadr, inc); DEC(len) END ELSE WHILE len > 0 DO mode.dst.pack(mode.dst, dadr, dbit, Zero); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END END ClearAny; PROCEDURE Clear1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR out: CHAR; BEGIN IF (dbit > 0) OR (len < 8) THEN SYSTEM.GET(dadr, out); WHILE (dbit < 8) & (len > 0) DO out := Clr[ORD(out), dbit]; INC(dbit); DEC(len) END; SYSTEM.PUT(dadr, out) END; WHILE len >= 32 DO SYSTEM.PUT(dadr, LONG(LONG(0))); INC(dadr, 4); DEC(len, 32) END; WHILE len >= 8 DO SYSTEM.PUT(dadr, 0X); INC(dadr); DEC(len, 8) END; IF len > 0 THEN SYSTEM.GET(dadr, out); dbit := 0; REPEAT out := Clr[ORD(out), dbit]; INC(dbit); DEC(len) UNTIL len = 0; SYSTEM.PUT(dadr, out) END END Clear1; (* PROCEDURE ClearBytes (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN len := len * mode.dst.bpp DIV 8; WHILE len >= 4 DO SYSTEM.PUT(dadr, LONG(LONG(0))); INC(dadr, 4); DEC(len) END; WHILE len > 0 DO SYSTEM.PUT(dadr, 0X); INC(dadr); DEC(len) END END ClearBytes; *) PROCEDURE ClearBytes(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE LDR R0, [FP, #dadr] LDR R1, [FP, #len] MOV R2, #0 loop: CMP R1, #0 BLE end ; exit if len <= 0 STRB R2, [R0, #0] ADD R0, R0, #1 ; INC(dadr); SUB R1, R1, #1 ; DEC(len); B loop end: END ClearBytes; (* len is nr of DWords*) PROCEDURE Clear32(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE LDR R0, [FP, #dadr] LDR R1, [FP, #len] MOV R2, #0 loop: CMP R1, #0 BLE end ; exit if len <= 0 STR R2, [R0, #0] ADD R0, R0, #4 ; INC(dadr,4); SUB R1, R1, #1 ; DEC(len); B loop end: END Clear32; (*---- fill --------------*) PROCEDURE Fill8(destAdr: ADDRESS; size: SIZE; filler: LONGINT); CODE LDR R0, [FP, #destAdr] LDR R1, [FP, #size] LDR R2, [FP, #filler] loop: CMP R1, #0 BEQ end ; exit if size = 0 STRB R2, [R0, #0] ADD R0, R0, #1 ; INC(destAdr); SUB R1, R1, #1 ; DEC(size); B loop end: END Fill8; (* size in 16bit words*) PROCEDURE Fill16(destAdr: ADDRESS; size: SIZE; filler: LONGINT); CODE LDR R0, [FP, #destAdr] LDR R1, [FP, #size] LDR R2, [FP, #filler] loop: CMP R1, #0 BEQ end ; exit if size = 0 STRH R2, [R0, #0] ADD R0, R0, #2 ; INC(destAdr,2); SUB R1, R1, #1 ; DEC(size); B loop end: END Fill16; (* size in 24bit entities*) PROCEDURE Fill24(destAdr: ADDRESS; size: SIZE; filler: LONGINT); CODE LDR R0, [FP, #destAdr] LDR R1, [FP, #size] LDR R2, [FP, #filler] LSR R4, R2, #8 LSR R5, R2, #16 loop: CMP R1, #0 BEQ end ; exit if size = 0 STRB R2, [R0, #0] STRB R4, [R0, #1] STRB R5, [R0, #2] ADD R0, R0, #3 ; INC(destAdr,3); SUB R1, R1, #1 ; DEC(size); B loop end: END Fill24; (* size in DWords*) PROCEDURE Fill32(destAdr: ADDRESS; size: SIZE; filler: LONGINT); (*! to do: change interface, introduce in Blend()*) CODE LDR R0, [FP, #destAdr] LDR R1, [FP, #size] LDR R2, [FP, #filler] loop: CMP R1, #0 BEQ end ; exit if size = 0 STR R2, [R0, #0] ADD R0, R0, #4 ; INC(destAdr,4); SUB R1, R1, #1 ; DEC(size); B loop end: END Fill32; (* len in DWords*) PROCEDURE Fill32A(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); (*! to do: change interface, introduce in Blend()*) CODE LDR R0, [FP, #dadr] LDR R1, [FP, #len] LDR R2, [FP, #sadr] LDR R2, [R2, #0] loop: CMP R1, #0 BEQ end ; exit if size = 0 STR R2, [R0, #0] ADD R0, R0, #4 ; INC(destAdr,4); SUB R1, R1, #1 ; DEC(size); B loop end: END Fill32A; (*--- srcCopy Transfer ---*) (* constant values *) PROCEDURE Set1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR out: CHAR; BEGIN IF (dbit > 0) OR (len < 8) THEN SYSTEM.GET(dadr, out); WHILE (dbit < 8) & (len > 0) DO out := Set[ORD(out), dbit]; INC(dbit); DEC(len) END; SYSTEM.PUT(dadr, out) END; WHILE len >= 8 DO SYSTEM.PUT(dadr, 0FFX); INC(dadr); DEC(len, 8) END; IF len > 0 THEN SYSTEM.GET(dadr, out); dbit := 0; REPEAT out := Set[ORD(out), dbit]; INC(dbit); DEC(len) UNTIL len = 0; SYSTEM.PUT(dadr, out) END END Set1; PROCEDURE ConstCopy8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN Fill8(dadr, len, ORD(mode.buf[0])) (*WHILE len > 0 DO SYSTEM.PUT(dadr, mode.buf[0]); INC(dadr); DEC(len) END*) END ConstCopy8; PROCEDURE ConstCopy16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN Fill16(dadr, len, ORD(mode.buf[0])+ASH(ORD(mode.buf[1]),8)) (*WHILE len > 0 DO SYSTEM.MOVE(ADDRESSOF(mode.buf[0]), dadr, 2); INC(dadr, 2); DEC(len) END*) END ConstCopy16; PROCEDURE ConstCopy24 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN Fill24(dadr, len, ORD(mode.buf[0])+ASH(ORD(mode.buf[1]),8)+ASH(ORD(mode.buf[2]),16)); (*WHILE len > 0 DO SYSTEM.MOVE(ADDRESSOF(mode.buf[0]), dadr, 3); INC(dadr, 3); DEC(len) END*) END ConstCopy24; (* identical formats *) PROCEDURE Copy1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in, out: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE (sbit = 0) & (dbit = 0) & (len >= 8) DO SYSTEM.PUT(dadr, in); INC(sadr); INC(dadr); DEC(len, 8); SYSTEM.GET(sadr, in) END; IF (dbit > 0) OR (len < 8) THEN SYSTEM.GET(dadr, out) END; WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN out := Set[ORD(out), dbit] ELSE out := Clr[ORD(out), dbit] END; INC(sbit); INC(dbit); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END; IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); dbit := 0; IF len < 8 THEN SYSTEM.GET(dadr, out) END END END; IF dbit > 0 THEN SYSTEM.PUT(dadr, out) END END Copy1; PROCEDURE Copy8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN SYSTEM.MOVE(sadr, dadr, len) END Copy8; PROCEDURE I8CopyI8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR byte: CHAR; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr, byte); SYSTEM.PUT(dadr, mode.map[ORD(byte)]); INC(sadr); INC(dadr); DEC(len) END END I8CopyI8; PROCEDURE Copy16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN SYSTEM.MOVE(sadr, dadr, 2*len) END Copy16; PROCEDURE I16CopyI16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR val: INTEGER; BEGIN WHILE len > 0 DO val:=SYSTEM.GET16(sadr); SYSTEM.PUT16(dadr, mode.map[val MOD 10000H]); INC(sadr); INC(dadr); DEC(len) END END I16CopyI16; PROCEDURE Copy24 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN SYSTEM.MOVE(sadr, dadr, 3*len) END Copy24; PROCEDURE Copy32(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE LDR R0, [FP, #dadr] LDR R1, [FP, #len] LDR R2, [FP, #sadr] loop: CMP R1, #0 BLE end ; exit if len <= 0 LDR R4, [R2, #0] ; R4 := src STR R4, [R0, #0] ; dst := src ADD R0, R0, #4 ; INC(dadr,4); ADD R2, R2, #4 ; INC(sadr,4); SUB R1, R1, #1 ; DEC(len); B loop end: (*BEGIN SYSTEM.MOVE(sadr, dadr, 4*len)*) END Copy32; (* general methods *) PROCEDURE AnyCopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, sbit, mode.buf); mode.dst.pack(mode.dst, dadr, dbit, mode.buf); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END AnyCopyAny; PROCEDURE AnyBytesCopyAnyBytes (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR sinc, dinc: LONGINT; pix: Pixel; BEGIN sinc := mode.src.bpp DIV 8; dinc := mode.dst.bpp DIV 8; WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, sbit, mode.buf); mode.dst.pack(mode.dst, dadr, dbit, mode.buf); INC(sadr, sinc); INC(dadr, dinc); DEC(len) END END AnyBytesCopyAnyBytes; (* A1 *) PROCEDURE AnyCopyA1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR out: CHAR; pix: Pixel; BEGIN SYSTEM.GET(dadr, out); pix[a] := 0FFX; WHILE len > 0 DO mode.src.unpack(mode.src, sadr, sbit, pix); sbit := sbit + mode.src.bpp; INC(sadr, sbit MOD 8); sbit := sbit MOD 8; IF pix[a] >= 80X THEN out := Set[ORD(out), dbit] ELSE out := Clr[ORD(out), dbit] END; INC(dbit); DEC(len); IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); SYSTEM.GET(dadr, out); dbit := 0 END END; SYSTEM.PUT(dadr, out) END AnyCopyA1; PROCEDURE A8CopyA1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR out, in: CHAR; BEGIN IF (dbit > 0) OR (len < 8) THEN SYSTEM.GET(dadr, out) END; WHILE len > 0 DO SYSTEM.GET(sadr, in); IF in >= 80X THEN out := Set[ORD(out), dbit] ELSE out := Clr[ORD(out), dbit] END; INC(sadr); INC(dbit); DEC(len); IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); dbit := 0; IF len < 8 THEN SYSTEM.GET(dadr, out) END END END; IF dbit > 0 THEN SYSTEM.PUT(dadr, out) END END A8CopyA1; PROCEDURE BGRA8888CopyA1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR out, in: CHAR; BEGIN INC(sadr, a); (* only look at alpha component *) IF (dbit > 0) OR (len < 8) THEN SYSTEM.GET(dadr, out) END; WHILE len > 0 DO SYSTEM.GET(sadr, in); IF in >= 80X THEN out := Set[ORD(out), dbit] ELSE out := Clr[ORD(out), dbit] END; INC(sadr, 4); INC(dbit); DEC(len); IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); dbit := 0; IF len < 8 THEN SYSTEM.GET(dadr, out) END END END; IF dbit > 0 THEN SYSTEM.PUT(dadr, out) END END BGRA8888CopyA1; PROCEDURE A1CopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN mode.dst.pack(mode.dst, dadr, dbit, mode.buf) ELSE mode.dst.pack(mode.dst, dadr, dbit, Zero) END; INC(sbit); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1CopyAny; PROCEDURE A1CopyA8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN SYSTEM.PUT(dadr, 0FFX) ELSE SYSTEM.PUT(dadr, 0X) END; INC(sbit); INC(dadr); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1CopyA8; PROCEDURE A1CopyBGRA8888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; in: CHAR; BEGIN pix := mode.buf; SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN pix[a] := 0FFX ELSE pix[a] := 0X END; SYSTEM.MOVE(ADDRESSOF(pix), dadr, 4); INC(sbit); INC(dadr, 4); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1CopyBGRA8888; (* A8 *) PROCEDURE AnyCopyA8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN pix[a] := 0FFX; WHILE len > 0 DO mode.src.unpack(mode.src, sadr, sbit, pix); SYSTEM.PUT(dadr, pix[a]); INC(dadr); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END AnyCopyA8; PROCEDURE BGRA8888CopyA8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR byte: CHAR; BEGIN INC(sadr, 3); WHILE len > 0 DO SYSTEM.GET(sadr, byte); SYSTEM.PUT(dadr, byte); INC(sadr, 4); INC(dadr); DEC(len) END END BGRA8888CopyA8; PROCEDURE A8CopyBGRA8888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN pix := mode.buf; WHILE len > 0 DO SYSTEM.GET(sadr, pix[a]); SYSTEM.MOVE(ADDRESSOF(pix), dadr, 4); INC(sadr); INC(dadr, 4); DEC(len) END END A8CopyBGRA8888; (* P8 *) PROCEDURE AnyCopyP8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, sbit, pix); SYSTEM.PUT(dadr, CHR(CLUTs.Match(mode.dst.pal.clut, ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(dadr); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END AnyCopyP8; PROCEDURE Any16CopyP8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, 0, pix); SYSTEM.PUT(dadr, CHR(CLUTs.Match(mode.dst.pal.clut, ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(sadr, 2); INC(dadr); DEC(len) END END Any16CopyP8; PROCEDURE BGR888CopyP8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 3); SYSTEM.PUT(dadr, CHR(CLUTs.Match(mode.dst.pal.clut, ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(sadr, 3); INC(dadr); DEC(len) END END BGR888CopyP8; PROCEDURE BGRA8888CopyP8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 4); SYSTEM.PUT(dadr, CHR(CLUTs.Match(mode.dst.pal.clut, ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(sadr, 4); INC(dadr); DEC(len) END END BGRA8888CopyP8; PROCEDURE P8CopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR b: CHAR; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr, b); mode.dst.pack(mode.dst, dadr, dbit, mode.src.pal.col[ORD(b)]); INC(sadr); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END P8CopyAny; PROCEDURE P8CopyAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR b: CHAR; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr, b); mode.dst.pack(mode.dst, dadr, 0, mode.src.pal.col[ORD(b)]); INC(sadr); INC(dadr, 2); DEC(len) END END P8CopyAny16; PROCEDURE P8CopyBGR888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR b: CHAR; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr, b); SYSTEM.MOVE(ADDRESSOF(mode.src.pal.col[ORD(b)]), dadr, 3); INC(sadr); INC(dadr, 3); DEC(len) END END P8CopyBGR888; PROCEDURE P8CopyBGRA8888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR b: CHAR; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr, b); SYSTEM.MOVE(ADDRESSOF(mode.src.pal.col[ORD(b)]), dadr, 4); INC(sadr); INC(dadr, 4); DEC(len) END END P8CopyBGRA8888; (* D8 *) PROCEDURE AnyCopyD8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, sbit, pix); SYSTEM.PUT(dadr, CHR(ColorToIndex(ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(dadr); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END AnyCopyD8; PROCEDURE Any16CopyD8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, 0, pix); SYSTEM.PUT(dadr, CHR(ColorToIndex(ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(sadr, 2); INC(dadr); DEC(len) END END Any16CopyD8; PROCEDURE BGR888CopyD8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 3); SYSTEM.PUT(dadr, CHR(ColorToIndex(ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(sadr, 3); INC(dadr); DEC(len) END END BGR888CopyD8; PROCEDURE BGRA8888CopyD8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 4); SYSTEM.PUT(dadr, CHR(ColorToIndex(ORD(pix[b]) + ASH(ORD(pix[g]), 8) + ASH(ORD(pix[r]), 16)))); INC(sadr, 4); INC(dadr); DEC(len) END END BGRA8888CopyD8; PROCEDURE D8CopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; byte: CHAR; col: LONGINT; BEGIN pix[a] := 0FFX; WHILE len > 0 DO SYSTEM.GET(sadr, byte); col := IndexToColor(ORD(byte)); pix[b] := CHR(col MOD 100H); pix[g] := CHR(ASH(col, -8) MOD 100H); pix[r] := CHR(ASH(col, -16) MOD 100H); mode.dst.pack(mode.dst, dadr, dbit, pix); INC(sadr); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END D8CopyAny; PROCEDURE D8CopyAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; byte: CHAR; col: LONGINT; BEGIN pix[a] := 0FFX; WHILE len > 0 DO SYSTEM.GET(sadr, byte); col := IndexToColor(ORD(byte)); pix[b] := CHR(col MOD 100H); pix[g] := CHR(ASH(col, -8) MOD 100H); pix[r] := CHR(ASH(col, -16) MOD 100H); mode.dst.pack(mode.dst, dadr, 0, pix); INC(sadr); INC(dadr, 2); DEC(len) END END D8CopyAny16; PROCEDURE D8CopyBGR888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR byte: CHAR; col: LONGINT; pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr, byte); col := IndexToColor(ORD(byte)); pix[b] := CHR(col MOD 100H); pix[g] := CHR(ASH(col, -8) MOD 100H); pix[r] := CHR(ASH(col, -16) MOD 100H); SYSTEM.MOVE(ADDRESSOF(pix[0]), dadr, 3); INC(sadr); INC(dadr, 3); DEC(len) END END D8CopyBGR888; PROCEDURE D8CopyBGRA8888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; byte: CHAR; col: LONGINT; BEGIN pix[a] := 0FFX; WHILE len > 0 DO SYSTEM.GET(sadr, byte); col := IndexToColor(ORD(byte)); pix[b] := CHR(col MOD 100H); pix[g] := CHR(ASH(col, -8) MOD 100H); pix[r] := CHR(ASH(col, -16) MOD 100H); SYSTEM.MOVE(ADDRESSOF(pix[0]), dadr, 4); INC(sadr); INC(dadr, 4); DEC(len) END END D8CopyBGRA8888; (* (* P816*) PROCEDURE AnyCopyP16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, sbit, pix); SYSTEM.PUT16(dadr, PaletteIndex(mode.dst.pal, ORD(pix[r]), ORD(pix[g]), ORD(pix[b]))); INC(dadr,2); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END AnyCopyP16; PROCEDURE Any16CopyP16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, 0, pix); SYSTEM.PUT16(dadr, PaletteIndex(mode.dst.pal, ORD(pix[r]), ORD(pix[g]), ORD(pix[b]))); INC(sadr, 2); INC(dadr,2); DEC(len) END END Any16CopyP16; PROCEDURE BGR888CopyP16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 3); SYSTEM.PUT16(dadr, PaletteIndex(mode.dst.pal, ORD(pix[r]), ORD(pix[g]), ORD(pix[b]))); INC(sadr, 3); INC(dadr,2); DEC(len) END END BGR888CopyP16; PROCEDURE BGRA8888CopyP16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 4); SYSTEM.PUT16(dadr, PaletteIndex(mode.dst.pal, ORD(pix[r]), ORD(pix[g]), ORD(pix[b]))); INC(sadr, 4); INC(dadr,2); DEC(len) END END BGRA8888CopyP16; PROCEDURE P16CopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN WHILE len > 0 DO mode.dst.pack(mode.dst, dadr, dbit, mode.src.pal.col[LONG(SYSTEM.GET16(sadr)) MOD 10000H]); INC(sadr,2); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END P16CopyAny; PROCEDURE P16CopyAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN WHILE len > 0 DO mode.dst.pack(mode.dst, dadr, 0, mode.src.pal.col[LONG(SYSTEM.GET16(sadr)) MOD 10000H]); INC(sadr,2); INC(dadr, 2); DEC(len) END END P16CopyAny16; *) PROCEDURE P16CopyBGR888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN WHILE len > 0 DO SYSTEM.MOVE(ADDRESSOF(mode.src.pal.col[LONG(SYSTEM.GET16(sadr)) MOD 10000H]), dadr, 3); INC(sadr,2); INC(dadr, 3); DEC(len) END END P16CopyBGR888; PROCEDURE P16CopyBGRA8888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR val:LONGINT; BEGIN WHILE len > 0 DO val:=LONG(SYSTEM.GET16(sadr)) MOD 10000H; SYSTEM.MOVE(ADDRESSOF(mode.src.pal.col[val]), dadr, 4); INC(sadr,2); INC(dadr, 4); DEC(len) END END P16CopyBGRA8888; (* BGR555, BGR565, BGR466 *) PROCEDURE AnyCopyAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, 0, pix); mode.dst.pack(mode.dst, dadr, 0, pix); INC(dadr, 2); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END AnyCopyAny16; PROCEDURE Any16CopyAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, 0, pix); mode.dst.pack(mode.dst, dadr, 0, pix); INC(sadr, 2); INC(dadr, 2); DEC(len) END END Any16CopyAny16; PROCEDURE BGR888CopyAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN pix[a] := 0FFX; WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 3); mode.dst.pack(mode.dst, dadr, 0, pix); INC(sadr, 3); INC(dadr, 2); DEC(len) END END BGR888CopyAny16; PROCEDURE BGRA8888CopyAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 4); mode.dst.pack(mode.dst, dadr, 0, pix); INC(dadr, 2); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END BGRA8888CopyAny16; PROCEDURE Any16CopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, 0, pix); mode.dst.pack(mode.dst, dadr, 0, pix); INC(sadr, 2); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END Any16CopyAny; PROCEDURE Any16CopyBGR888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, 0, pix); SYSTEM.MOVE(ADDRESSOF(pix[0]), dadr, 3); INC(sadr, 2); INC(dadr, 3); DEC(len) END END Any16CopyBGR888; PROCEDURE Any16CopyBGRA8888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, 0, pix); SYSTEM.MOVE(ADDRESSOF(pix[0]), dadr, 4); INC(sadr, 2); INC(dadr, 4); DEC(len) END END Any16CopyBGRA8888; (* BGR888 *) PROCEDURE AnyCopyBGR888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, sbit, pix); SYSTEM.MOVE(ADDRESSOF(pix[0]), dadr, 3); INC(dadr, 3); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END AnyCopyBGR888; PROCEDURE BGRA8888CopyBGR888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, dadr, 3); INC(sadr, 4); INC(dadr, 3); DEC(len) END END BGRA8888CopyBGR888; (*PROCEDURE SSE2BGRA8888CopyBGR888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE {SYSTEM.i386, SYSTEM.MMX, SYSTEM.SSE, SYSTEM.SSE2, SYSTEM.Pentium} PUSHFD PUSH EBX ; CLI MOV ESI, [EBP+sadr] ; source adr MOV EDI, [EBP+dadr] ; source adr MOV ECX, [EBP+len] loop: CMP ECX, 0 JLE end CMP ECX, 4 JL singlepixel fourpixel: ; 4pixels at the time MOV EAX, [ESI] ; pixel 0 MOV EBX, [ESI+4] ; pixel 1 AND EAX, 0FFFFFFH AND EBX, 0FFFFFFH MOV EDX, EBX SHL EDX, 24 OR EAX, EDX ; 1000 MOV [EDI], EAX ; write back to mem MOV EAX, [ESI+8] ; pixel 2 AND EAX, 0FFFFFFH SHR EBX,8 MOV EDX, EAX SHL EDX, 16 OR EBX, EDX ; 2211 MOV [EDI+4], EBX MOV EDX, [ESI+12] ; pixel 3 SHL EDX, 8 SHR EAX, 16 OR EAX, EDX ; 3332 MOV [EDI], EAX ADD ESI, 16 ADD EDI, 12 SUB ECX, 4 JG loop JMP end singlepixel: MOV EAX, [ESI] MOV [EDI], AX SHR EAX, 16 MOV [EDI+2], AL ADD ESI, 4 ADD EDI, 3 SUB ECX, 1 JG loop end: EMMS ; declare FPU registers free POP EBX POPFD END SSE2BGRA8888CopyBGR888;*) PROCEDURE BGR888CopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN pix[a] := 0FFX; WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 3); mode.dst.pack(mode.dst, dadr, dbit, pix); INC(sadr, 3); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END BGR888CopyAny; PROCEDURE BGR888CopyBGRA8888(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, dadr, 3); SYSTEM.PUT(dadr+3, 0FFX); INC(sadr, 3); INC(dadr, 4); DEC(len) END END BGR888CopyBGRA8888; (* PROCEDURE SSE2BGR888CopyBGRA8888(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE {SYSTEM.i386, SYSTEM.MMX, SYSTEM.SSE, SYSTEM.SSE2,SYSTEM.Pentium} PUSHFD PUSH EBX ; CLI PXOR XMM0, XMM0 MOV EAX, 0FF00H PINSRW XMM0, EAX, 1 PINSRW XMM0, EAX, 3 PINSRW XMM0, EAX, 5 PINSRW XMM0, EAX, 7 ; prepare for fourpixel SHL EAX, 16 ; prepare for singlepixel MOV ESI, [EBP+sadr] ; source adr MOV EDI, [EBP+dadr] ; source adr MOV ECX, [EBP+len] loop: CMP ECX, 0 JLE end CMP ECX, 4 JL singlepixel fourpixel: ; 4pixels at the time PXOR XMM2,XMM2 PXOR XMM1,XMM1 MOV EBX, [ESI+9] ; read 1st source pixel MOVD XMM2, EBX PSLLDQ XMM2, 4 MOV EBX, [ESI+6] ; read 2nd source pixel MOVD XMM1, EBX POR XMM2, XMM1 PSLLDQ XMM2, 4 MOV EBX, [ESI+3] ; read 3rd source pixel MOVD XMM1, EBX POR XMM2, XMM1 PSLLDQ XMM2, 4 MOV EBX, [ESI] ; read 4th source pixel MOVD XMM1, EBX POR XMM2, XMM1 ADD ESI, 12 POR XMM2, XMM0 MOVDQU [EDI], XMM2 ; set the pixels ADD EDI, 16 ; inc adr SUB ECX, 4 JG loop JMP end singlepixel: MOV EBX, [ESI] ; read source pixel OR EBX, EAX ADD ESI, 3 MOV [EDI], EBX ADD EDI, 4 ; inc adr SUB ECX, 1 JG loop end: EMMS ; declare FPU registers free POP EBX POPFD END SSE2BGR888CopyBGRA8888;*) (* BGRA8888 *) PROCEDURE AnyCopyBGRA8888 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO pix := mode.buf; mode.src.unpack(mode.src, sadr, sbit, pix); SYSTEM.MOVE(ADDRESSOF(pix[0]), dadr, 4); INC(dadr, 4); sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; DEC(len) END END AnyCopyBGRA8888; PROCEDURE BGRA8888CopyAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(pix[0]), 4); mode.dst.pack(mode.dst, dadr, dbit, pix); INC(sadr, 4); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len) END END BGRA8888CopyAny; (*--- dstCopy Transfer ---*) PROCEDURE EmptyTransfer (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); END EmptyTransfer; (*--- srcOverDst Transfer ---*) (* A1 *) PROCEDURE AnyOverA1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR out: CHAR; pix: Pixel; BEGIN SYSTEM.GET(dadr, out); WHILE len > 0 DO mode.src.unpack(mode.src, sadr, sbit, pix); IF pix[a] >= 80X THEN out := Set[ORD(out), dbit] END; sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; INC(dbit); DEC(len); IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); dbit := 0; SYSTEM.GET(dadr, out) END END; SYSTEM.PUT(dadr, out) END AnyOverA1; PROCEDURE A1OverA1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in, out: CHAR; BEGIN SYSTEM.GET(sadr, in); SYSTEM.GET(dadr, out); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN out := Set[ORD(out), dbit] END; INC(sbit); INC(dbit); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END; IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); dbit := 0; SYSTEM.GET(dadr, out) END END; SYSTEM.PUT(dadr, out) END A1OverA1; PROCEDURE A8OverA1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in, out: CHAR; BEGIN SYSTEM.GET(dadr, out); WHILE len > 0 DO SYSTEM.GET(sadr, in); IF in >= 80X THEN out := Set[ORD(out), dbit] END; INC(sadr); INC(dbit); DEC(len); IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); dbit := 0; SYSTEM.GET(dadr, out) END END; SYSTEM.PUT(dadr, out) END A8OverA1; PROCEDURE BGRA8888OverA1 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in, out: CHAR; BEGIN SYSTEM.GET(dadr, out); WHILE len > 0 DO SYSTEM.GET(sadr + a, in); IF in >= 80X THEN out := Set[ORD(out), dbit] END; INC(sadr, 4); INC(dbit); DEC(len); IF dbit = 8 THEN SYSTEM.PUT(dadr, out); INC(dadr); dbit := 0; SYSTEM.GET(dadr, out) END END; SYSTEM.PUT(dadr, out) END BGRA8888OverA1; PROCEDURE A1OverAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN mode.dst.pack(mode.dst, dadr, dbit, mode.buf) END; INC(sbit); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8; DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1OverAny; PROCEDURE A1OverConst8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN SYSTEM.PUT(dadr, mode.buf[0]) END; INC(sbit); INC(dadr); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1OverConst8; PROCEDURE A1OverConst16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN SYSTEM.MOVE(ADDRESSOF(mode.buf[0]), dadr, 2) END; INC(sbit); INC(dadr, 2); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1OverConst16; PROCEDURE A1OverConst24 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN SYSTEM.MOVE(ADDRESSOF(mode.buf[0]), dadr, 3) END; INC(sbit); INC(dadr, 3); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1OverConst24; PROCEDURE A1OverConst32 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in: CHAR; BEGIN SYSTEM.GET(sadr, in); WHILE len > 0 DO IF Bit[ORD(in), sbit] THEN SYSTEM.MOVE(ADDRESSOF(mode.buf[0]), dadr, 4) END; INC(sbit); INC(dadr, 4); DEC(len); IF sbit = 8 THEN INC(sadr); sbit := 0; SYSTEM.GET(sadr, in) END END END A1OverConst32; (* A8 *) PROCEDURE AnyOverA8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR pix: Pixel; b: CHAR; BEGIN WHILE len > 0 DO mode.src.unpack(mode.src, sadr, sbit, pix); IF pix[a] = 0FFX THEN SYSTEM.PUT(dadr, 0FFX) ELSIF pix[a] # 0X THEN SYSTEM.GET(dadr, b); SYSTEM.PUT(dadr, CHR(ORD(pix[a]) + ORD(b) * LONG(255-ORD(pix[a])) DIV 255)) END; sbit := sbit + mode.src.bpp; INC(sadr, sbit DIV 8); sbit := sbit MOD 8; INC(dadr); DEC(len) END END AnyOverA8; PROCEDURE A8OverAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR spix, dpix: Pixel; alpha, rc,gc,bc,ac: CHAR; BEGIN ac := mode.col[a]; rc := mode.col[r]; gc := mode.col[g]; bc := mode.col[b]; WHILE len > 0 DO SYSTEM.GET(sadr, alpha); alpha := CHR(ORD(ac) * ORD(alpha) DIV 255); IF alpha = 0FFX THEN mode.dst.pack(mode.dst, dadr, dbit, mode.buf) ELSIF alpha # 0X THEN spix[a] := alpha; (* the following computation of the colors has to be done because the blending method seems to assume this *) spix[r] := CHR(ORD(rc) * ORD(alpha) DIV 255); spix[g] := CHR(ORD(gc) * ORD(alpha) DIV 255); spix[b] := CHR(ORD(bc) * ORD(alpha) DIV 255); mode.dst.unpack(mode.dst, dadr, dbit, dpix); Blend(mode.op, spix, dpix); mode.dst.pack(mode.dst, dadr, dbit, dpix); END; INC(sadr); DEC(len); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8 END END A8OverAny; PROCEDURE A8OverBGRA8888Asm(CONST col: Pixel; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE LDR R0, [FP, #sadr] LDR R1, [FP, #dadr] LDR R2, [FP, #len] LDR R6, [FP, #col] LDRB R3, [R6, #0] ; col[b] LDRB R4, [R6, #1] ; col[g] LDRB R5, [R6, #2] ; col[r] LDRB R10, [R6, #3] ; col[a] ADD R10, R10, #1; to account for DIV 256 i/o DIV 255 below loop: CMP R2, #0 BLE end ; exit if len <= 0 LDRB R6, [R0, #0] ; src[a] MUL R6, R10, R6 ; alpha := src0[a]*col[a] LSR R6, R6, #8 ; alpha := alpha DIV 256 CMP R6, #255 BNE compute ; src[a] # 255 -> compute blended colors ; src[a] = 255 -> just move src to dst MOV R8, R3 ; dst[b] := src0[b] ORR R8, R8, R4, LSL #8 ; dst[g] := src0[g] ORR R8, R8, R5, LSL #16 ; dst[r] := src0[r] ORR R8, R8, R6, LSL #24 ; dst[a] := src[a] B store ; go to the actual data move compute: RSB R7, R6, #255 ; fd := 255 - src[a] LDR R8, [R1, #0] ; R8 := dst ; compute src[b] MUL R9, R3, R6 ; src0[b]*src[a] LSR R9, R9, #8 ; src[b] := (src0[b]*src[a]) DIV 256 ; compute dst[b] AND R11, R8, #0FFH ; dst[b] MUL R11, R11, R7 ; dst[b]*fd ADD R11, R11, R9, LSL #8 ; dst[b]*fd + src[b]*256 LSR R11, R11, #8 ; (dst[b]*fd + src[b]*256) DIV 256 CMP R11, #255 BLT put_b MOV R11, #255 put_b: BIC R8, R8, #0FFH ; clear dst[b] ORR R8, R8, R11 ; compute src[g] MUL R9, R4, R6 ; src0[g]*src[a] LSR R9, R9, #8 ; src[g] := (src0[g]*src[a]) DIV 256 ; compute dst[g] AND R11, R8, #0FF00H ; dst[g]*256 LSR R11, R11, #8 ; dst[g] MUL R11, R11, R7 ; dst[g]*fd ADD R11, R11, R9, LSL #8 ; dst[g]*fd + src[g]*256 LSR R11, R11, #8 ; (dst[g]*fd + src[g]*256) DIV 256 CMP R11, #255 BLT put_g MOV R11, #255 put_g: BIC R8, R8, #0FF00H ; clear dst[g] ORR R8, R8, R11, LSL #8 ; compute src[r] MUL R9, R5, R6 ; src0[r]*src[a] LSR R9, R9, #8 ; src[r] := (src0[r]*src[a]) DIV 256 ; compute dst[r] AND R11, R8, #0FF0000H ; dst[r]*65536 LSR R11, R11, #16 ; dst[r] MUL R11, R11, R7 ; dst[r]*fd ADD R11, R11, R9, LSL #8 ; dst[r]*fd + src[r]*256 LSR R11, R11, #8 ; (dst[r]*fd + src[r]*256) DIV 256 CMP R11, #255 BLT put_r MOV R11, #255 put_r: BIC R8, R8, #0FF0000H ; clear dst[r] ORR R8, R8, R11, LSL #16 ; compute dst[a] AND R11, R8, #0FF000000H ; dst[a]*16777216 LSR R11, R11, #24 ; dst[a] MUL R11, R11, R7 ; dst[a]*fd ADD R11, R11, R6, LSL #8 ; dst[a]*fd + src[a]*256 LSR R11, R11, #8 ; (dstfdc[a] + src[a]*256) DIV 256 CMP R11, #255 BLT put_a MOV R11, #255 put_a: BIC R8, R8, #0FF000000H ; clear dst[a] ORR R8, R8, R11, LSL #24 store: STR R8, [R1, #0] ADD R0, R0, #1 ; INC(sadr); ADD R1, R1, #4 ; INC(dadr,4); SUB R2, R2, #1 ; DEC(len); B loop end: END A8OverBGRA8888Asm; PROCEDURE A8OverBGRA8888(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); BEGIN A8OverBGRA8888Asm(mode.col,sadr,sbit,dadr,dbit,len); END A8OverBGRA8888; (*PROCEDURE A8OverBGRA8888(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR src , dst: Pixel; rc,gc,bc, fd, fs: LONGINT; BEGIN rc := ORD(mode.col[r]); gc := ORD(mode.col[g]); bc := ORD(mode.col[b]); fs := 255; WHILE len > 0 DO SYSTEM.GET(sadr, src[a]); SYSTEM.MOVE(dadr, ADDRESSOF(dst), 4); (* the following computation of the colors has to be done because the blending method seems to assume this *) src[r] := CHR(rc * ORD(src[a]) DIV 255); src[g] := CHR(gc * ORD(src[a]) DIV 255); src[b] := CHR(bc * ORD(src[a]) DIV 255); fd := 255-ORD(src[a]); dst[0] := Clamp[200H + (fs * ORD(src[0]) + fd * ORD(dst[0])) DIV 255]; dst[1] := Clamp[200H + (fs * ORD(src[1]) + fd * ORD(dst[1])) DIV 255]; dst[2] := Clamp[200H + (fs * ORD(src[2]) + fd * ORD(dst[2])) DIV 255]; dst[3] := Clamp[200H + (fs * ORD(src[3]) + fd * ORD(dst[3])) DIV 255]; SYSTEM.MOVE(ADDRESSOF(dst),dadr,4); INC(sadr); INC(dadr,4); DEC(len); END END A8OverBGRA8888;*) PROCEDURE A8OverA8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in, out: CHAR; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr, in); IF in = 0FFX THEN SYSTEM.PUT(dadr, 0FFX) ELSIF in # 0X THEN SYSTEM.GET(dadr, out); SYSTEM.PUT(dadr, CHR(ORD(in) + ORD(out) * LONG(255-ORD(in)) DIV 255)) END; INC(sadr); INC(dadr); DEC(len) END END A8OverA8; PROCEDURE BGRA8888OverBGRA8888(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE LDR R0, [FP, #sadr] LDR R1, [FP, #dadr] LDR R2, [FP, #len] loop: CMP R2, #0 BLE end ; exit if len <= 0 LDR R8, [R0, #0] ; R8 := src LSR R6, R8, #24 ; R6 := src[a] CMP R6, #255 BEQ store ; src[a] = 255 -> just move src to dst MOV R9, #0FFH ; LSB mask AND R3, R9, R8 ; R3 := src[b] AND R4, R9, R8, LSR #8 ; R4 := src[g] AND R5, R9, R8, LSR #16 ; R5 := src[r] compute: RSB R7, R6, #255 ; fd := 255 - src[a] LDR R8, [R1, #0] ; R8 := dst ; compute dst[b] AND R11, R8, #0FFH ; dst[b] MUL R11, R11, R7 ; dst[b]*fd ADD R11, R11, R3, LSL #8 ; dst[b]*fd + src[b]*256 LSR R11, R11, #8 ; (dst[b]*fd + src[b]*256) DIV 256 CMP R11, #255 BLT put_b MOV R11, #255 put_b: BIC R8, R8, #0FFH ; clear dst[b] ORR R8, R8, R11 ; compute dst[g] AND R11, R8, #0FF00H ; dst[g]*256 LSR R11, R11, #8 ; dst[g] MUL R11, R11, R7 ; dst[g]*fd ADD R11, R11, R4, LSL #8 ; dst[g]*fd + src[g]*256 LSR R11, R11, #8 ; (dst[g]*fd + src[g]*256) DIV 256 CMP R11, #255 BLT put_g MOV R11, #255 put_g: BIC R8, R8, #0FF00H ; clear dst[g] ORR R8, R8, R11, LSL #8 ; compute dst[r] AND R11, R8, #0FF0000H ; dst[r]*65536 LSR R11, R11, #16 ; dst[r] MUL R11, R11, R7 ; dst[r]*fd ADD R11, R11, R5, LSL #8 ; dst[r]*fd + src[r]*256 LSR R11, R11, #8 ; (dst[r]*fd + src[r]*256) DIV 256 CMP R11, #255 BLT put_r MOV R11, #255 put_r: BIC R8, R8, #0FF0000H ; clear dst[r] ORR R8, R8, R11, LSL #16 ; compute dst[a] AND R11, R8, #0FF000000H ; dst[a]*16777216 LSR R11, R11, #24 ; dst[a] MUL R11, R11, R7 ; dst[a]*fd ADD R11, R11, R6, LSL #8 ; dst[a]*fd + src[a]*256 LSR R11, R11, #8 ; (dstfdc[a] + src[a]*256) DIV 256 CMP R11, #255 BLT put_a MOV R11, #255 put_a: BIC R8, R8, #0FF000000H ; clear dst[a] ORR R8, R8, R11, LSL #24 store: STR R8, [R1, #0] ADD R0, R0, #4 ; INC(sadr,4); ADD R1, R1, #4 ; INC(dadr,4); SUB R2, R2, #1 ; DEC(len); B loop end: END BGRA8888OverBGRA8888; (*PROCEDURE BGRA8888OverBGRA8888(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR src, dst: Pixel; fd,t: LONGINT; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(src), 4); IF src[a] = 0FFX THEN SYSTEM.MOVE(sadr,dadr,4); ELSIF src[a] # 0X THEN SYSTEM.MOVE(dadr, ADDRESSOF(dst), 4); fd := 256-ORD(src[a]); dst[0] := CHR(MIN( (256 * ORD(src[0]) + fd * ORD(dst[0])) DIV 256, 255)); (* IF t < 255 THEN dst[0] := CHR(t) ELSE dst[0] := CHR(255) END; *) dst[1] := CHR(MIN((256 * ORD(src[1]) + fd * ORD(dst[1])) DIV 256, 255)); (* IF t < 255 THEN dst[1] := CHR(t) ELSE dst[1] := CHR(255) END; *) dst[2] := CHR(MIN( (256 * ORD(src[2]) + fd * ORD(dst[2])) DIV 256, 255)); (* IF t < 255 THEN dst[2] := CHR(t) ELSE dst[2] := CHR(255) END; *) dst[3] := CHR(MIN( (256 * ORD(src[3]) + fd * ORD(dst[3])) DIV 256, 255)); (* IF t < 255 THEN dst[3] := CHR(t) ELSE dst[3] := CHR(255) END; *) SYSTEM.MOVE(ADDRESSOF(dst),dadr,4); END; INC(sadr,4); INC(dadr,4); DEC(len); END END BGRA8888OverBGRA8888;*) (* BGRA8888 *) PROCEDURE BGRA8888OverAny (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR spix, dpix: Pixel; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr, ADDRESSOF(spix),4); (* SYSTEM.GET (sadr, spix); *) IF spix[a] = 0FFX THEN mode.dst.pack(mode.dst, dadr, dbit, spix) ELSIF spix[a] # 0X THEN mode.dst.unpack(mode.dst, dadr, dbit, dpix); Blend(mode.op, spix, dpix); mode.dst.pack(mode.dst, dadr, dbit, dpix) END; INC(sadr, SIZEOF (Pixel)); DEC(len); dbit := dbit + mode.dst.bpp; INC(dadr, dbit DIV 8); dbit := dbit MOD 8 END END BGRA8888OverAny; PROCEDURE BGRA8888OverA8 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR in, out: CHAR; BEGIN WHILE len > 0 DO SYSTEM.GET(sadr + a, in); IF in = 0FFX THEN SYSTEM.PUT(dadr, 0FFX) ELSIF in # 0X THEN SYSTEM.GET(dadr, out); SYSTEM.PUT(dadr, CHR(ORD(in) + ORD(out) * (255 - ORD(in)) DIV 255)) END; INC(sadr, 4); INC(dadr); DEC(len) END END BGRA8888OverA8; PROCEDURE BGRA8888OverAny16 (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR src, dst: Pixel; fd, t: LONGINT; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr,ADDRESSOF(src),4); (* SYSTEM.GET (sadr, src);*) IF src[a] = 0FFX THEN mode.dst.pack(mode.dst, dadr, dbit, src) ELSIF src[a] # 0X THEN mode.dst.unpack(mode.dst, dadr, 0, dst); fd := 255-ORD(src[a]); t := (256 * ORD(src[0]) + fd * ORD(dst[0])) DIV 256; IF t < 255 THEN dst[0] := CHR(t) ELSE dst[0] := CHR(255) END; t := (256 * ORD(src[1]) + fd * ORD(dst[1])) DIV 256; IF t < 255 THEN dst[1] := CHR(t) ELSE dst[1] := CHR(255) END; t := (256 * ORD(src[2]) + fd * ORD(dst[2])) DIV 256; IF t < 255 THEN dst[2] := CHR(t) ELSE dst[2] := CHR(255) END; t := (256 * ORD(src[3]) + fd * ORD(dst[3])) DIV 256; IF t < 255 THEN dst[3] := CHR(t) ELSE dst[3] := CHR(255) END; mode.dst.pack(mode.dst, dadr, 0, dst); END; INC(dadr, 2); INC(sadr, SIZEOF (Pixel)); DEC(len) END END BGRA8888OverAny16; PROCEDURE BGRA8888Over565* (VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); VAR src, dst: Pixel; fd, t: LONGINT; BEGIN WHILE len > 0 DO SYSTEM.MOVE(sadr,ADDRESSOF(src),4); (* SYSTEM.GET (sadr, src); *) IF src[a] = 0FFX THEN SYSTEM.PUT16(dadr, ASH(ORD(src[b]), -3) + ASH(ASH(ORD(src[g]), -2), 5) + ASH(ASH(ORD(src[r]), -3), 11)); ELSIF src[a] # 0X THEN t := SYSTEM.GET16(dadr); dst[b] := CHR((t MOD 32) * 8); dst[g] := CHR((t DIV 32 MOD 64) * 4); dst[r] := CHR((t DIV 2048 MOD 32) * 8); fd := 256-ORD(src[a]); t := (256 * ORD(src[0]) + fd * ORD(dst[0])) DIV 256; IF t < 255 THEN dst[0] := CHR(t) ELSE dst[0] := CHR(255) END; t := (256 * ORD(src[1]) + fd * ORD(dst[1])) DIV 256; IF t < 255 THEN dst[1] := CHR(t) ELSE dst[1] := CHR(255) END; t := (256 * ORD(src[2]) + fd * ORD(dst[2])) DIV 256; IF t < 255 THEN dst[2] := CHR(t) ELSE dst[2] := CHR(255) END; t := (256 * ORD(src[3]) + fd * ORD(dst[3])) DIV 256; IF t < 255 THEN dst[3] := CHR(t) ELSE dst[3] := CHR(255) END; SYSTEM.PUT16(dadr, ASH(ORD(dst[b]), -3) + ASH(ASH(ORD(dst[g]), -2), 5) + ASH(ASH(ORD(dst[r]), -3), 11)); END; INC(dadr, 2); INC(sadr, 4); DEC(len) END END BGRA8888Over565; (* PROCEDURE MMXBGRA8888Over565(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE {SYSTEM.i386, SYSTEM.MMX} PUSHFD ; CLI MOV ESI, [EBP+sadr] MOV EDI, [EBP+dadr] PXOR MMX0, MMX0 PXOR MMX1, MMX1 MOV EAX, 0FFFFFFFFH MOVD MMX7, EAX PUNPCKLBW MMX7, MMX0 ; 00FF00FF00FF00FF MOV ECX, [EBP+len] loop: CMP ECX, 0 JE end MOV EAX, [ESI] XOR EBX, EBX MOV BX, [EDI] ; 255 - alpha MOV EDX, EAX SHR EDX, 24 CMP EDX, 0 JE empty CMP EDX, 255 JE full alpha: NEG EDX ADD EDX, 255 MOVD MMX6, EDX PUNPCKLWD MMX6, MMX6 PUNPCKLDQ MMX6, MMX6 MOVD MMX1, EAX ; unpack dst MOV EDX, EBX ; b SHL EDX, 3 AND EDX, 0F8H MOV EAX, EDX MOV EDX, EBX ; g SHL EDX, 5 AND EDX, 0FC00H OR EAX, EDX MOV EDX, EBX ; r SHL EDX, 8 AND EDX, 0F80000H OR EAX, EDX MOVD MMX2, EAX PUNPCKLBW MMX1, MMX0 ; 0000ARGB --> 0A0R0G0B PMULLW MMX1, MMX7 PUNPCKLBW MMX2, MMX0 ; 0000ARGB --> 0A0R0G0B PMULLW MMX2, MMX6 PADDUSW MMX1, MMX2 ; PSRLW MMX1, 8 ; normalize DB 0FH, 71H, 0D1H, 08H PACKUSWB MMX1, MMX0 ; HUGA BIMBO Muell MOVD EAX, MMX1 full: ; XOR EDX, EDX ; SHR EAX, 3 ; MOV EDX, EAX ; AND EDX, 1FH ; SHR EAX, 2 ; AND EAX, 0FFFFFFE0H ; OR EDX, EAX ; AND EDX, 7FFH ; ; SHR EAX, 3 ; AND EAX, ; ; ; SHR AL, 3 ; SHR AH, 2 ; MOV EDX, EAX ; SHR EAX, 3 ; AND EAX, 01F0000H ; OR EDX, EAX ; AND EDX, 01F3F1FH MOV EBX, EAX AND EBX, 0FFH SHR EBX, 3 MOV EDX, EBX MOV EBX, EAX SHR EBX, 8 AND EBX, 0FFH SHR EBX, 2 SHL EBX, 5 OR EDX, EBX MOV EBX, EAX SHR EBX, 16 AND EBX, 0FFH SHR EBX, 3 SHL EBX, 11 OR EDX, EBX MOV [EDI], DX empty: ADD ESI, 4; ADD EDI, 2; DEC ECX JMP loop end: EMMS ; declare FPU registers free POPFD END MMXBGRA8888Over565;*) (* PROCEDURE SSE2BGRA8888Over565(VAR mode: Mode0; sadr: ADDRESS; sbit: LONGINT; dadr: ADDRESS; dbit, len: LONGINT); CODE {SYSTEM.i386, SYSTEM.MMX, SYSTEM.SSE, SYSTEM.SSE2} PUSHFD PUSH EBX ; CLI PXOR MMX0, MMX0 PXOR MMX1, MMX1 PXOR MMX2, MMX2 PXOR MMX3, MMX3 PXOR MMX4, MMX4 PXOR MMX5, MMX5 PXOR MMX6, MMX6 PXOR MMX7, MMX7 PXOR XMM3, XMM3 PXOR XMM4, XMM4 MOV ESI, [EBP+sadr] MOV EDI, [EBP+dadr] MOV ECX, [EBP+len] ; create masks ; src only FF which is rotated -> MMX3 MOV EAX, 0000000FFH MOVD MMX3, EAX ; dest red -> MMX4 MOV EAX, 0F800F800H MOVD MMX4, EAX ; dest green -> MMX5 MOV EAX, 07E007E0H MOVD MMX5, EAX ; dest blue -> MMX6 ; moved as MMX6 is used in singlepixel ; MOV EAX, 001F001FH ; MOVD MMX6, EAX ; BEGIN ; WHILE len > 0 DO loop: CMP ECX,0 JE end ; jump to end if ECX = 0 ; if len < 8 then do one pixel at the time CMP ECX, 8 JL singlepixel ; else ; take 8 at the time MOV EBX, ESI AND EBX, 0FH CMP EBX, 0 JNE singlepixel alleightpixels: ; dest blue -> MMX6 MOV EAX, 001F001FH MOVD MMX6, EAX ; src := SYSTEM.VAL(Pixel, SYSTEM.GET32(sadr)); ; Load data into memory ;MOV XMM4, 0FF000000FF000000FF000000FF000000H MOVDQA XMM2, [ESI] ;src 5-8 MOVQ2DQ XMM4, MMX3 ; 000000000000000000000000000000FFH MOVDQA XMM1, [ESI+16] ;src 1-4 PREFETCHNTA [ESI+32] ; prepare src 9-15 ; get alphas MOVDQU XMM6, XMM2 PSHUFD XMM4, XMM4, 0 MOVDQU XMM5, XMM1 PSLLD XMM4, 24 PAND XMM6, XMM4 ; alpha 5-8 in XMM6 PAND XMM5, XMM4 ; alpha 1-4 in XMM5 PSRLD XMM5, 24 PSHUFHW XMM5, XMM5, 85H PSRLD XMM6, 24 ; put both alphas into 1 register PSHUFHW XMM6, XMM6, 85H PSHUFLW XMM5, XMM5, 85H PSHUFLW XMM6, XMM6, 58H PSHUFD XMM5, XMM5, 0D0H ; 0102030400000000 PSHUFD XMM6, XMM6, 5CH ; 0000000005060708 PXOR XMM0,XMM0 POR XMM5, XMM6 ; XMM5 = alphas 0102030405060708 PCMPEQD XMM0, XMM5 PMOVMSKB EAX, XMM0 CMP EAX, 0FFFFH ; all alphas = zero; TEST not possible, because only 8 bits compared JE endloop ; mask out alpha = zero ; fd := 255-ORD(src[a]); fd = XMM4 ; MOV XMM4, 00FF00FF00FF00FF00FF00FF00FF00FFH PXOR XMM4, XMM4 MOV EAX, 00FFH PINSRW XMM4, EAX ,0 PSHUFLW XMM4, XMM4, 0 PSHUFD XMM4, XMM4, 0 PSUBW XMM4, XMM5 MOV EAX,1H PINSRW XMM3, EAX ,0 PSHUFLW XMM3, XMM3, 0 PSHUFD XMM3, XMM3, 0 PADDUSW XMM4, XMM3 ; new red ; calculate red 2 ; get source ; sred14 = src14 && (srcMask <<16) ; srcMask << 16 MOVQ2DQ XMM3, MMX3 PSHUFD XMM3, XMM3, 0 MOVDQU XMM5, XMM1 MOVDQU XMM6, XMM2 PSLLD XMM3, 16 ; sred14 = src14 && (srcMask << 24) ; src14 must be copied because it mustn't be changed PAND XMM5, XMM3 ; sred14 PSRLD XMM5, 16 ; sred14s = shuffled sred14 PSHUFHW XMM5, XMM5,85H PAND XMM6, XMM3 ; sred58 PSRLD XMM6, 16 PSHUFLW XMM5, XMM5,85H PSHUFHW XMM6, XMM6,85H PSHUFD XMM5, XMM5,0D0H ; sred14s PSHUFLW XMM6, XMM6,58H PSHUFD XMM6, XMM6,5CH ; sred58s POR XMM5, XMM6 ; sred18 ; sred18255 = sred18 * 256- sred18 MOVDQU XMM7, XMM5 PSLLW XMM5, 8 PSUBUSW XMM5, XMM7 ; sred18255 ; src is now ready ; destination ; dest18 must be copied because it mustn't be changed ; Load data into memory MOVDQU XMM3, [EDI] ;dest 1-8 MOVQ2DQ XMM6, MMX4 PSHUFD XMM6, XMM6, 0 MOVDQU XMM7, XMM3 PAND XMM7, XMM6 ; dred18 PSRLW XMM7, 8 ; dred18alpha = dred18 * negalpha PMULLW XMM7, XMM4 ; dred18alpha ; dest is prepared ; combining dest and src ; dred18big = sred18255 + dred18alpha PADDUSW XMM7, XMM5 ; dred18big ; dred18f = dred18big && destMaskred128 because >> 11 and << 11 is && mask PAND XMM7, XMM6 ; dred18f ; dest18nr0 = dest18 && (~destMaskred128) PANDN XMM6, XMM3 ; dest18nr0 ; dest18nrf = dest18nr0 || dred18f POR XMM6, XMM7 MOVDQU XMM3, XMM6 ; red is calculated ; calculate green: ; get source ; sgreen14 = src14 && (srcMask <<8) ; srcMask << 8 MOVQ2DQ XMM7, MMX3 PSHUFD XMM7, XMM7, 0 MOVDQU XMM5, XMM1 PSLLD XMM7, 8 PAND XMM5, XMM7 ; sgreen14 PSRLD XMM5, 8 ; sgreen14s = shuffled sgreen14 PSHUFHW XMM5, XMM5,85H MOVDQU XMM6, XMM2 PSHUFLW XMM5, XMM5,85H PAND XMM6, XMM7 ; sgreen58 PSRLD XMM6, 8 PSHUFD XMM5, XMM5,0D0H ; sgreen14s ; sgreen58 = src58&& (srcMask << 8) ; src58 must be copied because it mustn't be changed ; sgreen58s = shuffled sgreen58 PSHUFHW XMM6, XMM6,85H PSHUFLW XMM6, XMM6,58H PSHUFD XMM6, XMM6,5CH ; sgreen58s ; sgreen18 = sgreen14s || sgreen58s POR XMM5, XMM6 ; sgreen18 ; sgreen18255 = sgreen18 * 256- sgreen18 MOVDQU XMM7, XMM5 MOVQ2DQ XMM6, MMX5 PSLLW XMM5, 8 PSUBUSW XMM5, XMM7 ; sgreen18255 PSHUFD XMM6, XMM6, 0 MOVDQU XMM7, XMM3 PAND XMM7, XMM6 ; dgreen18 PSRLW XMM7,3 ; dgreen18alpha = dgreen18 * negalpha PMULLW XMM7, XMM4 ; dgreen18alpha ; dest is prepared ; combining dest and src ; dgreen18big = sgreen18255 + dgreen18alpha PADDUSW XMM7, XMM5 ; dgreen18big PANDN XMM6, XMM3 ; dest18ng0 ; dgreen18f = (dgreen18big >> 11) <<5 PSRLW XMM7, 10 ; dgreen18f PSLLW XMM7, 5 ; dest18ng0 = dest18 && (~destMaskgreen128) ; dest18ngf = dest18ng0 || dred18f POR XMM6, XMM7 MOVDQU XMM3, XMM6 ; green is calculated ; calculate blue ; get source ; sblue14 = src14 && (srcMask) ; srcMask MOVQ2DQ XMM7, MMX3 MOVDQU XMM5, XMM1 PSHUFD XMM7, XMM7, 0 MOVDQU XMM6, XMM2 ; sblue14 = src14 && (srcMask) ; src14 must be copied because it mustn't be changed PAND XMM5, XMM7 ; sblue14 ; sblue14s = shuffled sblue14 PSHUFHW XMM5, XMM5,85H PAND XMM6, XMM7 ; sblue58 PSHUFHW XMM6, XMM6,85H PSHUFLW XMM5, XMM5,85H PSHUFLW XMM6, XMM6,58H PSHUFD XMM5, XMM5,0D0H ; sblue14s PSHUFD XMM6, XMM6,5CH ; sblue58s POR XMM5, XMM6 ; sblue18 ; sblue18255 = sblue18 * 256- sblue18 MOVDQU XMM7, XMM5 PSLLW XMM5, 8 PSUBUSW XMM5, XMM7 ; sblue18255 MOVQ2DQ XMM6, MMX6 PSHUFD XMM6, XMM6, 0 MOVDQU XMM7, XMM3 PAND XMM7, XMM6 ; dblue18 PSLLW XMM7, 3 PMULLW XMM7, XMM4 ; dblue18alpha ; dest is prepared ; combining dest and src ; dblue18big = sblue18255 + dblue18alpha PADDUSW XMM7, XMM5 ; dblue18big ; dblue18f = (dblue18big >> 11) PANDN XMM6, XMM3 ; dest18nr0 PSRLW XMM7, 11 ; dblue18f ; dest18nr0 = dest18 && (~destMaskblue128) ; dest18nbf = dest18nb0 || dblue18f POR XMM6, XMM7 MOVDQU XMM3, XMM6 ; blue is calculated ; now dest is calculated, store it ; get 0 stuff MOVDQU XMM5, [EDI] PAND XMM5,XMM0 PANDN XMM0, XMM3 POR XMM0, XMM5 MOVDQU [EDI],XMM0 PREFETCHNTA [EDI+16] ; prepare dest 9-15 endloop: ADD ESI, 32 ; num of bytes ADD EDI, 16 SUB ECX, 8 JMP loop singlepixel: ; original code from MMXBGRA8888Over565, adjusted to fit this procedure MOV EAX, 0FFFFFFFFH MOVD MMX7, EAX PUNPCKLBW MMX7, MMX0 ; 00FF00FF00FF00FF MOV EAX,[ESI] XOR EBX, EBX MOV BX, [EDI] ; 255 - alpha MOV EDX, EAX SHR EDX, 24 CMP EDX, 0 JE empty CMP EDX, 255 JE full alpha: NEG EDX ADD EDX, 255 MOVD MMX6, EDX PUNPCKLWD MMX6, MMX6 PUNPCKLDQ MMX6, MMX6 MOVD MMX1, EAX ; unpack dst MOV EDX, EBX ; b SHL EDX, 3 AND EDX, 0F8H MOV EAX, EDX MOV EDX, EBX ; g SHL EDX, 5 AND EDX, 0FC00H OR EAX, EDX MOV EDX, EBX ; r SHL EDX, 8 AND EDX, 0F80000H OR EAX, EDX MOVD MMX2, EAX PUNPCKLBW MMX1, MMX0 ; 0000ARGB --> 0A0R0G0B PMULLW MMX1, MMX7 PUNPCKLBW MMX2, MMX0 ; 0000ARGB --> 0A0R0G0B PMULLW MMX2, MMX6 PADDUSW MMX1, MMX2 ; PSRLW MMX1, 8 ; normalize DB 0FH, 71H, 0D1H, 08H PACKUSWB MMX1, MMX0 ; HUGA BIMBO Muell MOVD EAX, MMX1 full: MOV EBX, EAX AND EBX, 0FFH SHR EBX, 3 MOV EDX, EBX MOV EBX, EAX SHR EBX, 8 AND EBX, 0FFH SHR EBX, 2 SHL EBX, 5 OR EDX, EBX MOV EBX, EAX SHR EBX, 16 AND EBX, 0FFH SHR EBX, 3 SHL EBX, 11 OR EDX, EBX MOV [EDI], DX empty: ADD ESI, 4; ADD EDI, 2; DEC ECX JMP loop end: EMMS ; declare FPU registers free POP EBX POPFD END SSE2BGRA8888Over565;*) (** find (optimized) pixel transfer procedure for transfer mode and given source and destination formats **) PROCEDURE Bind* (VAR mode: Mode; VAR src, dst: Format); VAR op: LONGINT; val,i: LONGINT; BEGIN IF Same(src, mode.src) & Same(dst, mode.dst) THEN ASSERT(mode.transfer # NIL, 120); RETURN (* assume transfer procedure is still valid *) END; mode.src := src; mode.dst := dst; mode.buf := mode.col; IF (src.pal # NIL) & ((mode.map = NIL) OR (LEN(mode.map^) # src.pal.used) ) THEN NEW(mode.map, src.pal.used) END; (* try to convert complex composite operations into simpler ones *) IF alpha IN src.components * dst.components THEN (* source and destination contain alpha information *) op := mode.op ELSIF alpha IN src.components THEN (* only source contains alpha *) CASE mode.op OF | dstOverSrc: op := dstCopy | srcInDst: op := srcCopy | srcWithoutDst: op := clear | srcAtopDst: op := srcOverDst | dstAtopSrc: op := dstInSrc | srcXorDst: op := dstWithoutSrc ELSE op := mode.op END ELSIF alpha IN dst.components THEN (* only destination contains alpha *) CASE mode.op OF | srcOverDst: op := srcCopy | dstInSrc: op := dstCopy | dstWithoutSrc: op := clear | srcAtopDst: op := srcInDst | dstAtopSrc: op := dstOverSrc | srcXorDst: op := srcWithoutDst ELSE op := mode.op END ELSE (* no alpha in either source or destination *) CASE mode.op OF | srcOverDst, srcInDst, srcAtopDst: op := srcCopy | dstOverSrc, dstInSrc, dstAtopSrc: op := dstCopy | srcWithoutDst, dstWithoutSrc, srcXorDst: op := clear ELSE op := mode.op END END; IF op = InvDst THEN mode.transfer:=InvAny; ELSIF op = InvOverDst THEN mode.transfer:=InvOverAny; ELSIF op = clear THEN CASE dst.code OF | a1: mode.transfer := Clear1 | a8, bgr555, bgr565, bgr466, bgr888(*, bgra8888*): mode.transfer := ClearBytes | bgra8888: mode.transfer:=Clear32; | p8: mode.buf[0] := CHR(CLUTs.Match(dst.pal.clut, 0)); IF mode.buf[0] = 0X THEN mode.transfer := ClearBytes ELSE mode.transfer := ConstCopy8 END | d8: mode.buf[0] := CHR(ColorToIndex(0)); IF mode.buf[0] = 0X THEN mode.transfer := ClearBytes ELSE mode.transfer := ConstCopy8 END | p16: val:=CLUTs.Match(dst.pal.clut, 0); IF dst.pal.used>256 THEN val:=val*dst.pal.used DIV 256 END; SYSTEM.PUT16(ADDRESSOF(mode.buf[0]),SHORT(val)); (*PH090122*) (*mode.buf[0] := CHR(PaletteIndex(dst.pal, 0, 0, 0));*) IF val = 0 THEN mode.transfer := ClearBytes ELSE mode.transfer := ConstCopy16 END ELSE mode.transfer := ClearAny END ELSIF op = srcCopy THEN CASE dst.code OF | a1: CASE src.code OF | a1: mode.transfer := Copy1 | a8: mode.transfer := A8CopyA1 | bgra8888: mode.transfer := BGRA8888CopyA1 ELSE IF alpha IN src.components THEN mode.transfer := AnyCopyA1 ELSE mode.transfer := Set1 END END | a8: CASE src.code OF | a1: mode.transfer := A1CopyA8 | a8: mode.transfer := Copy8 | bgra8888: mode.transfer := BGRA8888CopyA8 ELSE IF alpha IN src.components THEN mode.transfer := AnyCopyA8 ELSE mode.buf[0] := 0FFX; mode.transfer := ConstCopy8 END END | p8: CASE src.code OF | a1, a8: mode.buf[0] := CHR(CLUTs.Match(dst.pal.clut, ORD(mode.col[b]) + ASH(ORD(mode.col[g]), 8) + ASH(ORD(mode.col[r]), 16))); mode.transfer := ConstCopy8 | p8: IF src.pal = dst.pal THEN mode.transfer := Copy8 ELSE FOR i := 0 TO src.pal.used-1 DO mode.map[i] := SHORT(CLUTs.Match(dst.pal.clut, ORD(src.pal.col[i, b]) + ASH(ORD(src.pal.col[i, g]), 8) + ASH(ORD(src.pal.col[i, r]), 16))) END; mode.transfer := I8CopyI8 END | d8: FOR i := 0 TO 255 DO mode.map[i] := SHORT(CLUTs.Match(dst.pal.clut, IndexToColor(i) MOD 1000000H)) END; mode.transfer := I8CopyI8 | bgr555, bgr565, bgr466,p16: mode.transfer := Any16CopyP8 | bgr888: mode.transfer := BGR888CopyP8 | bgra8888: mode.transfer := BGRA8888CopyP8 ELSE mode.transfer := AnyCopyP8 END | d8: CASE src.code OF | a1, a8: mode.buf[0] := CHR(ColorToIndex( ORD(mode.col[b]) + ASH(ORD(mode.col[g]), 8) + ASH(ORD(mode.col[r]), 16))); mode.transfer := ConstCopy8 | p8: FOR i := 0 TO src.pal.used-1 DO mode.map[i] := SHORT(ColorToIndex( ORD(src.pal.col[i, b]) + ASH(ORD(src.pal.col[i, g]), 8) + ASH(ORD(src.pal.col[i, r]), 16))) END; mode.transfer := I8CopyI8 | d8: mode.transfer := Copy8 | bgr555, bgr565, bgr466, p16: mode.transfer := Any16CopyD8 | bgr888: mode.transfer := BGR888CopyD8 | bgra8888: mode.transfer := BGRA8888CopyD8 ELSE mode.transfer := AnyCopyD8 END | p16: CASE src.code OF | a1, a8: dst.pack(dst, ADDRESSOF(mode.buf[0]), 0, mode.col); mode.transfer := ConstCopy16 | p8: mode.transfer := P8CopyAny16 | d8: mode.transfer := D8CopyAny16 | p16: IF src.pal = dst.pal THEN mode.transfer := Copy16 ELSE FOR i := 0 TO src.pal.used-1 DO val:=CLUTs.Match(dst.pal.clut, ORD(src.pal.col[i, b]) + ASH(ORD(src.pal.col[i, g]), 8) + ASH(ORD(src.pal.col[i, r]), 16)); IF dst.pal.used>256 THEN val := val * dst.pal.used DIV 256 END; mode.map[i] := SHORT(val) END; mode.transfer := I16CopyI16 END | bgr555, bgr565, bgr466: mode.transfer := Any16CopyAny16 | bgr888: mode.transfer := BGR888CopyAny16 | bgra8888: mode.transfer := BGRA8888CopyAny16 ELSE mode.transfer := AnyCopyAny16 END; | bgr555, bgr565, bgr466: CASE src.code OF | a1, a8: dst.pack(dst, ADDRESSOF(mode.buf[0]), 0, mode.col); mode.transfer := ConstCopy16 | p8: mode.transfer := P8CopyAny16 | d8: mode.transfer := D8CopyAny16 | bgr555, bgr565, bgr466,p16: IF src.code = dst.code THEN mode.transfer := Copy16 ELSE mode.transfer := Any16CopyAny16 END | bgr888: mode.transfer := BGR888CopyAny16 | bgra8888: mode.transfer := BGRA8888CopyAny16 ELSE mode.transfer := AnyCopyAny16 END; | bgr888: CASE src.code OF | a1, a8: mode.buf := mode.col; mode.transfer := ConstCopy24 | p8: mode.transfer := P8CopyBGR888 | d8: mode.transfer := D8CopyBGR888 | p16: mode.transfer := P16CopyBGR888 (*PH090122*) | bgr555, bgr565, bgr466: mode.transfer := Any16CopyBGR888 | bgr888: mode.transfer := Copy24 | bgra8888: (* IF SSE2enabled THEN mode.transfer := SSE2BGRA8888CopyBGR888 ELSE *) mode.transfer := BGRA8888CopyBGR888 (* END*); ELSE mode.transfer := AnyCopyBGR888 END | bgra8888: CASE src.code OF | a1: mode.transfer := A1CopyBGRA8888 | a8: mode.transfer := A8CopyBGRA8888 | p8: mode.transfer := P8CopyBGRA8888 | d8: mode.transfer := D8CopyBGRA8888 | p16: mode.transfer := P16CopyBGRA8888 (*PH090122*) | bgr555, bgr565, bgr466: mode.transfer := Any16CopyBGRA8888 | bgr888: (*IF SSE2enabled THEN mode.transfer := SSE2BGR888CopyBGRA8888*) (*ELSE*) mode.transfer :=BGR888CopyBGRA8888; (*END;*) | bgra8888: mode.transfer := Copy32 ELSE mode.transfer := AnyCopyBGRA8888 END ELSE CASE src.code OF | a1: mode.transfer := A1CopyAny | p8: mode.transfer := P8CopyAny | d8: mode.transfer := D8CopyAny | bgr555, bgr565, bgr466,p16: mode.transfer := Any16CopyAny | bgr888: mode.transfer := BGR888CopyAny | bgra8888: mode.transfer := BGRA8888CopyAny ELSE IF (src.bpp MOD 8 = 0) & (dst.bpp MOD 8 = 0) THEN mode.transfer := AnyBytesCopyAnyBytes ELSE mode.transfer := AnyCopyAny END END END ELSIF op = dstOverSrc THEN mode.transfer := EmptyTransfer ELSIF op = srcOverDst THEN CASE dst.code OF | a1: CASE src.code OF | a1: mode.transfer := A1OverA1 | a8: mode.transfer := A8OverA1 | bgra8888: mode.transfer := BGRA8888OverA1 ELSE mode.transfer := AnyOverA1 END | a8: CASE src.code OF | a1: mode.buf[0] := 0FFX; mode.transfer := A1OverConst8 | a8: mode.transfer := A8OverA8 | bgra8888: mode.transfer := BGRA8888OverA8 ELSE mode.transfer := AnyOverA8 END | bgra8888: CASE src.code OF | a1: mode.buf := mode.col; mode.transfer := A1OverConst32 | a8: mode.buf := mode.col; mode.transfer := A8OverAny; IF mode.op = srcOverDst THEN mode.transfer := A8OverBGRA8888 END; | bgra8888: mode.transfer := BGRA8888OverBGRA8888 ELSE mode.transfer := BGRA8888OverAny; (* ? *) END ELSE CASE src.code OF | a1: CASE dst.code OF | p8: mode.buf[0] := CHR(CLUTs.Match(dst.pal.clut, ORD(mode.col[b]) + ASH(ORD(mode.col[g]), 8) + ASH(ORD(mode.col[r]), 16))); mode.transfer := A1OverConst8 | d8: mode.buf[0] := CHR(ColorToIndex(ORD(mode.col[b]) + ASH(ORD(mode.col[g]), 8) + ASH(ORD(mode.col[r]), 16))); mode.transfer := A1OverConst8 | p16: (* this is probably not correct ... *) mode.buf[0] := CHR(PaletteIndex(dst.pal, ORD(mode.col[r]), ORD(mode.col[g]), ORD(mode.col[b]))); mode.transfer := A1OverConst16 | bgr555, bgr565, bgr466: dst.pack(dst, ADDRESSOF(mode.buf[0]), 0, mode.col); mode.transfer := A1OverConst16 | bgr888: mode.buf := mode.col; mode.transfer := A1OverConst24 ELSE mode.transfer := A1OverAny END | a8: mode.buf := mode.col; mode.transfer := A8OverAny | bgra8888: CASE dst.code OF | bgr555, bgr466, p16: mode.transfer := BGRA8888OverAny16 | bgr565 : (*IF MMXenabled THEN mode.transfer := MMXBGRA8888Over565; IF SSE2enabled THEN mode.transfer := SSE2BGRA8888Over565; END; ELSE*) mode.transfer := BGRA8888Over565 (*END*) ELSE mode.transfer := BGRA8888OverAny END ELSE mode.transfer := AnyBlendAny END END ELSE mode.transfer := AnyBlendAny END; ASSERT(mode.transfer # NIL, 120) END Bind; (**--- Image Operations ---**) (** get pixel from image **) PROCEDURE Get* (img: Image; x, y: LONGINT; VAR pix: Pixel; VAR mode: Mode); VAR bit: LONGINT; adr: ADDRESS; BEGIN ASSERT((0 <= x) & (x < img.width) & (0 <= y) & (y < img.height), 100); bit := x * img.fmt.bpp; adr := img.adr + y * img.bpr + bit DIV 8; bit := bit MOD 8; Bind(mode, img.fmt, PixelFormat); (*mode.transfer(mode, adr, bit, ADDRESSOF(pix), 0, 1)*) mode.transfer(mode, adr, bit, ADDRESSOF(pix[0]), 0, 1) (*PH090122*) END Get; (** put pixel into image **) PROCEDURE Put* (img: Image; x, y: LONGINT; CONST pix: Pixel; VAR mode: Mode); VAR bit: LONGINT; adr: ADDRESS; BEGIN (*ASSERT((0 <= x) & (x < img.width) & (0 <= y) & (y < img.height), 100);*) (*avoid a HALT if roundoff errors from higher levels occur here*) IF (0 > x) OR (x >= img.width) OR (0 > y) OR (y >= img.height) THEN RETURN END; bit := x * img.fmt.bpp; adr := img.adr + y * img.bpr + bit DIV 8; bit := bit MOD 8; Bind(mode, PixelFormat, img.fmt); mode.transfer(mode, ADDRESSOF(pix[0]), 0, adr, bit, 1) END Put; (** fill rectangular area **) PROCEDURE Fill* (img: Image; llx, lly, urx, ury: LONGINT; CONST pix: Pixel; VAR mode: Mode); VAR bit, bb, x, c, t: LONGINT; m: Mode; adr, aa: ADDRESS; BEGIN ASSERT((0 <= llx) & (llx < urx) & (urx <= img.width) & (0 <= lly) & (lly < ury) & (ury <= img.height), 100); bit := llx * img.fmt.bpp; adr := img.adr + lly * img.bpr + bit DIV 8; bit := bit MOD 8; IF (mode.op = srcCopy) & (img.fmt.code IN {bgr565}) THEN (* shortcut for speed in important cases *) c := ASH(ORD(pix[b]), -3) + ASH(ASH(ORD(pix[g]), -2), 5) + ASH(ASH(ORD(pix[r]), -3), 11); t := urx - llx; WHILE lly < ury DO Fill16(adr, t, c); INC(lly); INC(adr, img.bpr) END ELSIF (mode.op = srcCopy) & (img.fmt.code IN {}) THEN c := ASH(ORD(pix[r]), 24) + ASH(ORD(pix[g]), 16) + ASH(ORD(pix[b]), 8) + ORD(pix[a]); t := urx - llx; WHILE lly < ury DO Fill32(adr, t, c); INC(lly); INC(adr, img.bpr) END ELSE Bind(mode, PixelFormat, img.fmt); IF (mode.op IN {clear, srcCopy}) OR (pix[a] = 0FFX) & (mode.op IN {srcOverDst, dstWithoutSrc}) THEN (* dst is replaced *) (* copy one pixel to lower left corner of rect *) mode.transfer(mode, ADDRESSOF(pix[0]), 0, adr, bit, 1); (* copy pixel to rest of bottom row *) InitMode(m, srcCopy); Bind(m, img.fmt, img.fmt); IF (bit = 0) & (img.fmt.bpp MOD 8 = 0) THEN (* use simple address calculation *) bb := img.fmt.bpp DIV 8; aa := adr + bb; x := llx+1; WHILE x < urx DO m.transfer(m, adr, 0, aa, 0, 1); INC(aa, bb); INC(x) END ELSE bb := bit + img.fmt.bpp; aa := adr + bb DIV 8; bb := bb MOD 8; x := llx+1; WHILE x < urx DO m.transfer(m, adr, bit, aa, bb, 1); bb := bb + img.fmt.bpp; aa := aa + bb DIV 8; bb := bb MOD 8; INC(x) END END; (* now copy bottom row to others *) INC(lly); aa := adr + img.bpr; WHILE lly < ury DO m.transfer(m, adr, bit, aa, bit, urx - llx); INC(lly); INC(aa, img.bpr) END ELSE (* fill pixel by pixel *) WHILE lly < ury DO x := llx; aa := adr; bb := bit; WHILE x < urx DO mode.transfer(mode, ADDRESSOF(pix[0]), 0, aa, bb, 1); bb := bb + img.fmt.bpp; aa := aa + bb DIV 8; bb := bb MOD 8; INC(x) END; INC(lly); INC(adr, img.bpr) END END END END Fill; (** clear image **) PROCEDURE Clear* (img: Image); VAR mode: Mode; BEGIN InitMode(mode, clear); Bind(mode, PixelFormat, img.fmt); Fill(img, 0, 0, img.width, img.height, Zero, mode) END Clear; (** get several pixels and store them in array in requested format **) PROCEDURE GetPixels* (img: Image; x, y, w: LONGINT; VAR fmt: Format; VAR buf: ARRAY OF CHAR; ofs : LONGINT; VAR mode: Mode); VAR sbit: LONGINT; sadr: ADDRESS; BEGIN ASSERT((0 <= x) & (x + w <= img.width) & (0 <= y) & (y <= img.height), 100); ASSERT(ofs + w * fmt.bpp DIV 8 <= LEN(buf), 101); Bind(mode, img.fmt, fmt); sbit := x * img.fmt.bpp; sadr := img.adr + y * img.bpr + sbit DIV 8; sbit := sbit MOD 8; mode.transfer(mode, sadr, sbit, ADDRESSOF(buf[ofs]), 0, w) END GetPixels; (** put several pixels from array in given format into image **) PROCEDURE PutPixels* (img: Image; x, y, w: LONGINT; VAR fmt: Format; VAR buf: ARRAY OF CHAR; ofs : LONGINT; VAR mode: Mode); VAR dbit: LONGINT; dadr: ADDRESS; BEGIN ASSERT((0 <= x) & (x + w <= img.width) & (0 <= y) & (y <= img.height), 100); ASSERT(ofs + w * fmt.bpp DIV 8 <= LEN(buf), 101); dbit := x * img.fmt.bpp; dadr := img.adr + y * img.bpr + dbit DIV 8; dbit := dbit MOD 8; Bind(mode, fmt, img.fmt); mode.transfer(mode, ADDRESSOF(buf[ofs]), 0, dadr, dbit, w) END PutPixels; (** copy rectangular area to the same or another image in specified mode **) PROCEDURE Copy* (src, dst: Image; llx, lly, urx, ury, dx, dy: LONGINT; VAR mode: Mode); VAR w, h, sbit, dbit, slen, sb, db, len, l: LONGINT; sadr, dadr, sa, da: ADDRESS; BEGIN ASSERT((0 <= llx) & (llx <= urx) & (urx <= src.width) & (0 <= lly) & (lly <= ury) & (ury <= src.height), 100); ASSERT((0 <= dx) & (dx + urx - llx <= dst.width) & (0 <= dy) & (dy + ury - lly <= dst.height), 101); Bind(mode, src.fmt, dst.fmt); w := urx - llx; h := ury - lly; IF (src # dst) OR (lly > dy) OR (lly = dy) & ((llx > dx) OR (urx <= dx)) THEN (* copy lines bottom-up *) sbit := llx * src.fmt.bpp; sadr := src.adr + lly * src.bpr + sbit DIV 8; sbit := sbit MOD 8; dbit := dx * dst.fmt.bpp; dadr := dst.adr + dy * dst.bpr + dbit DIV 8; dbit := dbit MOD 8; WHILE h > 0 DO mode.transfer(mode, sadr, sbit, dadr, dbit, w); INC(sadr, src.bpr); INC(dadr, dst.bpr); DEC(h) END ELSIF lly < dy THEN (* copy lines top-down *) sbit := llx * src.fmt.bpp; sadr := src.adr + ury * src.bpr + sbit DIV 8; sbit := sbit MOD 8; dbit := dx * dst.fmt.bpp; dadr := dst.adr + (dy + h) * dst.bpr + dbit DIV 8; dbit := dbit MOD 8; WHILE h > 0 DO DEC(sadr, src.bpr); DEC(dadr, dst.bpr); DEC(h); mode.transfer(mode, sadr, sbit, dadr, dbit, w) END ELSIF llx # dx THEN (* uh oh! overlapping spans *) slen := dx + w - urx; (* maximal span length guaranteeing non-overlapping spans *) sbit := urx * src.fmt.bpp; sadr := src.adr + lly * src.bpr + sbit DIV 8; sbit := sbit MOD 8; dbit := (dx + w) * dst.fmt.bpp; dadr := dst.adr + dy * dst.bpr + dbit DIV 8; dbit := dbit MOD 8; WHILE h > 0 DO sa := sadr; sb := sbit; da := dadr; db := dbit; len := w; WHILE len > 0 DO l := slen; IF l > len THEN l := len END; DEC(sb, l * src.fmt.bpp); INC(sa, sb DIV 8); sb := sb MOD 8; DEC(db, l * dst.fmt.bpp); INC(da, db DIV 8); db := db MOD 8; mode.transfer(mode, sa, sb, da, db, l); DEC(len, l) END; INC(sadr, src.bpr); INC(dadr, dst.bpr); DEC(h) END END END Copy; (** replicate pattern within rectangular area of image using given mode **) PROCEDURE FillPattern* (pat, dst: Image; llx, lly, urx, ury, px, py: LONGINT; VAR mode: Mode); VAR pw, ph, olx, oby, ilx, olw, irw, dy, sy, dx, sx, ty: LONGINT; BEGIN ASSERT((0 <= llx) & (llx <= urx) & (urx <= dst.width) & (0 <= lly) & (lly <= ury) & (ury <= dst.height), 100); pw := pat.width; ph := pat.height; olx := px + (llx - px) DIV pw * pw; oby := py + (lly - py) DIV ph * ph; ilx := olx + pw; olw := llx - olx; irw := (urx - px) MOD pw; IF urx - irw < ilx THEN irw := olw + urx - llx END; dy := lly; sy := lly - oby; IF (oby < lly) & (oby + ph <= ury) THEN dx := llx; sx := olw; IF (olx < llx) & (ilx <= urx) THEN Copy(pat, dst, sx, sy, pw, ph, llx, lly, mode); dx := ilx; sx := 0 END; WHILE dx + pw <= urx DO Copy(pat, dst, 0, sy, pw, ph, dx, lly, mode); INC(dx, pw) END; IF dx < urx THEN Copy(pat, dst, sx, sy, irw, ph, dx, lly, mode) END; dy := oby + ph; sy := 0 END; WHILE dy + ph <= ury DO dx := llx; sx := olw; IF (olx < llx) & (ilx <= urx) THEN Copy(pat, dst, sx, 0, pw, ph, llx, dy, mode); dx := ilx; sx := 0 END; WHILE dx + pw <= urx DO Copy(pat, dst, 0, 0, pw, ph, dx, dy, mode); INC(dx, pw) END; IF dx < urx THEN Copy(pat, dst, sx, 0, irw, ph, dx, dy, mode) END; INC(dy, ph) END; IF dy < ury THEN ty := sy + ury - dy; dx := llx; sx := olw; IF (olx < llx) & (ilx <= urx) THEN Copy(pat, dst, sx, sy, pw, ty, llx, dy, mode); dx := ilx; sx := 0 END; WHILE dx + pw <= urx DO Copy(pat, dst, 0, sy, pw, ty, dx, dy, mode); INC(dx, pw) END; IF dx < urx THEN Copy(pat, dst, sx, sy, irw, ty, dx, dy, mode) END END END FillPattern; (** darken image while maintaining coverage **) PROCEDURE Darken* (img: Image; factor: REAL); VAR s, i, j, k, y, x, bit: LONGINT; adr: ADDRESS; clamp: ARRAY 256 OF CHAR; pix: Pixel; BEGIN s := ABS(ENTIER(255*factor + 0.5)); IF (s # 255) & (img.fmt.components # {alpha}) THEN i := 256; j := 256*s; REPEAT DEC(i); DEC(j, s); k := j DIV 255; IF k <= 255 THEN clamp[i] := CHR(k) ELSE clamp[i] := 0FFX END UNTIL i = 0; y := 0; WHILE y < img.height DO x := 0; adr := img.adr + y * img.bpr; bit := 0; WHILE x < img.width DO img.fmt.unpack(img.fmt, adr, bit, pix); pix[r] := clamp[ORD(pix[r])]; pix[g] := clamp[ORD(pix[g])]; pix[b] := clamp[ORD(pix[b])]; img.fmt.pack(img.fmt, adr, bit, pix); bit := bit + img.fmt.bpp; INC(adr, bit); bit := bit MOD 8; INC(x) END; INC(y) END END END Darken; (** fade image **) PROCEDURE Fade* (img: Image; factor: REAL); VAR s, i, j, k, y, x, bit: LONGINT; adr: ADDRESS; clamp: ARRAY 256 OF CHAR; pix: Pixel; BEGIN s := ABS(ENTIER(255*factor + 0.5)); IF s = 0 THEN Clear(img) ELSIF s # 255 THEN i := 256; j := 256*s; REPEAT DEC(i); DEC(j, s); k := j DIV 255; IF k <= 255 THEN clamp[i] := CHR(k) ELSE clamp[i] := 0FFX END UNTIL i = 0; y := 0; WHILE y < img.height DO x := 0; adr := img.adr + y * img.bpr; bit := 0; WHILE x < img.width DO img.fmt.unpack(img.fmt, adr, bit, pix); pix[r] := clamp[ORD(pix[r])]; pix[g] := clamp[ORD(pix[g])]; pix[b] := clamp[ORD(pix[b])]; pix[a] := clamp[ORD(pix[a])]; img.fmt.pack(img.fmt, adr, bit, pix); bit := bit + img.fmt.bpp; INC(adr, bit); bit := bit MOD 8; INC(x) END; INC(y) END END END Fade; (** make image brighter and more transparent; Opaque(I, f) = Darken(Fade(I, f), 1/f) **) PROCEDURE Opaque* (img: Image; factor: REAL); VAR s, i, j, k, y, x, bit: LONGINT; adr: ADDRESS; clamp: ARRAY 256 OF CHAR; pix: Pixel; BEGIN s := ABS(ENTIER(255*factor + 0.5)); IF s = 0 THEN Clear(img) ELSIF s # 255 THEN i := 256; j := 256*s; REPEAT DEC(i); DEC(j, s); k := j DIV 255; IF k <= 255 THEN clamp[i] := CHR(k) ELSE clamp[i] := 0FFX END UNTIL i = 0; y := 0; WHILE y < img.height DO x := 0; adr := img.adr + y * img.bpr; bit := 0; WHILE x < img.width DO img.fmt.unpack(img.fmt, adr, bit, pix); pix[a] := clamp[ORD(pix[a])]; img.fmt.pack(img.fmt, adr, bit, pix); bit := bit + img.fmt.bpp; INC(adr, bit); bit := bit MOD 8; INC(x) END; INC(y) END END END Opaque; (** add components of two (faded) images **) PROCEDURE Add* (i, j, res: Image); VAR y, x, ibit, jbit, rbit, k: LONGINT; iadr, jadr, radr: ADDRESS; ipix, jpix, rpix: Pixel; BEGIN ASSERT((i.width = j.width) & (i.height = j.height) & (i.width <= res.width) & (i.height <= res.height), 100); y := 0; WHILE y < i.height DO x := 0; iadr := i.adr + y * i.bpr; ibit := 0; jadr := j.adr + y * j.bpr; jbit := 0; radr := res.adr + y * res.bpr; rbit := 0; WHILE x < i.width DO i.fmt.unpack(i.fmt, iadr, ibit, ipix); j.fmt.unpack(j.fmt, jadr, jbit, jpix); FOR k := 0 TO 3 DO rpix[k] := Clamp[ORD(ipix[k]) + ORD(jpix[k])] END; res.fmt.pack(res.fmt, radr, rbit, rpix); ibit := ibit + i.fmt.bpp; INC(iadr, ibit); ibit := ibit MOD 8; jbit := jbit + j.fmt.bpp; INC(jadr, jbit); jbit := jbit MOD 8; rbit := rbit + res.fmt.bpp; INC(radr, rbit); rbit := rbit MOD 8; INC(x) END; INC(y) END END Add; (** copy image to another using error diffusion dithering (Floyd-Steinberg) **) PROCEDURE Dither* (src, dst: Image); TYPE error = RECORD r, g, b: LONGINT END; VAR e351: POINTER TO ARRAY OF error; y, x, sb, db, ex, e, e3, e5: LONGINT; sadr, dadr, sa, da: ADDRESS; e7, e51, e1: error; spix, dpix: Pixel; BEGIN ASSERT((src.width <= dst.width) & (src.height <= dst.height), 100); NEW(e351, src.width+2); (* accumulated error for next row *) y := 0; sadr := src.adr; dadr := dst.adr; WHILE y < src.height DO (* scan from left to right *) e7.r := 0; e7.g := 0; e7.b := 0; e51.r := 0; e51.g := 0; e51.b := 0; e1.r := 0; e1.g := 0; e1.b := 0; x := 0; sa := sadr; sb := 0; da := dadr; db := 0; WHILE x < src.width DO ex := x+1; src.fmt.unpack(src.fmt, sa, sb, spix); spix[r] := Clamp[200H + ORD(spix[r]) + e351[ex].r + e7.r]; spix[g] := Clamp[200H + ORD(spix[g]) + e351[ex].g + e7.g]; spix[b] := Clamp[200H + ORD(spix[b]) + e351[ex].b + e7.b]; dst.fmt.pack(dst.fmt, da, db, spix); dst.fmt.unpack(dst.fmt, da, db, dpix); e := ORD(spix[r]) - ORD(dpix[r]); e3 := 3*e DIV 16; e5 := 5*e DIV 16; e7.r := 7*e DIV 16; e351[x].r := e3 + e51.r; e51.r := e5 + e1.r; e1.r := e - e3 - e5 - e7.r; e := ORD(spix[g]) - ORD(dpix[g]); e3 := 3*e DIV 16; e5 := 5*e DIV 16; e7.g := 7*e DIV 16; e351[x].g := e3 + e51.g; e51.g := e5 + e1.g; e1.g := e - e3 - e5 - e7.g; e := ORD(spix[b]) - ORD(dpix[b]); e3 := 3*e DIV 16; e5 := 5*e DIV 16; e7.b := 7*e DIV 16; e351[x].b := e3 + e51.b; e51.b := e5 + e1.b; e1.b := e - e3 - e5 - e7.b; sb := sb + src.fmt.bpp; INC(sa, sb DIV 8); sb := sb MOD 8; db := db + dst.fmt.bpp; INC(da, db DIV 8); db := db MOD 8; x := ex END; INC(y); INC(sadr, src.bpr); INC(dadr, dst.bpr); IF y < src.height THEN (* scan from right to left *) e351[x] := e51; e7.r := 0; e7.g := 0; e7.b := 0; e51.r := 0; e51.g := 0; e51.b := 0; e1.r := 0; e1.g := 0; e1.b := 0; INC(sa, src.bpr); INC(da, dst.bpr); WHILE x > 0 DO ex := x; DEC(x); sb := sb - src.fmt.bpp; INC(sa, sb DIV 8); sb := sb MOD 8; db := db - dst.fmt.bpp; INC(da, db DIV 8); db := db MOD 8; src.fmt.unpack(src.fmt, sa, sb, spix); spix[r] := Clamp[200H + ORD(spix[r]) + e351[ex].r + e7.r]; spix[g] := Clamp[200H + ORD(spix[g]) + e351[ex].g + e7.g]; spix[b] := Clamp[200H + ORD(spix[b]) + e351[ex].b + e7.b]; dst.fmt.pack(dst.fmt, da, db, spix); dst.fmt.unpack(dst.fmt, da, db, dpix); INC(ex); e := ORD(spix[r]) - ORD(dpix[r]); e3 := 3*e DIV 16; e5 := 5*e DIV 16; e7.r := 7*e DIV 16; e351[x].r := e3 + e51.r; e51.r := e5 + e1.r; e1.r := e - e3 - e5 - e7.r; e := ORD(spix[g]) - ORD(dpix[g]); e3 := 3*e DIV 16; e5 := 5*e DIV 16; e7.g := 7*e DIV 16; e351[x].g := e3 + e51.g; e51.g := e5 + e1.g; e1.g := e - e3 - e5 - e7.g; e := ORD(spix[b]) - ORD(dpix[b]); e3 := 3*e DIV 16; e5 := 5*e DIV 16; e7.b := 7*e DIV 16; e351[x].b := e3 + e51.b; e51.b := e5 + e1.b; e1.b := e - e3 - e5 - e7.b END; e351[1] := e51; INC(y); INC(sadr, src.bpr); INC(dadr, dst.bpr) END END END Dither; (**--- File I/O ---**) (** write image to file rider **) PROCEDURE Write* (VAR fr: Streams.Writer; img: Image); VAR m: Image; h, w, len: LONGINT; adr, aa: ADDRESS; buf: ARRAY 256 OF CHAR; SrcCopy:Mode; BEGIN InitMode(SrcCopy, srcCopy); IF ~(img.fmt.code IN {a1..bgra8888,p16}) THEN NEW(m); IF img.fmt.components = {color} THEN Create(m, img.width, img.height, BGR888) ELSIF img.fmt.components = {alpha} THEN Create(m, img.width, img.height, A8) ELSIF img.fmt.components = {index} THEN Create(m, img.width, img.height, D8) ELSE Create(m, img.width, img.height, BGRA8888) END; Copy(img, m, 0, 0, img.width, img.height, 0, 0, SrcCopy); img := m END; fr.RawNum(2); (* version *) fr.RawNum(img.fmt.code); fr.RawNum(img.width); fr.RawNum(img.height); fr.RawNum(ABS(img.bpr)); h := img.height; adr := img.adr; WHILE h > 0 DO w := ABS(img.bpr); aa := adr; WHILE w > 0 DO len := 256; IF len > w THEN len := w END; SYSTEM.MOVE(aa, ADDRESSOF(buf[0]), len); fr.Bytes(buf, 0, len); DEC(w, len); INC(aa, len) END; DEC(h); INC(adr, img.bpr) END; IF img.fmt.code IN {p8,p16} THEN fr.RawNum(img.fmt.pal.used); len := 0; WHILE len < img.fmt.pal.used DO fr.Char(img.fmt.pal.col[len, r]); fr.Char(img.fmt.pal.col[len, g]); fr.Char(img.fmt.pal.col[len, b]); INC(len) END END; fr.Update (* optional *) END Write; (** read image from file rider **) PROCEDURE Read* (VAR fr: Streams.Reader; img: Image); VAR ver, code, w, h, bpr, len, bytesRead: LONGINT; adr, aa: ADDRESS; fmt: Format; buf: ARRAY 256 OF CHAR; used: LONGINT; BEGIN ASSERT(img#NIL,100); fr.RawNum(ver); (* know version 1&2*) ASSERT(ver IN {1,2},101); fr.RawNum(code); CASE code OF | a1: fmt := A1 | a8: fmt := A8 | p8: InitFormat(fmt, p8, 8, 1, {index}, NIL, PackP8, UnpackP8) | d8: fmt := D8 | p16: InitFormat(fmt, p16, 16, 2, {index}, NIL, PackP16, UnpackP16); | bgr555: fmt := BGR555 | bgr565: fmt := BGR565 | bgr466: fmt := BGR466 | bgr888: fmt := BGR888 | bgra8888: fmt := BGRA8888 END; fr.RawNum(w); fr.RawNum(h); Create(img, SHORT(w), SHORT(h), fmt); fr.RawNum(bpr); ASSERT(bpr <= img.bpr); adr := img.adr; WHILE h > 0 DO w := bpr; aa := adr; WHILE w > 0 DO len := 256; IF len > w THEN len := w END; fr.Bytes(buf, 0, len, bytesRead); (* ignore bytesRead *) SYSTEM.MOVE(ADDRESSOF(buf[0]), aa, len); DEC(w, len); INC(aa, len) END; DEC(h); INC(adr, img.bpr) END; IF code IN {p8,p16} THEN fr.RawNum(used); len := 0; NEW(img.fmt.pal); img.fmt.pal.Init(used); WHILE len < used DO fr.Char(img.fmt.pal.col[len, r]); fr.Char(img.fmt.pal.col[len, g]); fr.Char(img.fmt.pal.col[len, b]); img.fmt.pal.col[len, a] := 0FFX; INC(len) END; InitPalette(img.fmt.pal, used, 4) END END Read; (*--- Initialization ---*) PROCEDURE InitBitTables; VAR b, i: LONGINT; BEGIN FOR b := 0 TO 0FFH DO FOR i := 0 TO 7 DO IF ODD(ASH(b, -i)) THEN Bit[b, i] := TRUE; Set[b, i] := CHR(b); Clr[b, i] := CHR(b - ASH(1, i)) ELSE Bit[b, i] := FALSE; Set[b, i] := CHR(b + ASH(1, i)); Clr[b, i] := CHR(b) END END END END InitBitTables; PROCEDURE InitClamp; VAR i: LONGINT; BEGIN FOR i := 0 TO 1FFH DO Clamp[i] := 0X END; FOR i := 0 TO 0FFH DO Clamp[200H+i] := CHR(i) END; FOR i := 300H TO 4FFH DO Clamp[i] := 0FFX END END InitClamp; PROCEDURE ToggleMMX*; BEGIN MMXenabled := ~MMXenabled END ToggleMMX; PROCEDURE ToggleSSE2*; BEGIN SSE2enabled := ~SSE2enabled; KernelLog.String("SSE2 toggled! Is now: "); KernelLog.Boolean(SSE2enabled);KernelLog.Ln; END ToggleSSE2; (** Map a color value to an 8-bit CLUT index. Only used if format = index8. *) PROCEDURE ColorToIndex*(col: LONGINT): LONGINT; BEGIN (* default implementation is not very useful and should be overridden. *) RETURN SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, ASH(col, 7-23)) * {5..7} + SYSTEM.VAL(SET, ASH(col, 4-15)) * {2..4} + SYSTEM.VAL(SET, ASH(col, 1-7)) * {0..1}) END ColorToIndex; (** Map an 8-bit CLUT index to a color value. Only used if format = index8. *) PROCEDURE IndexToColor*(index: LONGINT): LONGINT; BEGIN (* default implementation is not very useful and should be overridden. *) RETURN ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {5..7}), 23-7) + ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {2..4}), 15-4) + ASH(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, index) * {0..1}), 7-1) END IndexToColor; BEGIN (*MMXenabled := 23 IN Machine.features; SSE2enabled := Machine.SSE2Support;*) (* plugin := Displays.registry.Await(""); (* assume only one system-wide D8 display driver *) d8display := plugin(Displays.Display); *) InitFormat(A1, a1, 1, 1, {alpha}, NIL, PackA1, UnpackA1); InitFormat(A8, a8, 8, 1, {alpha}, NIL, PackA8, UnpackA8); InitFormat(D8, d8, 8, 1, {index}, NIL, PackD8, UnpackD8); InitFormat(BGR555, bgr555, 16, 2, {color}, NIL, PackBGR555, UnpackBGR555); InitFormat(BGR565, bgr565, 16, 2, {color}, NIL, PackBGR565, UnpackBGR565); InitFormat(BGR466, bgr466, 16, 2, {color}, NIL, PackBGR466, UnpackBGR466); InitFormat(BGR888, bgr888, 24, 4, {color}, NIL, PackBGR888, UnpackBGR888); InitFormat(BGRA8888, bgra8888, 32, 4, {color, alpha}, NIL, PackBGRA8888, UnpackBGRA8888); PixelFormat := BGRA8888; Zero[0] := 0X; Zero[1] := 0X; Zero[2] := 0X; Zero[3] := 0X; InitBitTables; InitClamp END Raster. (** Remarks 1. Images While many applications wish to handle images of any kind without having to care about details, other applications need low-level access to image interna for maximum effiency. With this in mind, the Images module provides an abstract procedural interface but also discloses low-level information to those clients needing it: * an image references a contiguous block of memory holding pixel data * the point of reference is the address of the pixel in the lower-left corner * pixels are organized in rows (either bottom-up or top-down) * rows can be aligned to an arbitrary number of bytes * the leftmost pixel in a row has the lowest address of all pixels in that row * every pixel uses the same number of bits Memory for images can be automatically allocated by using Create(). Alternatively, an image can be initialized on an existing memory block (Init(), InitBuf()) or even on part of an other image (InitRect()). 2. Pixels A general pixel pix[] contains four components (in range 0X..255X), specifying red, green, blue, and alpha value of the pixel and accessable as pix[r], pix[g], pix[b] and pix[a]. Note that in order to speed up compositing operations, the alpha value is premultiplied into the color components. Example: a red pixel with 50% coverage can be initialized with SetRGBA(pix, 255, 0, 0, 127), after which pix[r]=pix[a]=7FX and pix[g]=pix[b]=0X. Use GetRGBA() to recover the original color and alpha values. 3. Palettes Many bitmap images and Oberon display drivers use some kind of indexed format to store colors, i.e. the value stored in the bitmap serves as an index into an array of colors. A Palette stores up to 256 colors as an array of pixels, making the mapping of an index to the corresponding color straightforward. To speed up the inverse mapping from an RGB triple to an index with PaletteIndex(), additional data is initialized when InitPalette() is called. Use ComputePalette() to compute a palette that best approximates the colors in a given image (e.g. before quantizing it to indexed format). 4. Formats While general pixels accurately describe color and alpha information, they use a lot of memory (32 bits). Most images therefore only store part of that information. A Format record describes how pixels are represented within an image. It contains * the number of bits used per pixel (must be 1, 2, 4, 8, 16, 24 or 32) * the set of components stored in a pixel (color, index and/or alpha) * a palette if the format uses one * procedures for storing (packing) and loading (unpacking) a general pixel The pack and unpack procedures are given an address and a bit number specifying where the pixel is located in memory, with bit numbers ascending from left to right (although a format is free to choose any bit ordering within a pixel). 5. Predefined Formats The following global variables contain formats which are special and have a unique code number identifying them. Besides, most operations have better performance if acting on images using them. * A1 (code a1): one bit alpha, MSB leftmost (corresponds to Oberon display patterns) * A8 (code a8): 8 bit alpha (mainly for anti-aliased character patterns) * - (code p8): 8 bit indexed with custom palette (Oberon pictures, use InitPaletteFormat to initialize) * D8 (code d8): 8 bit indexed with display palette (no palette structure attached) * - (code p16): 16 bit indexed with 16bit Palette. This type is, e.g., often used in medical imaging (DICOM-3 standard) (* PH 2004 *) * BGR555 (code bgr555), BGR565 (code bgr565), BGR466 (code bgr466): 16 bit hi-color * BGR888 (code bgr888): 24 bit true-color * BGRA8888 (code bgra8888), PixelFormat: 32 bit true-color with alpha channel (general pixel format) Procedure DisplayFormat() returns the format that best matches the supplied kind of display transfer format. The returned image format is preferably used for allocating shadow bitmaps. 6. Compositing Most operations require a transfer mode for specifying how source and destination pixels should be combined when alpha information is present. The following compositing operations are supported: * clear: destination becomes black and completely transparent * srcCopy: source completely replaces destination (cf. Display.replace) * dstCopy: no effect * srcOverDst: source replaces destination where source is opaque (cf. Display.paint) * dstOverSrc: destination replaces source where destination is opaque * srcInDst: source where destination is opaque * dstInSrc: destination where source is opaque * srcWithoutDest*: source is cleared where destination is opaque * dstWithoutSrc*: destination is cleared where source is opaque * srcAtopDst*: source replaces destination where destination is opaque * dstAtopSrc*: destination replaces source where source is opaque * srcXorDst*: destination is cleared where both source and destination are opaque (cf. Display.invert) A transfer mode is initialized with a compositing operation and optionally with a color. (The color is used when the source is a pure alpha format which doesn't contain any color of its own.) An initialized mode can be bound to a source and destination format by calling Bind(), by which the mode's transfer procedure is set appropriately. A transfer procedure unpacks pixels from source and destination, blends them according to the compositing operation, and packs the resulting pixel in the destination. Bind() chooses an optimal transfer procedure for the given combination of compositing operation, source format, and destination format. 7. Internalization and Externalization Images can be loaded from file and stored to file using one of many popular image file formats. The Load() and Store() procedures rely on a section 'ImageFormats' in the Aos registry. This section contains a list of file types that are associated with command procedures. When one of these commands is called, it should initialize the global 'LoadProc' and 'StoreProc' variables. These, when called, should read an image from or write an image to the file and set 'done' to TRUE if successful. **)