Vga
UNIT VGA;
(****************************************************************************)
INTERFACE
(****************************************************************************)
(****************************************************************************)
(* Here we go ... procedure definitions. :) *)
(****************************************************************************)
(** This one changes the screenmode to N ***********************************)
PROCEDURE SetMode(N : DWORD);
(** Set a certain color in the VGA palette. ********************************)
PROCEDURE SetColor(N, R, G, B : BYTE);
(** Set a color fade between two given colors. *****************************)
PROCEDURE SetColorFade(N1,N2,R1,G1,B1,R2,G2,B2 : LONGINT);
(** Allocate a new fake screen. Returns offset *****************************)
FUNCTION NewPage : DWORD;
(** Disposes a fake screen. ************************************************)
PROCEDURE DisposePage(PageOFfset : DWORD);
(** The standard pixel procedures. *****************************************)
PROCEDURE PutPixel(WHERE : DWORD; X,Y : DWORD; C : BYTE);
PROCEDURE AddPixel(WHERE : DWORD; X,Y : DWORD; C : BYTE);
FUNCTION GetPixel(WHERE : DWORD; X,Y : DWORD) : BYTE;
(* Line drawing procedures *************************************************)
PROCEDURE Line(WHERE : DWORD; X1, Y1, X2, Y2 : LONGINT; C : BYTE);
PROCEDURE AddLine(WHERE : DWORD; X1, Y1, X2, Y2 : LONGINT; C : BYTE);
PROCEDURE GshadeLine(WHERE : DWORD; X1, Y1, X2, Y2 : LONGINT; C1, C2 : BYTE);
(* Clear a given fake screen ***********************************************)
VAR ClearPage : PROCEDURE(WHERE : DWORD);
(* Fills a screen with a given value. **************************************)
PROCEDURE FillPage(WHERE : DWORD; Color : BYTE);
(* Copies one page to another. *********************************************)
VAR CopyPage : PROCEDURE(From, Too : DWORD);
(* Transparant copy (no color 0) *******************************************)
PROCEDURE CopyPageT(FROM, TOO : DWORD);
(* Loads a 256*256 RAW image. (as source for rotate) ***********************)
PROCEDURE LoadRAW(Where : DWORD; Name : STRING);
(* Plots a pixel on a 256*256 image. ***************************************)
PROCEDURE PutPixel255(Where : DWORD; X, Y, C : BYTE);
(* Grabs a pixel from a 256*256 image. *************************************)
FUNCTION GetPixel255(Where : DWORD; X, Y : BYTE): BYTE;
(* This one rotates a 256*256 source to a 320*200 screen. ******************)
PROCEDURE Rotate(From, Too : DWORD; Rot : DWORD; X, Y, SCALE : LONGINT);
(* Transparant rotate. (No color 0) ****************************************)
PROCEDURE RotateT(From, Too : DWORD; Rot : DWORD; X, Y, SCALE : LONGINT);
(* Transparant Rotate Warp. (WarpX and WarpY should be < 8) ****************)
PROCEDURE RotateTW(From, Too : DWORD; Rot : DWORD; X, Y, SCALE : LONGINT; WARPX, WARPY : WORD);
(* Same as above but high precision warp. warpx and warpy < 2048 ***********)
PROCEDURE RotateTW2(From, Too : DWORD; Rot : DWORD; X, Y, SCALE, WARPX, WARPY : LONGINT);
(* Copying pages (320*200) whilst smudging them ****************************)
VAR CopyPageSmudge:PROCEDURE(FROM,TOO : DWORD);
(* Copy smudge, check out to know difference :) ***************************)
PROCEDURE CopyPageSmudge2(FROM, TOO : DWORD);
(* Average two pages. Too := (From1+From2)/2 *******************************)
VAR MixPages :PROCEDURE(From1,From2,Too : DWORD);
(* Saturate two pages. too := (From1+From2)<255 ****************************)
VAR MixPages2 :PROCEDURE(From1,From2,Too : DWORD);
(* Alpha blend two pages. amount = 255 -> 100% from1 ***********************)
VAR MixPages3 :PROCEDURE(From1,From2,Too : DWORD; Amount : BYTE);
(* Bumpmapping with mutliple lightsources **********************************)
PROCEDURE BumpMap(FROM, TOO, LIGHT : DWORD; LX, LY : WORD);
(* Bumpmapping with one lightsource. ***************************************)
PROCEDURE BumpMap2(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER);
(* Bumpmapping with one lightsource. (no zeros) ****************************)
PROCEDURE BumpMap2t(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER);
(* Bumpmapping with one lightsource. height+slope **************************)
PROCEDURE BumpMap3(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER);
(* Bumpmapping with one lightsource. height+slope+transparent **************)
PROCEDURE BumpMap3t(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER);
(* Scale a 320*200 to 256*256 (to use as rotatesource) *********************)
PROCEDURE Scale320to256(FROM, TOO : DWORD);
PROCEDURE Scale256to320(FROM, TOO : DWORD);
(* Apply distort relocation maps to 256*256 source giving 320*200 **********)
PROCEDURE Relocate(From, Too, Distort1, Distort2, D1Ofs, D2Ofs : LONGINT);
(* Relocate not doing color 0. *********************************************)
PROCEDURE RelocateT(From, Too, Distort1, Distort2, D1Ofs, D2Ofs : LONGINT);
(* This one does a fire effect. ********************************************)
PROCEDURE DoFire(From, Too, Flame : DWORD);
(* Use this one to init the standard light for the bumpmap. ****************)
PROCEDURE InitBump(Light : DWORD);
PROCEDURE InitBumpSmall(Light : DWORD);
(* This one does a ripple. *************************************************)
VAR Ripple : PROCEDURE(VAR Page1, Page2 : DWORD);
(* This one does the displacement effect. **********************************)
PROCEDURE DisPlace(From, Too, Disp : DWORD);
(* Use these to produce some standard distort maps. ************************)
PROCEDURE InitTunnel(Distort1, Distort2 : DWORD);
PROCEDURE InitTunnel2(Distort1, Distort2 : DWORD);
PROCEDURE InitTunnelFast(Distort1, Distort2 : DWORD);
PROCEDURE InitFlashke(Distort1, Distort2 : DWORD);
PROCEDURE InitSpiral(Distort1, Distort2 : DWORD);
(****************************************************************************)
IMPLEMENTATION
(****************************************************************************)
(* MMX instructions don't take direct operands ... that would btw mean an *)
(* opcode with 8 bytes extra :) ... so ... here's some mask I use to mask *)
(* out the upper bit of every byte since mmx doesn't have PSRLB !! .. *)
(****************************************************************************)
CONST SomeBitsOutMask : ARRAY[0..7] OF CHAR = ('','','','','','','','');
Mask512W : ARRAY[0..3] OF WORD = (512,512,512,512);
Mask128W : ARRAY[0..3] OF WORD = (128,128,128,128);
(****************************************************************************)
(* This procedure sets the screenmode to a desired mode number. *)
(****************************************************************************)
PROCEDURE SetMode(N : DWORD); ASSEMBLER; ASM
MOV EAX, [N] (* Get modenr. *)
INT $10 (* Call video interrupt. *)
END;
(****************************************************************************)
(* This one plots a pixel on a 320*200 screen. *)
(****************************************************************************)
PROCEDURE PutPixel(WHERE : DWORD; (* Offset of destination screen. *)
X,Y : DWORD; (* Positions in destination. *)
C : BYTE); (* Color of pixel to plot. *)
ASSEMBLER; ASM
(* What we do here : MEM[Where + X*320 + Y] := C. Just a lot faster :) *)
MOV EAX, [X] (* Get the line. *)
MOV EDI, [Y] (* Get the column number. *)
SHL EAX, 6 (* Line*64 *)
ADD EDI, [WHERE] (* Add source pointer to column. *)
MOV BL, [C] (* Get Color. *)
LEA EAX, [EAX+4*EAX] (* Eax := (Line*64) + 4*(line*64) = Line*320 *)
MOV [EDI+EAX], BL (* Put the color in its place. *)
END;
(****************************************************************************)
(* This one adds a pixel to the value current on screen *)
(****************************************************************************)
PROCEDURE AddPixel(WHERE : DWORD; (* Offset of destination. *)
X,Y : DWORD; (* Positions of destination pixel. *)
C : BYTE); (* Amount to add to pixel. *)
ASSEMBLER; ASM
(* What we do here : MEM[Where + X*320 + Y] +:= C. Just a lot faster :) *)
MOV EAX, [X] (* Get the line. *)
MOV EDI, [Y] (* Get the column number. *)
SHL EAX, 6 (* Line*64 *)
ADD EDI, [WHERE] (* Add source pointer to column. *)
MOV BL, [C] (* Get Color. *)
LEA EAX, [EAX+4*EAX] (* Eax := (Line*64) + 4*(line*64) = Line*320 *)
ADD [EDI+EAX], BL (* Add the color to the pixel there. *)
END;
(****************************************************************************)
(* This one grabs a pixel from a given screen. *)
(****************************************************************************)
FUNCTION GetPixel(WHERE : DWORD; (* Offset of page to grab pixel from. *)
X, Y : DWORD) (* Positions of pixel. *)
: BYTE; (* The color returned. *)
ASSEMBLER; ASM
MOV EDX, [X] (* Get line *)
MOV EDI, [Y] (* Get column. *)
SHL EDX, 6 (* EDX = Line*64 *)
ADD EDI, [WHERE] (* Add offset of source to column. *)
LEA EDX, [EDX+4*EDX] (* EDX = (Line*64)+4*(Line*64) = Line*320 *)
MOV AL, [EDI+EDX] (* Grab pixel. *)
END;
(****************************************************************************)
(* This one draws a line on screen in color C *)
(****************************************************************************)
PROCEDURE Line(WHERE : DWORD; (* Offset of destination. *)
X1, Y1, (* Positions of begin pixel. *)
X2, Y2 : LONGINT; (* Positions of ending pixel. *)
C : BYTE); (* Color to plot line in. *)
VAR CX, CY : LONGINT; (* Current X and Current Y. 16:16 fixed point. *)
DX, DY : LONGINT; (* Delta X and Delta Y. 16:16 fp. *)
L1, L2 : LONGINT; (* Length(L1) and Loop(L2). Temporary variables. *)
BEGIN
(** Step 0 : Figure out length of line. ***********************************)
IF ABS(X2-X1) > ABS(Y2-Y1) THEN L1 := ABS(X2-X1)
ELSE L1 := ABS(Y2-Y1);
(** Step 1 : Avoid lines that are of 0 length. ****************************)
IF L1 = 0 THEN INC(L1);
(** Step 2 : Calculate starting positions. ********************************)
CX := X1 SHL 16;
CY := Y1 SHL 16;
(** Step 3 : Calculate delta's. What do we need to add every pixel ? ******)
DX := ((X2-X1) SHL 16) DIV L1;
DY := ((Y2-Y1) SHL 16) DIV L1;
(** Step 4 : Loop for as many pixels as there are in the line. ************)
FOR L2 := 0 TO L1 DO BEGIN
(** Step 4a : Plot the current pixel. ***********************************)
PutPixel(Where, CX SHR 16, CY SHR 16, C);
(** Step 4b : Update the positions. *************************************)
CX +:= DX;
CY +:= DY;
END;
END;
(****************************************************************************)
(* Same thing, but this time adds a line. *)
(****************************************************************************)
PROCEDURE AddLine(WHERE : DWORD; (* Offset of destination screen. *)
X1, Y1, (* Beginpixel positions *)
X2, Y2 : LONGINT;(* Endpixel positions. *)
C : BYTE); (* Amount to add. *)
VAR CX, CY : LONGINT; (* Current X and Current Y. 16:16 fixed point. *)
DX, DY : LONGINT; (* Delta X and Delta Y. 16:16 fp. *)
L1, L2 : LONGINT; (* Length(L1) and Loop(L2). Temporary variables. *)
BEGIN
(** Step 0 : Figure out length of line. ***********************************)
IF ABS(X2-X1) > ABS(Y2-Y1) THEN L1 := ABS(X2-X1)
ELSE L1 := ABS(Y2-Y1);
(** Step 1 : Avoid lines that are of 0 length. ****************************)
IF L1 = 0 THEN INC(L1);
(** Step 2 : Calculate starting positions. ********************************)
CX := X1 SHL 16;
CY := Y1 SHL 16;
(** Step 3 : Calculate delta's. What do we need to add every pixel ? ******)
DX := ((X2-X1) SHL 16) DIV L1;
DY := ((Y2-Y1) SHL 16) DIV L1;
(** Step 4 : Loop for as many pixels as there are in the line. ************)
FOR L2 := 0 TO L1 DO BEGIN
(** Step 4a : Add to the current pixel. *********************************)
AddPixel(Where, CX SHR 16, CY SHR 16, C);
(** Step 4b : Update the positions. *************************************)
CX +:= DX;
CY +:= DY;
END;
END;
(****************************************************************************)
(* This procedure draws a shaded line on where. *)
(****************************************************************************)
PROCEDURE GshadeLine(WHERE : DWORD; (* Offset of destination. *)
X1, Y1, (* Positions of begin pixel. *)
X2, Y2 : LONGINT; (* Positions of ending pixel. *)
C1, C2 : BYTE); (* Color to plot line in. *)
VAR CX, CY, CC : LONGINT;
DX, DY, DC : LONGINT;
L1, L2 : LONGINT;
BEGIN
(** Step 0 : Figure out length of line. ***********************************)
IF ABS(X2-X1) > ABS(Y2-Y1) THEN L1 := ABS(X2-X1)
ELSE L1 := ABS(Y2-Y1);
(** Step 1 : Avoid lines that are of 0 length. ****************************)
IF L1 = 0 THEN INC(L1);
(** Step 2 : Calculate starting positions. ********************************)
CX := X1 SHL 16;
CY := Y1 SHL 16;
CC := C1 SHL 16;
(** Step 3 : Calculate delta's. What do we need to add every pixel ? ******)
DX := ((X2-X1) SHL 16) DIV L1;
DY := ((Y2-Y1) SHL 16) DIV L1;
DC := ((C2-C1) SHL 16) DIV L1;
(** Step 4 : Loop for as many pixels as there are in the line. ************)
FOR L2 := 0 TO L1 DO BEGIN
(** Step 4a : Plot the current pixel. ***********************************)
PutPixel(Where, CX SHR 16, CY SHR 16, CC SHR 16);
(** Step 4b : Update the positions. *************************************)
CX +:= DX;
CY +:= DY;
CC +:= DC;
END;
END;
(****************************************************************************)
(* This procedure sets one palette entry of the VGA to specified colors. *)
(****************************************************************************)
PROCEDURE SetColor(N, (* Nr of color to set. *)
R, G, B : BYTE); (* Red green and blue component. *)
(* Color components are expected to be 0-255 !!!!!!!!!!!!!!!!!!!!!!!!!!! *)
ASSEMBLER; ASM
MOV DX, $3C7 (* Port $3c7 = Set palette write index. *)
MOV AL, [N] (* Get the colorNr *)
OUT DX, AL (* Send it to the VGA card. *)
ADD DX, 2 (* Port $3c9 = Palette data Write/read *)
MOV AL, [R] (* Get the red component. *)
SHR AL, 2 (* Rescale from 0-255 to standard vga 0-63 *)
OUT DX, AL (* Send it to the VGA card. *)
MOV AL, [G] (* Get the green component. *)
SHR AL, 2 (* Rescale it. *)
OUT DX, AL (* Send it. *)
MOV AL, [B] (* Get the blue component. *)
SHR AL, 2 (* Rescale it. *)
OUT DX, AL (* send it. *)
END;
(****************************************************************************)
(* This procedure creates a shade of colors between N1 and N2 *)
(****************************************************************************)
PROCEDURE SetColorFade(N1, (* Starting color nr. *)
N2, (* Ending color nr. (N1 < N2) *)
R1,G1,B1, (* Starting color components. *)
R2,G2,B2 : LONGINT);(* Ending color components. *)
VAR CR, CG, CB : LONGINT; (* Current red, green and blue values. 16:16 *)
DR, DG, DB : LONGINT; (* Delta red, green and blue. 16:16 *)
Counter : BYTE; (* a counter. To count shit :) *)
BEGIN
(** Step 1 : Calculate delta values. **************************************)
DR := ( (R2-R1) SHL 16) DIV (N2-N1);
DG := ( (G2-G1) SHL 16) DIV (N2-N1);
DB := ( (B2-B1) SHL 16) DIV (N2-N1);
(** Step 2 : Get starting values. *****************************************)
CR := R1 SHL 16;
CG := G1 SHL 16;
CB := B1 SHL 16;
(** Step 3 : Do the shit :) ***********************************************)
FOR Counter := N1 TO N2-1 DO BEGIN (* Repeat for all colors. *)
PORT[$3c7] := Counter; (* Send color nr. *)
PORT[$3c9] := CR SHR 18; CR+:=DR;(* Send current red and update. *)
PORT[$3c9] := CG SHR 18; CG+:=DG;(* Send current green and update. *)
PORT[$3c9] := CB SHR 18; CB+:=DB;(* Send current blue and update. *)
END;
END;
(****************************************************************************)
(* This one fills the screen with a certain color. *)
(****************************************************************************)
PROCEDURE FillPage(WHERE : DWORD; Color : BYTE); ASSEMBLER; ASM
MOV EDI, [WHERE]
MOV AL, [COLOR]
MOV AH, AL
MOV BX, AX
SHL EAX, 16
MOV AX, BX
MOV ECX, 16384
@LOOP:
MOV [EDI], EAX
ADD EDI, 4
DEC ECX
JNZ @LOOP
END;
(****************************************************************************)
(* This one fills the screen completely with 0. mmx version. *)
(****************************************************************************)
PROCEDURE ClearPage_mmx(Where : DWORD); ASSEMBLER; ASM
MOV EDI, [Where] (* Get destination pointer. *)
PSLLW mm0, 32 (* Clear mm0 register. *)
MOVQ mm1, mm0 (* Clear mm1 too. *)
MOV ECX, 4096 (* Repeat 4096 times. (4096*16=65536) *)
@LOOP:
MOVQ [EDI], mm0 (* Send mm0. *)
MOVQ [EDI+8], mm1 (* Send mm1. *)
ADD EDI, 16 (* Voila, 16 bytes done. *)
DEC ECX (* Decrement counter. *)
JNZ @LOOP (* Jump when counter is not zero. *)
EMMS (* Exit multimediastate. *)
END;
(****************************************************************************)
(* This one fills the screen completely with zeroes, x86 version *)
(****************************************************************************)
PROCEDURE ClearPage_x86(Where : DWORD); ASSEMBLER; ASM
MOV EDI, [Where] (* Get destination pointer. *)
XOR EAX, EAX (* Clear EAX. *)
MOV ECX, 8192 (* Repeat 8192 times. (8192*8=65536) *)
@LOOP:
MOV [EDI], EAX (* Send EAX. *)
MOV [EDI+4], EAX (* Send EAX one dword further. *)
ADD EDI, 8 (* Increase destination pointer with 8. *)
DEC ECX (* Decrease pixelcounter. *)
JNZ @LOOP (* Jump when counter is not zero. *)
END;
(****************************************************************************)
(* This one copies one page to another, mmx version *)
(****************************************************************************)
PROCEDURE CopyPage_mmx(From, (* Offset of source page. *)
Too : DWORD); (* Offset of destination page. *)
ASSEMBLER; ASM
MOV EDI, [TOO] (* Get destination pointer. *)
MOV ECX, 4096 (* Set counter. (4096*16=65536) *)
MOV ESI, [FROM] (* Get source pointer *)
@LOOP:
MOVQ mm0, [ESI] (* Read First 8 bytes into mm0 *)
MOVQ mm1, [ESI+8] (* Read next 8 bytes into mm1 *)
ADD ESI, 16 (* Increase sourcepointer with 16 *)
MOVQ [EDI], mm0 (* Store first 8 bytes. *)
MOVQ [EDI+8], mm1 (* Store next 8 bytes. *)
ADD EDI, 16 (* Increase destination pointer with 16 *)
DEC ECX (* Decrease loop counter. *)
JNZ @LOOP (* Jump unless counter = 0 *)
EMMS (* Exit multimediastate *)
END;
(****************************************************************************)
(* This one copies one page to another, x86 version *)
(****************************************************************************)
PROCEDURE CopyPage_X86(From, (* Offset of source page. *)
Too : DWORD); (* Offset of destination page. *)
ASSEMBLER; ASM
MOV EDI, [TOO] (* Get destination pointer. *)
MOV ECX, 8192 (* Set loop count. *)
MOV ESI, [FROM] (* Get source pointer. *)
@LOOP:
MOV EAX, [ESI] (* Read first four bytes. *)
MOV EBX, [ESI+4] (* Read next four bytes. *)
ADD ESI, 8 (* Update sourcep pointer. *)
MOV [EDI], EAX (* Store first four bytes. *)
MOV [EDI+4], EBX (* Store next four bytes. *)
ADD EDI, 8 (* Update destination pointer. *)
DEC ECX (* Decrease loop counter. *)
JNZ @LOOP (* Jump unless counter is zero. *)
END;
(****************************************************************************)
(* This one copies one page to another, not copying color 0, x86 version *)
(****************************************************************************)
PROCEDURE CopyPageT(From, Too : DWORD); ASSEMBLER; ASM
MOV EDI, [Too] (* Get destination pointer. *)
MOV ECX, 65536 (* Set pixel count. *)
MOV ESI, [From] (* Get source pointer. *)
@LOOP:
MOV AL, [ESI] (* Get source pixel. *)
CMP AL, 0 (* Compare to 0 *)
JZ @SKIP (* If 0 then skip plotting. *)
MOV [EDI], AL (* Plot pixel. *)
@SKIP:
INC ESI (* Increase source pointer. *)
INC EDI (* Increase destination pointer. *)
DEC ECX (* Decrease loop counter. *)
JNZ @LOOP (* Jump unless loopcounter = 0 *)
END;
(****************************************************************************)
(* This one smudges one page to another. x86 version *)
(****************************************************************************)
PROCEDURE CopyPageSmudge_x86(From, Too : DWORD); ASSEMBLER; ASM
MOV EDI, [TOO] (* Get destination pointer. *)
MOV ECX, 63360 (* Set pixel count (skip top/bottom) *)
MOV ESI, [FROM] (* Get source addres *)
ADD EDI, 320 (* Skip first line on destination. *)
ADD ESI, 320 (* And skip first line on source. *)
@LOOP:
MOVZX EAX, BYTE PTR [ESI-320] (* Get pixel above. *)
MOVZX EBX, BYTE PTR [ESI-1] (* Get pixel left. *)
MOVZX EDX, BYTE PTR [ESI+1] (* Get pixel right. *)
ADD EAX, EBX
MOVZX EBX, BYTE PTR [ESI+320] (* Get pixel below. *)
ADD EAX, EDX
ADD EAX, EBX (* Count four pixels together. *)
SHR EAX, 2 (* Divide by four. *)
MOV [EDI], AL (* And store the result. *)
INC ESI (* Increase source pointer. *)
INC EDI (* Increase destination pointer. *)
DEC ECX (* Decrease loop count. *)
JNZ @LOOP (* Loop until 0 *)
END;
(****************************************************************************)
(* This one smudges one page to another, mmx version *)
(****************************************************************************)
PROCEDURE CopyPageSmudge_mmx(From, Too : DWORD); ASSEMBLER; ASM
MOV EDI, [TOO] (* Get destination page. *)
MOV ECX, 7920 (* Loop count. (7920*8=65536-640) *)
MOV ESI, [FROM] (* Get source page. *)
ADD EDI, 320 (* Skip first line. *)
ADD ESI, 320 (* Also on source. *)
PSLLQ mm7, 64 (* Clear mm7 *)
@LOOP:
MOVQ mm0, QWORD PTR [ESI-320] (* Get 8 pixels above. *)
MOVQ mm1, QWORD PTR [ESI-1] (* Get 8 pixels left. *)
MOVQ mm2, mm0 (* Copy above pixels. *)
MOVQ mm3, mm1 (* Copy left pixels. *)
PUNPCKHBW mm0, mm7 (* Unpack 4 above pxls in mm0 to words*)
PUNPCKHBW mm1, mm7 (* Unpack 4 left pxls in mm1 to words *)
PUNPCKLBW mm2, mm7 (* Unpack low above pxls to words. *)
PUNPCKLBW mm3, mm7 (* Unpack low left pxls to words. *)
PADDUSW mm0, mm1 (* Add above and left pixels. *)
PADDUSW mm2, mm3 (* Add 4 next above and left pixels. *)
MOVQ mm4, QWORD PTR [ESI+1] (* Get 8 right pixels. *)
MOVQ mm5, QWORD PTR [ESI+320] (* Get 8 below pixels. *)
MOVQ mm1, mm4 (* Copy 8 right pixels. *)
MOVQ mm3, mm5 (* Copy 8 below pixels. *)
PUNPCKHBW mm4, mm7 (* Unpack high right pxls to words. *)
PUNPCKHBW mm5, mm7 (* Unpack high below pxls to words. *)
PUNPCKLBW mm1, mm7 (* Unpack low right pxls to words. *)
PUNPCKLBW mm3, mm7 (* Unpack low below pxls to words. *)
PADDUSW mm4, mm5 (* Add right and below pixels. *)
PADDUSW mm1, mm3 (* Add other right and below pixels. *)
PADDUSW mm0, mm4 (* Now add 4st 4 pixels all together *)
PADDUSW mm2, mm1 (* Same for next four. *)
PSRLW mm0, 2 (* SHR MM0, 2. Divide by 4 *)
PSRLW mm2, 2 (* SHR MM2, 2. Divide by 4 *)
PACKUSWB mm2, mm0 (* Pack words in mm2 and mm0 to bytes *)
MOVQ [EDI], mm2 (* Store 8 pixels on destination. *)
ADD ESI, 8 (* Increase source pointer. *)
ADD EDI, 8 (* Increase destination pointer. *)
DEC ECX (* Decrease loop counter. *)
JNZ @LOOP (* Jump until ECX = 0 *)
EMMS (* Exit multimedia state. *)
END;
(****************************************************************************)
(* This one does a different kind of smudge ... rather fun :) *)
(****************************************************************************)
PROCEDURE CopyPageSmudge2(From, Too : DWORD); ASSEMBLER; ASM
MOV EDI, [TOO] (* Get destination addres *)
MOV ECX, 63360 (* Set loop count = 64000-2*320 *)
MOV ESI, [FROM] (* Get source. *)
ADD EDI, 320 (* Skip first line on destination. *)
ADD ESI, 320 (* Skip first line on source. *)
@LOOP:
MOVZX EAX, BYTE PTR [ESI-320] (* Get pixel above. *)
MOVZX EBX, BYTE PTR [ESI-1] (* Get pixel left. *)
MOVZX EDX, BYTE PTR [ESI+1] (* Get pixel right. *)
ADD EAX, EBX (* EAX := Above + left *)
MOVZX EBX, BYTE PTR [ESI+320] (* Get pixel under. *)
ADD EAX, EDX (* EAX +:= right. *)
MOVZX EDX, BYTE PTR [ESI-321] (* Get pixel aboveleft. *)
ADD EAX, EBX (* EAX +:= under. *)
MOVZX EBX, BYTE PTR [ESI-319] (* Get pixel aboveright. *)
ADD EDX, EBX (* EDX := Aboveleft+Aboveright. *)
MOVZX EBX, BYTE PTR [ESI+319] (* Get pixel belowleft. *)
ADD EDX, EBX (* EDX +:= belowleft. *)
MOVZX EBX, BYTE PTR [ESI+321] (* Get pixel belowright. *)
ADD EDX, EBX (* EDX +:= belowright. *)
MOVZX EBX, BYTE PTR [ESI] (* Get pixel itself. *)
LEA EBX, [EBX+2*EBX] (* Multiply pixel with 3 *)
ADD EDX, EBX (* EDX +:= 3*pixel *)
SHR EDX, 1 (* EDX /:= 2; *)
ADD EAX, EDX (* Add all together. *)
SHR EAX, 3 (* Divide by 8 *)
MOV [EDI], AL (* And put on source. *)
INC ESI (* Increase source pointer. *)
INC EDI (* Increase destination pointer. *)
DEC ECX (* Decrease loop counter. *)
JNZ @LOOP (* Jump until 0 *)
END;
(****************************************************************************)
(* This one does a putpixel on a 256*256 screen ... (src for rotate). *)
(****************************************************************************)
PROCEDURE PutPixel255(Where : DWORD; X, Y, C : BYTE); ASSEMBLER; ASM
XOR EAX, EAX (* Empty EAX *)
MOV EDI, [WHERE] (* Get source addres *)
MOV AL, [Y] (* Get column number. *)
MOV BL, [C] (* Get color. *)
MOV AH, [X] (* Get line number. *)
MOV [EDI+EAX], BL (* Store color at correct place. *)
END;
(****************************************************************************)
(* This one grabs a pixel from a 256*256 screen. *)
(****************************************************************************)
FUNCTION GetPixel255(Where : DWORD; X, Y : BYTE) : BYTE; ASSEMBLER; ASM
XOR EBX, EBX (* Empty EBX. *)
MOV EDI, [WHERE] (* Get source addres *)
MOV BH, [X] (* Get line. *)
MOV BL, [Y] (* Get column. *)
MOV AL, [EDI+EBX] (* Get pixel and return it. *)
END;
(****************************************************************************)
(* This one rotates a 256*256 source image to the screen, tiling it ... *)
(****************************************************************************)
PROCEDURE Rotate(From, Too : DWORD; (* Source(256) and Destination. *)
Rot : DWORD; (* 0 < ROT < 4096 *)
X, Y, (* pixelmappedtocenter/256*65535 *)
SCALE : LONGINT); (* Sort of scale. *)
VAR ANGLE : REAL; (* Temporary real variable. Yuck *)
Ddx,Ddy,D2x,D2y : INTEGER; (* Delta's to move over source. *)
i,j : INTEGER; (* Starting coordinates in the bitmap.*)
BEGIN
(* Calculate angle. ******************************************************)
angle := rot * 2 * 3.14159236/ 2048;
(* Moving delta's. 8:8 fixed point ***************************************)
Ddx:=trunc(((-Cos(angle)*256)) * SCALE) SHR 8;
Ddy:=trunc(((Sin(Angle)*256)) * Scale) SHR 8;
D2x:=trunc(((-Cos(angle+3.14159265/2) * 341))*SCALE) SHR 8;
D2y:=trunc(((Sin(angle+3.14159265/2) * 341))*SCALE) SHR 8;
(* Starting coordinates in the source bitmap. *)
i:=X-Ddx*(160)-D2x*(100);
j:=y-Ddy*(160)-D2y*(100);
(* Do the shit :) *)
ASM
MOV ESI, [FROM] (* Get source addres. *)
MOV EDI, [TOO] (* Get destination addres. *)
MOV ECX, 200 (* The line count. *)
@LineLoop:
PUSH ECX (* Store the linecount on the stack. *)
MOV BX, [I] (* Get starting coordinates for this line. *)
MOV DX, [J] (* Store them in the BX and DX registers. *)
MOV ECX, 320 (* Set the pixel count. *)
XOR EAX, EAX (* Clear the EAX register. *)
@PixelLoop:
PUSH ECX (* Store the pixelcount on the stack. *)
MOV AH, BH (* Get current linenr. *)
MOV AL, DH (* Get current column. *)
MOV CL, [ESI+EAX] (* Get source pixel. *)
MOV [EDI], CL (* Store pixel on destination. *)
INC EDI (* Increase destination pointer. *)
ADD BX, [DDX] (* Update source positions for next pixel. *)
ADD DX, [DDY] (* Update source positions for next pixel. *)
POP ECX (* Get pixelcount from stack. *)
DEC ECX (* Decrease pixelcount. *)
JNZ @PixelLoop (* Jump until pixelcount is 0 *)
MOV AX, [D2X] (* Get line update vars. *)
MOV CX, [D2Y] (* idem dito. *)
ADD [I], AX (* Add these to the starting coordinates of *)
ADD [J], CX (* the beginning of the line = move to next *)
POP ECX (* Get linecount. *)
DEC ECX (* Decrease linecount. *)
JNZ @LineLoop (* Jump until linecount = 0 *)
END; (**)
END;
(****************************************************************************)
(* This one rotates a 256*256 source image to the screen and skips color 0 *)
(****************************************************************************)
PROCEDURE RotateT(From, Too : DWORD; (* Source(256) and Destination. *)
Rot : DWORD; (* 0 < ROT < 4096 *)
X, Y, (* pixelmappedtocenter/256*65535 *)
SCALE : LONGINT); (* Sort of scale. *)
VAR ANGLE : REAL; (* Temporary real variable. Yuck *)
Ddx,Ddy,D2x,D2y : INTEGER; (* Delta's to move over source. *)
i,j : INTEGER; (* Starting coordinates in the bitmap.*)
BEGIN
(* Calculate angle. ******************************************************)
angle := rot * 2 * 3.14159236/ 2048;
(* Moving delta's. 8:8 fixed point ***************************************)
Ddx:=trunc(((-Cos(angle)*256)) * SCALE) SHR 8;
Ddy:=trunc(((Sin(Angle)*256)) * Scale) SHR 8;
D2x:=trunc(((-Cos(angle+3.14159265/2) * 341))*SCALE) SHR 8;
D2y:=trunc(((Sin(angle+3.14159265/2) * 341))*SCALE) SHR 8;
(* Starting coordinates in the source bitmap. *)
i:=X-Ddx*(160)-D2x*(100);
j:=y-Ddy*(160)-D2y*(100);
(* Do the shit :) *)
ASM
MOV ESI, [FROM] (* Get source addres. *)
MOV EDI, [TOO] (* Get destination addres. *)
MOV ECX, 200 (* The line count. *)
@LineLoop:
PUSH ECX (* Store the linecount on the stack. *)
MOV BX, [I] (* Get starting coordinates for this line. *)
MOV DX, [J] (* Store them in the BX and DX registers. *)
MOV ECX, 320 (* Set the pixel count. *)
XOR EAX, EAX (* Clear the EAX register. *)
@PixelLoop:
PUSH ECX (* Store the pixelcount on the stack. *)
MOV AH, BH (* Get current linenr. *)
MOV AL, DH (* Get current column. *)
MOV CL, [ESI+EAX] (* Get source pixel. *)
CMP CL, 0 (* Check if source pixel is 0 *)
JZ @Skip (* If it is 0 then skip the plotting. *)
MOV [EDI], CL (* Store pixel on destination. *)
@Skip:
INC EDI (* Increase destination pointer. *)
ADD BX, [DDX] (* Update source positions for next pixel. *)
ADD DX, [DDY] (* Update source positions for next pixel. *)
POP ECX (* Get pixelcount from stack. *)
DEC ECX (* Decrease pixelcount. *)
JNZ @PixelLoop (* Jump until pixelcount is 0 *)
MOV AX, [D2X] (* Get line update vars. *)
MOV CX, [D2Y] (* idem dito. *)
ADD [I], AX (* Add these to the starting coordinates of *)
ADD [J], CX (* the beginning of the line = move to next *)
POP ECX (* Get linecount. *)
DEC ECX (* Decrease linecount. *)
JNZ @LineLoop (* Jump until linecount = 0 *)
END; (**)
END;
(****************************************************************************)
(* This one rotates a 256*256 source image to the screen and skips color 0 *)
(* and warps the image. *)
(****************************************************************************)
PROCEDURE RotateTW(From, Too : DWORD; Rot : DWORD; X, Y, SCALE : LONGINT; WARPX, WARPY : WORD);
VAR ANGLE : REAL; (* Yuck :) *)
Ddx,Ddy,D2x,D2y : INTEGER;
i,j : INTEGER;
WARPDDY : INTEGER;
BEGIN
(* Sin and cos only 4 for every screen ... aint gonna waist a look- *)
(* up table on that ! *)
angle := rot * 2*3.14159236 / 2048;
(* Fixed Point Verplaatsingsvectoren geroteerd en gewogen(scale) *)
Ddx:=trunc(((-Cos(angle)*256)) * SCALE) SHR 8;
Ddy:=trunc(((Sin(Angle)*256)) * Scale) SHR 8;
D2x:=trunc(((-Cos(angle+3.14159265/2) * 341))*SCALE) SHR 8;
D2y:=trunc(((Sin(angle+3.14159265/2) * 341))*SCALE) SHR 8;
(* Starting coordinates in the source bitmap. *)
i:=X-Ddx*(160)-D2x*(100);
j:=y-Ddy*(160)-D2y*(100);
(* Do the shit :) *)
ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV ECX, 200
@LineLoop:
PUSH ECX
MOV BX, [I]
MOV DX, [J]
MOV ECX, 320
MOV AX, [DDY]
MOV [WarpDDY], AX
XOR EAX, EAX
@PixelLoop:
MOV AH, BH
MOV AL, DH
SHL EBX, 8
MOV BL, [ESI+EAX]
CMP BL, 0
JZ @SKIP
MOV [EDI], BL
@SKIP:
INC EDI
SHR EBX, 8
MOV AX, [WarpDDY]
ADD DX, AX
ADD AX, [WarpY]
MOV [WarpDDY], AX
ADD BX, [DDX]
DEC ECX
JNZ @PixelLoop
MOV AX, [D2X]
MOV CX, [D2Y]
ADD [I], AX
ADD [J], CX
POP ECX
ADD AX, [WARPX]
MOV [D2X], AX
DEC ECX
JNZ @LineLoop
END; (**)
END;
(****************************************************************************)
(* This one rotates a 256*256 source image to the screen and skips color 0 *)
(* and warps the image. (Slower but high precision warping.) *)
(****************************************************************************)
PROCEDURE RotateTW2(From, Too : DWORD; Rot : DWORD; X, Y, SCALE, WARPX, WARPY : LONGINT);
VAR ANGLE : REAL; (* Yuck :) *)
Ddx,Ddy,D2x,D2y : LONGINT;
i,j : LONGINT;
WARPDDY : LONGINT;
BEGIN
(* Sin and cos only 4 for every screen ... aint gonna waist a look- *)
(* up table on that ! *)
angle := rot * 2*3.14159236 / 2048;
(* Fixed Point Verplaatsingsvectoren geroteerd en gewogen(scale) *)
Ddx:=trunc(((-Cos(angle)*65536)) * SCALE) SHR 8;
Ddy:=trunc(((Sin(Angle)*65536)) * Scale) SHR 8;
D2x:=trunc(((-Cos(angle+3.14159265/2) * 87296))*SCALE) SHR 8;
D2y:=trunc(((Sin(angle+3.14159265/2) * 87296))*SCALE) SHR 8;
(* Starting coordinates in the source bitmap. *)
i:=(X SHL 8)-(Ddx)*(160)-(D2x + 100 * WarpX)*(100);
j:=(y SHL 8)-(Ddy + 160*WarpY)*(160)-(D2y)*(100);
(* Do the shit :) *)
ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV ECX, 200
@LineLoop:
PUSH ECX
MOV EBX, [I]
MOV EDX, [J]
MOV ECX, 320
MOV EAX, [DDY]
MOV [WarpDDY], EAX
XOR EAX, EAX
@PixelLoop:
PUSH ECX
XOR EAX, EAX
MOV ECX, EBX
SHR ECX, 8
MOV AH, CH
MOV ECX, EDX
SHR ECX, 8
MOV AL, CH
MOV CL, [ESI+EAX]
CMP CL, 0
JZ @SKIP
MOV [EDI], CL
@SKIP:
INC EDI
MOV EAX, [WarpDDY]
ADD EDX, EAX
ADD EAX, [WarpY]
MOV [WarpDDY], EAX
ADD EBX, [DDX]
POP ECX
DEC ECX
JNZ @PixelLoop
MOV EAX, [D2X]
MOV ECX, [D2Y]
ADD [I], EAX
ADD [J], ECX
POP ECX
ADD EAX, [WARPX]
MOV [D2X], EAX
DEC ECX
JNZ @LineLoop
END; (**)
END;
(****************************************************************************)
(* This one mixes two pages and stores the result. x86 version *)
(****************************************************************************)
PROCEDURE MixPages_x86(From1, From2, Too : DWORD); ASSEMBLER; ASM
MOV ESI, [FROM1]
MOV EBX, [FROM2]
MOV EDI, [TOO]
MOV ECX, 64000
@PixelLoop:
MOVZX EAX, BYTE PTR [ESI]
INC ESI
MOVZX EDX, BYTE PTR [EBX]
INC EBX
ADD EAX, EDX
SHR EAX, 1
MOV [EDI], AL
INC EDI
DEC ECX
JNZ @PixelLoop
END;
(****************************************************************************)
(* This one mixes two pages and stores. mmx version *)
(****************************************************************************)
PROCEDURE MixPages_MMX(From1, From2, Too : DWORD); ASSEMBLER; ASM
MOV ESI, [FROM1]
MOV EBX, [FROM2]
MOV EDI, [TOO]
MOVQ mm2, QWORD PTR [SomeBitsOutMask]
MOV ECX, 8192
@PixelLoop:
MOVQ mm0, [ESI]
ADD ESI, 8
MOVQ mm1, [EBX]
PSRLQ mm0, 1
PSRLQ mm1, 1
PAND mm0, mm2
PAND mm1, mm2
ADD EBX, 8
PADDUSB mm0, mm1
MOVQ [EDI], mm0
ADD EDI, 8
DEC ECX
JNZ @PixelLoop
EMMS
END;
(****************************************************************************)
(* This one mixes pages with saturation, just (A+B) and trim on 255 *)
(****************************************************************************)
PROCEDURE MixPages2_x86(From1, From2, Too : DWORD); ASSEMBLER; ASM
MOV ESI, [FROM1]
MOV EBX, [FROM2]
MOV EDI, [TOO]
MOV ECX, 64000
@PixelLoop:
MOVZX EAX, BYTE PTR [ESI]
INC ESI
MOVZX EDX, BYTE PTR [EBX]
INC EBX
ADD EAX, EDX
CMP EAX, 255
JB @OK
MOV AL, 255
@OK:
MOV [EDI], AL
INC EDI
DEC ECX
JNZ @PixelLoop
END;
(****************************************************************************)
(* This one does a saturated add of two pages, mmx version *)
(****************************************************************************)
PROCEDURE MixPages2_MMX(From1, From2, Too : DWORD); ASSEMBLER; ASM
MOV ESI, [FROM1]
MOV EBX, [FROM2]
MOV EDI, [TOO]
MOV ECX, 8000
@PixelLoop:
MOVQ mm0, [ESI]
ADD ESI, 8
MOVQ mm1, [EBX]
ADD EBX, 8
PADDUSB mm0, mm1
MOVQ [EDI], mm0
ADD EDI, 8
DEC ECX
JNZ @PixelLoop
EMMS
END;
(****************************************************************************)
(* This one does an alphablended mix of two pages. *)
(****************************************************************************)
PROCEDURE MixPages3_x86(From1, From2, Too : DWORD; Amount : BYTE);ASSEMBLER; ASM
MOV ESI, [FROM1]
MOV EBX, [FROM2]
MOV ECX, 64000
MOV EDI, [TOO]
@LOOP:
MOV AL, [ESI]
MUL [amount]
MOV DH, AH
MOV AL, [EBX]
MOV DL, [Amount]
NOT DL
MUL DL
SHR AX, 8
ADD AL, DH
MOV [EDI], AL
INC ESI
INC EBX
INC EDI
DEC ECX
JNZ @LOOP
END;
(****************************************************************************)
(* This one does an alphablended mix of two pages. mmx version. *)
(****************************************************************************)
PROCEDURE MixPages3_mmx(FROM1, FROM2, TOO : DWORD; Amount : BYTE); ASSEMBLER; ASM
MOV ESI, [FROM1]
MOVZX DX, [Amount]
MOV EBX, [FROM2]
SHL EDX, 16
MOV EDI, [TOO]
MOV ECX, 8000
MOVZX DX, [Amount]
MOV AX, DX
NOT AL
SHL EAX, 16
MOV AX, DX
NOT AL
MOVD mm0, EDX
MOVD mm1, EDX
PSLLQ mm1, 32
POR mm0, mm1
MOVD mm1, EAX
MOVD mm2, EAX
PSLLQ mm2, 32
POR mm1, mm2
PSLLQ mm7, 64
@QuadPixelLoop:
MOVQ mm2, [ESI]
MOVQ mm3, [EBX]
MOVQ mm4, mm2
MOVQ mm5, mm3
PUNPCKHBW mm2, mm7
PUNPCKLBW mm4, mm7
PMULLW mm2, mm0
PUNPCKHBW mm3, mm7
PMULLW mm4, mm0
PUNPCKLBW mm5, mm7
PMULLW mm3, mm1
ADD ESI, 8
PMULLW mm5, mm1
PADDUSW mm2, mm3
ADD EBX, 8
PADDUSW mm4, mm5
PSRLW mm2, 8
PSRLW mm4, 8
PACKUSWB mm4, mm2
MOVQ [EDI], mm4
ADD EDI, 8
DEC ECX
JNZ @QuadPixelLoop
EMMS
END;
(****************************************************************************)
(* This one does a bump-map. *)
(****************************************************************************)
PROCEDURE BumpMap(FROM, TOO, LIGHT : DWORD; LX, LY : WORD); ASSEMBLER;
VAR X, Y : WORD;
ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV EDX, [LIGHT]
MOV ECX, 63360
ADD ESI, 320
ADD EDI, 320
MOV [X], 0
MOV [Y], 0
@PixelLoop:
MOVZX EAX, BYTE [ESI-320]
MOV AH, BYTE [ESI+320]
SUB AL, AH
MOV BH, BYTE [ESI-1]
MOV BL, BYTE [ESI+1]
SUB BL, BH
MOV AH, 0
MOV BH, 0
ADD AX, [LX]
ADD BX, [LY]
ADD AX, [X]
ADD BX, [Y]
MOV AH, BL
INC [X]
CMP [X], 320
JNZ @NO
INC [Y]
MOV [X], 0;
@NO:
MOV BL, [EDX+EAX]
MOV [EDI], BL
INC ESI
INC EDI
DEC ECX
JNZ @PixelLoop
END;
(****************************************************************************)
(* This one does a bump-map. (no tiled lights) *)
(****************************************************************************)
PROCEDURE BumpMap2(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER); ASSEMBLER;
VAR X, Y : WORD;
ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV ECX, 63360
ADD ESI, 320
ADD EDI, 320
MOV [X], 0
MOV [Y], 0
@PixelLoop:
MOVZX EAX, BYTE [ESI-320]
MOVZX DX, BYTE [ESI+320]
SUB AX, DX
MOVZX BX, BYTE [ESI-1]
MOVZX DX, BYTE [ESI+1]
SUB BX, DX
ADD AX, [LX]
ADD BX, [LY]
ADD AX, [X]
ADD BX, [Y]
CMP AH, 0
JZ @XinRange
MOV AL, 0
MOV BL, 0
@XinRange:
CMP BH, 0
JZ @YinRange
MOV AL, 0
MOV BL, 0
@YinRange:
MOV AH, BL
INC [X]
MOV EDX, [LIGHT]
CMP [X], 320
JNZ @NO
INC [Y]
MOV [X], 0;
@NO:
MOV BL, [EDX+EAX]
MOV [EDI], BL
INC ESI
INC EDI
DEC ECX
JNZ @PixelLoop
END;
(****************************************************************************)
(* This one does a bump-map. (no tiled lights, no color 0) *)
(****************************************************************************)
PROCEDURE BumpMap2T(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER); ASSEMBLER;
VAR X, Y : WORD;
ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV ECX, 63360
ADD ESI, 320
ADD EDI, 320
MOV [X], 0
MOV [Y], 0
@PixelLoop:
MOV BL, BYTE PTR [ESI]
CMP BL, 0
JZ @Skip
MOVZX EAX, BYTE [ESI-320]
MOVZX DX, BYTE [ESI+320]
SUB AX, DX
MOVZX BX, BYTE [ESI-1]
MOVZX DX, BYTE [ESI+1]
SUB BX, DX
ADD AX, [LX]
ADD BX, [LY]
ADD AX, [X]
ADD BX, [Y]
CMP AH, 0
JZ @XinRange
MOV AL, 0
MOV BL, 0
@XinRange:
CMP BH, 0
JZ @YinRange
MOV AL, 0
MOV BL, 0
@YinRange:
MOV AH, BL
MOV EDX, [LIGHT]
MOV BL, [EDX+EAX]
@Skip:
INC [X]
CMP [X], 320
JNZ @NO
INC [Y]
MOV [X], 0;
@NO:
MOV [EDI], BL
INC ESI
INC EDI
DEC ECX
JNZ @PixelLoop
END;
(****************************************************************************)
(* This one does a bump-map. (no tiled lights) *)
(****************************************************************************)
PROCEDURE BumpMap3(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER); ASSEMBLER;
VAR X, Y : WORD;
ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV ECX, 63360
ADD ESI, 320
ADD EDI, 320
MOV [X], 0
MOV [Y], 0
@PixelLoop:
MOVZX EAX, BYTE [ESI-320]
MOVZX DX, BYTE [ESI+320]
SUB AX, DX
MOVZX EBX, BYTE [ESI-1]
MOVZX DX, BYTE [ESI+1]
SUB BX, DX
ADD AX, [LX]
ADD BX, [LY]
ADD AX, [X]
ADD BX, [Y]
MOVZX DX, BYTE [ESI]
NOT DL
SHR DL, 1
ADD DL, 128
MUL DX
SHR EAX, 8
MOV AH, DL
XCHG EAX, EBX
MOVZX DX, BYTE [ESI]
NOT DL
SHR DL, 1
ADD DL, 128
MUL DX
SHR EAX, 8
MOV AH, DL
XCHG EAX, EBX
CMP AH, 0
JZ @XinRange
MOV AL, 0
MOV BL, 0
@XinRange:
CMP BH, 0
JZ @YinRange
MOV AL, 0
MOV BL, 0
@YinRange:
MOV AH, BL
INC [X]
MOV EDX, [LIGHT]
CMP [X], 320
JNZ @NO
INC [Y]
MOV [X], 0;
@NO:
MOV BL, [EDX+EAX]
MOV [EDI], BL
INC ESI
INC EDI
DEC ECX
JNZ @PixelLoop
END;
(****************************************************************************)
(* This one does a bump-map. (slope+heights+transparent) *)
(****************************************************************************)
PROCEDURE BumpMap3t(FROM, TOO, LIGHT : DWORD; LX, LY : INTEGER); ASSEMBLER;
VAR X, Y : WORD;
ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV ECX, 63360
ADD ESI, 320
ADD EDI, 320
MOV [X], 0
MOV [Y], 0
@PixelLoop:
MOV BL, [ESI]
CMP BL, 0
JZ @Skip
MOVZX EAX, BYTE [ESI-320]
MOVZX DX, BYTE [ESI+320]
SUB AX, DX
MOVZX EBX, BYTE [ESI-1]
MOVZX DX, BYTE [ESI+1]
SUB BX, DX
ADD AX, [LX]
ADD BX, [LY]
ADD AX, [X]
ADD BX, [Y]
MOVZX DX, BYTE [ESI]
NOT DL
SHR DL, 1
ADD DL, 128
MUL DX
SHR EAX, 8
MOV AH, DL
XCHG EAX, EBX
MOVZX DX, BYTE [ESI]
NOT DL
SHR DL, 1
ADD DL, 128
MUL DX
SHR EAX, 8
MOV AH, DL
XCHG EAX, EBX
CMP AH, 0
JZ @XinRange
MOV AL, 0
MOV BL, 0
@XinRange:
CMP BH, 0
JZ @YinRange
MOV AL, 0
MOV BL, 0
@YinRange:
MOV AH, BL
MOV EDX, [LIGHT]
MOV BL, [EDX+EAX]
@Skip:
INC [X]
CMP [X], 320
JNZ @NO
INC [Y]
MOV [X], 0;
@NO:
MOV [EDI], BL
INC ESI
INC EDI
DEC ECX
JNZ @PixelLoop
END;
(****************************************************************************)
(* This one scales a 320*200 to 256*256 to use as source for rotate :) *)
(****************************************************************************)
PROCEDURE Scale320to256(FROM, TOO : DWORD);
ASSEMBLER; VAR EEX, EFX : LONGINT; ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV ECX, 256
MOV [EFX], 0
@LineLoop:
PUSH ECX
MOV [EEX], 0
MOV ECX, 256
@PixelLoop:
MOV EAX, [EFX]
MOV EBX, [EEX]
SHR EAX, 8
SHR EBX, 8
MOV EDX, 320
mul EDX
ADD EAX, EBX
MOV DL, [ESI+EAX]
MOV [EDI], DL
INC EDI
ADD [EEX], 320
DEC CL
JNZ @PixelLoop
ADD [EFX], 200
POP ECX
DEC ECX
JNZ @LineLoop
END;
(****************************************************************************)
(* This one scales a 256*256 to 320*200. *)
(****************************************************************************)
PROCEDURE Scale256to320(FROM, TOO : DWORD);
VAR CX, CY : LONGINT;
DX, DY : LONGINT;
W1, W2 : LONGINT;
BEGIN
DX := (255 SHL 8) DIV 199;
DY := (255 SHL 8) DIV 319;
CX := 0;
CY := 0;
FOR W1 := 0 TO 199 DO BEGIN
CY := 0;
FOR W2 := 0 TO 319 DO BEGIN
PutPixel(Too, W1, W2, GetPixel255(From, CX SHR 8, CY SHR 8));
CY +:= DY;
END;
CX +:= DX;
END;
END;
(****************************************************************************)
(* This one applys two relocation maps to from. (from is 255*255 !) *)
(****************************************************************************)
PROCEDURE Relocate(From, Too, Distort1, Distort2, D1Ofs, D2Ofs : LONGINT); ASSEMBLER; ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV EDX, [Distort1]
MOV EBX, [Distort2]
MOV ECX, 64000
@LOOP:
PUSH ECX
MOVZX EAX, BYTE PTR [EDX]
ADD EAX, [D1Ofs]
SHL EAX, 8
MOVZX ECX, BYTE PTR [EBX]
SHL ECX, 1
ADD ECX, [D2Ofs]
ADD EAX, ECX
AND EAX, $FFFF
MOV CL, [ESI+EAX]
MOV [EDI], CL
INC EDX
INC EBX
INC EDI
POP ECX
DEC ECX
JNZ @Loop
END;
(****************************************************************************)
(* Same, but doesn't draw color 0 *)
(****************************************************************************)
PROCEDURE RelocateT(From, Too, Distort1, Distort2, D1Ofs, D2Ofs : LONGINT); ASSEMBLER; ASM
MOV ESI, [FROM]
MOV EDI, [TOO]
MOV EDX, [Distort1]
MOV EBX, [Distort2]
MOV ECX, 64000
@LOOP:
PUSH ECX
MOVZX EAX, BYTE PTR [EDX]
ADD EAX, [D1Ofs]
SHL EAX, 8
MOVZX ECX, BYTE PTR [EBX]
SHL ECX, 1
ADD ECX, [D2Ofs]
ADD EAX, ECX
AND EAX, $FFFF
MOV CL, [ESI+EAX]
CMP CL, 0
JZ @Skip
MOV [EDI], CL
@Skip:
INC EDX
INC EBX
INC EDI
POP ECX
DEC ECX
JNZ @Loop
END;
(****************************************************************************)
(* This one does a ripple. (X86 version) *)
(****************************************************************************)
PROCEDURE Ripple_x86(VAR Page1, Page2 : DWORD); ASSEMBLER; ASM
MOV ECX, [Page1]
MOV EDX, [Page2]
MOV ESI, [ECX]
MOV EDI, [EDX]
MOV [ECX], EDI
MOV [EDX], ESI
ADD ESI, 320
ADD EDI, 320
MOV ECX, 63360
@LOOP:
MOVZX EAX, BYTE [ESI-320]
MOVZX EBX, BYTE [ESI-1]
MOVZX EDX, BYTE [ESI+1]
ADD EAX, EBX
MOVZX EBX, BYTE [ESI+320]
ADD EAX, EDX
MOVZX EDX, BYTE [EDI]
ADD EAX, EBX
SUB EAX, 512
SUB EDX, 128
INC ESI
SAR EAX, 1
SUB EAX, EDX
MOV EBX, EAX
SAR EAX, 5
SUB EBX, EAX
MOV EAX, EBX
ADD EAX, 128
CMP EAX, 0
JA @OK1
MOV EAX, 0
@OK1:
CMP EAX, 255
JB @OK2
MOV EAX, 255
@OK2:
MOV [EDI], AL
INC EDI
DEC ECX
JNZ @Loop
END;
(****************************************************************************)
(* This one does a ripple. (mmx version) *)
(****************************************************************************)
PROCEDURE Ripple_mmx(VAR Page1, Page2 : DWORD); ASSEMBLER; ASM
MOV ECX, [Page1]
MOV EDX, [Page2]
MOV ESI, [ECX]
MOV EDI, [EDX]
MOV [ECX], EDI
MOV [EDX], ESI
MOV ECX, 7920 (* Loop count. (7920*8=65536-640) *)
ADD EDI, 320 (* Skip first line. *)
ADD ESI, 320 (* Also on source. *)
PSLLQ mm7, 64 (* Clear mm7 *)
@LOOP:
MOVQ mm0, QWORD PTR [ESI-320] (* Get 8 pixels above. *)
MOVQ mm1, QWORD PTR [ESI-1] (* Get 8 pixels left. *)
MOVQ mm2, mm0 (* Copy above pixels. *)
MOVQ mm3, mm1 (* Copy left pixels. *)
PUNPCKHBW mm0, mm7 (* Unpack 4 above pxls in mm0 to words*)
PUNPCKHBW mm1, mm7 (* Unpack 4 left pxls in mm1 to words *)
PUNPCKLBW mm2, mm7 (* Unpack low above pxls to words. *)
PUNPCKLBW mm3, mm7 (* Unpack low left pxls to words. *)
PADDUSW mm0, mm1 (* Add above and left pixels. *)
PADDUSW mm2, mm3 (* Add 4 next above and left pixels. *)
MOVQ mm4, QWORD PTR [ESI+1] (* Get 8 right pixels. *)
MOVQ mm5, QWORD PTR [ESI+320] (* Get 8 below pixels. *)
MOVQ mm1, mm4 (* Copy 8 right pixels. *)
MOVQ mm3, mm5 (* Copy 8 below pixels. *)
PUNPCKHBW mm4, mm7 (* Unpack high right pxls to words. *)
PUNPCKHBW mm5, mm7 (* Unpack high below pxls to words. *)
PUNPCKLBW mm1, mm7 (* Unpack low right pxls to words. *)
PUNPCKLBW mm3, mm7 (* Unpack low below pxls to words. *)
PADDUSW mm4, mm5 (* Add right and below pixels. *)
PADDUSW mm1, mm3 (* Add other right and below pixels. *)
PADDUSW mm0, mm4 (* Now add 4st 4 pixels all together *)
PADDUSW mm2, mm1 (* Same for next four. *)
PSUBW mm0, [MASK512W]
PSUBW mm2, [MASK512W]
MOVQ mm4, QWORD PTR [EDI]
MOVQ mm1, mm4
PUNPCKHBW mm4, mm7
PUNPCKLBW mm1, mm7
PSUBW mm4, [MASK128W]
PSUBW mm1, [MASK128W]
PSRAW mm0, 1
PSRAW mm2, 1
PSUBW mm0, mm4
PSUBW mm2, mm1
MOVQ mm3, mm0
MOVQ mm4, mm2
PSRAW mm3, 5
PSRAW mm4, 5
PSUBW mm0, mm3
PSUBW mm2, mm4
PADDW mm0, [MASK128W]
PADDW mm2, [MASK128W]
PACKUSWB mm2, mm0 (* Pack words in mm2 and mm0 to bytes *)
MOVQ [EDI], mm2 (* Store 8 pixels on destination. *)
ADD ESI, 8 (* Increase source pointer. *)
ADD EDI, 8 (* Increase destination pointer. *)
DEC ECX (* Decrease loop counter. *)
JNZ @LOOP (* Jump until ECX = 0 *)
EMMS (* Exit multimedia state. *)
END;
(****************************************************************************)
(* Displacement effect. *)
(****************************************************************************)
PROCEDURE DisPlace(From, Too, Disp : DWORD); ASSEMBLER; ASM
MOV EDI, [Too]
MOV ESI, [Disp]
ADD EDI, 320
MOV EDX, 1
@LineLoop:
XOR ECX, ECX
@PixelLoop:
PUSH EDX
PUSH ECX
MOVZX EBX, BYTE [ESI-320]
MOVZX EAX, BYTE [ESI+320]
SUB EBX, EAX
ADD EDX, EBX
MOVZX EBX, BYTE [ESI-1]
MOVZX EAX, BYTE [ESI+1]
SUB EBX, EAX
ADD ECX, EBX
CMP ECX, 0
JA @OK1
MOV ECX, 0
@OK1:
CMP ECX, 319
JB @OK2
MOV ECX, 319
@OK2:
CMP EDX, 0
JA @OK3
MOV EDX, 0
@OK3:
CMP EDX, 199
JB @OK4
MOV EDX, 199
@OK4:
LEA EDX, [EDX+4*EDX]
MOV EBX, 0
SHL EDX, 6
ADD EDX, ECX
MOV EBX, [FROM]
MOV AL, [EBX+EDX]
MOV BYTE [EDI], AL
INC EDI
INC ESI
POP ECX
POP EDX
INC ECX
CMP ECX, 320
JNZ @PixelLoop
INC EDX
CMP EDX, 195
JNZ @LineLoop
END;
(****************************************************************************)
(* This one does a fire effect. *)
(****************************************************************************)
PROCEDURE DoFire(From, Too, Flame : DWORD); ASSEMBLER; ASM
MOV EDI, [TOO]
MOV ECX, 63360
MOV ESI, [FROM]
MOV EDX, [Flame]
@LOOP:
MOVZX EAX, BYTE PTR [ESI]
MOVZX EBX, BYTE PTR [ESI+319]
ADD EAX, EBX
MOVZX EBX, BYTE PTR [ESI+320]
SHL EBX, 2
ADD EAX, EBX
MOVZX EBX, BYTE PTR [ESI+321]
ADD EAX, EBX
MOVZX EBX, BYTE PTR [ESI+640]
ADD EAX, EBX
SHR EAX, 3
MOVZX EBX, BYTE PTR [EDX]
SHR EBX, 3
SUB EAX, EBX
JNS @Skip
MOV AL, 0
@Skip:
MOV [EDI], AL
INC ESI
INC EDI
INC EDX
DEC ECX
JNZ @LOOP
END;
(****************************************************************************)
(* Initialise two distortion maps for tunnel effect. *)
(****************************************************************************)
PROCEDURE InitTunnel(Distort1, Distort2 : DWORD);
VAR W1, W2, W3, W4, W5 : LONGINT;
R1, R2, R3 : REAL;
BEGIN
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN W3:=W1 ELSE W3:=1;
IF W2<>0 THEN W4:=W2 ELSE W4:=1;
R1:=Trunc(Exp(Ln(262144*(SQRT(W1*W1+W2*W2)+0.001))*0.1)*256);
W5:=trunc(R1+(32*Sin(R1*1.284/64)));
PutPixel(Distort1, W1+100, W2+160, W5 AND $FF);
END;
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN R2:=W1 ELSE R2:=0.0001;
IF W2<>0 THEN R3:=W2 ELSE R3:=0.0001;
R1:=ArcTan(R3/R2)*(256/6.284);
W3:=Trunc(R1);
PutPixel(Distort2, W1+100, W2+160, W3 AND $FF);
END;
END;
(****************************************************************************)
(* Initialise two distortion maps for tunnel effect. *)
(****************************************************************************)
PROCEDURE InitTunnel2(Distort1, Distort2 : DWORD);
VAR W1, W2, W3, W4, W5 : LONGINT;
R1, R2, R3 : REAL;
BEGIN
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN W3:=W1 ELSE W3:=1;
IF W2<>0 THEN W4:=W2 ELSE W4:=1;
R1:=Trunc(Exp(Ln(262144*(SQRT(W1*W1+W2*W2)+0.001))*0.1)*256);
W5:=trunc(R1+(32*Sin(R1*1.284/64)));
W5:=TRUNC(R1);
PutPixel(Distort1, W1+100, W2+160, W5 AND $FF);
END;
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN R2:=W1 ELSE R2:=0.0001;
IF W2<>0 THEN R3:=W2 ELSE R3:=0.0001;
R1:=ArcTan(R3/R2)*(256/6.284) + ArcTan(SQRT(W1*W1+W2*W2))*2000;
W3:=Trunc(R1);
PutPixel(Distort2, W1+100, W2+160, W3 AND $FF);
END;
END;
(****************************************************************************)
(* Initialise two distortion maps for tunnel effect. *)
(****************************************************************************)
PROCEDURE InitTunnelFast(Distort1, Distort2 : DWORD);
VAR W1, W2, W3, W4, W5 : LONGINT;
R1, R2, R3 : REAL;
BEGIN
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN W3:=W1 ELSE W3:=1;
IF W2<>0 THEN W4:=W2 ELSE W4:=1;
R1:=TRUNC(SQRT(((W3*W3)+(W4*W4))));
R1:=Trunc(Exp((Ln(Ln(256*R1))*0.41))*256);
W5:=Trunc(r1+(64*Cos(R1*1.284/64)));
PutPixel(Distort1, W1+100, W2+160, W5 AND $FF);
END;
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN R2:=W1 ELSE R2:=0.0001;
IF W2<>0 THEN R3:=W2 ELSE R3:=0.0001;
R1:=ArcTan(R3/R2)*(256/6.284);
W3:=Trunc(R1);
PutPixel(Distort2, W1+100, W2+160, W3 AND $FF);
END;
END;
(****************************************************************************)
(* Initialise two distortion maps for flashke effect. *)
(****************************************************************************)
PROCEDURE InitFlashke(Distort1, Distort2 : DWORD);
VAR W1, W2, W3, W4, W5 : LONGINT;
R1, R2, R3 : REAL;
BEGIN
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN W3:=W1 ELSE W3:=1;
IF W2<>0 THEN W4:=W2 ELSE W4:=1;
R1:=TRUNC(SQRT(((W3*W3)+(W4*W4))));
R1:=Trunc(Exp(Ln(256*R1)*0.21)*256);
W5:=Trunc(R1+(64*Cos(R1*1.284/32)));
PutPixel(Distort1, W1+100, W2+160, W5 AND $FF);
END;
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN R2:=W1 ELSE R2:=0.0001;
IF W2<>0 THEN R3:=W2 ELSE R3:=0.0001;
R1:=ArcTan(R3/R2)*(256/6.284) + SQRT(R2*R2 + R3*R3);
W3:=Trunc(R1);
PutPixel(Distort2, W1+100, W2+160, W3 AND $FF);
END;
END;
(****************************************************************************)
(* Initialise two distortion maps for flashke effect. *)
(****************************************************************************)
PROCEDURE InitSpiral(Distort1, Distort2 : DWORD);
VAR W1, W2, W3, W4, W5 : LONGINT;
R1, R2, R3 : REAL;
BEGIN
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN W3:=W1 ELSE W3:=1;
IF W2<>0 THEN W4:=W2 ELSE W4:=1;
R1:=TRUNC(SQRT(((W3*W3)+(W4*W4))));
R1:=Trunc((exp(ln( ABS(Sin(R1/256))*128 )*0.2))*256);
W5:=TRUNC(r1/(sin(R1/256)/cos(r1/256)));
PutPixel(Distort1, W1+100, W2+160, W5 AND $FF);
END;
FOR W1:=-100 TO 99 DO
FOR W2:=-160 TO 159 DO
BEGIN
IF W1<>0 THEN R2:=W1 ELSE R2:=0.0001;
IF W2<>0 THEN R3:=W2 ELSE R3:=0.0001;
R1:=(ArcTan(R3/R2)*(256/6.284)*4) + SIN(SQRT((SQR(R2)+SQR(R3))/256))*64 + COS(SQRT((SQR(R2)+SQR(R3))/256))*64;
W3:=Trunc(R1);
PutPixel(Distort2, W1+100, W2+160, W3 AND $FF);
END;
END;
(****************************************************************************)
(* Init's the standard light for the bumpmapper. *)
(****************************************************************************)
PROCEDURE InitBump(Light : DWORD);
VAR W1, W2 : LONGINT;
FUNCTION CL(X:LONGINT):LONGINT;BEGIN IF X < 0 THEN CL:=0 ELSE CL := X END;
BEGIN
FOR W1 := 0 TO 255 DO
FOR W2 := 0 TO 255 DO
PutPixel255(Light, W1, W2, CL(255-TRUNC(SQRT(SQR(W1-128)+SQR(W2-128))/191*370)));
END;
(****************************************************************************)
(* This one init's a lightmap with a smaller light. *)
(****************************************************************************)
PROCEDURE InitBumpSmall(Light : DWORD);
VAR W1, W2 : LONGINT;
FUNCTION CL(X:LONGINT):LONGINT;BEGIN IF X < 0 THEN CL:=0 ELSE CL := X END;
BEGIN
FOR W1 := 0 TO 255 DO
FOR W2 := 0 TO 255 DO
PutPixel255(Light, W1, W2, CL(255-TRUNC(SQRT(SQR(W1-128)+SQR(W2-128))/191*740)));
END;
(****************************************************************************)
(* This one loads a raw image from disk onto a fake screen. Only 256*256*8b *)
(****************************************************************************)
PROCEDURE LoadRAW(Where : DWORD; Name : STRING);
TYPE Square255 = ARRAY[0..255,0..255] OF BYTE;
VAR F : FILE;
P : ^Square255;
BEGIN
ASSIGN(F, Name);
{$i-}
RESET(F, 1);
{$i+}
P := PTR(Where);
IF IORESULT = 0 THEN BEGIN
BlockRead(F, P^, 65536);
END;
CLOSE(F);
END;
(****************************************************************************)
(* This one allocate memory for a new fake screen. Returns offset *)
(****************************************************************************)
FUNCTION NewPage : DWORD;
VAR Temp : POINTER;
BEGIN
getmem(temp, 65536);
NewPage := OFS(Temp^); (* Returns new page offset *)
END;
(****************************************************************************)
(* This one allocates the memory allocated to the given offset. *)
(****************************************************************************)
PROCEDURE DisposePage(PageOffset : DWORD);
VAR Temp : Pointer;
BEGIN
Temp := PTR(PAgeOffset);
Freemem(Temp, 65536);
END;
(****************************************************************************)
(* This one detects if mmx is available. *)
(****************************************************************************)
FUNCTION MMXsupported : BOOLEAN;ASSEMBLER; ASM
(* First check if the CPUID instruction is supported. *******************)
PUSHFD (* PUSH Extended flags *)
POP EAX (* Pop'em into EAX *)
MOV EBX, EAX (* Copy into EBX *)
XOR EAX, $200000 (* Change the 21st byte *)
PUSH EAX (* Push this new altered value *)
POPFD (* Pop'em into the EFLAGS register. *)
PUSHFD (* Push the flags again. *)
POP EAX (* Pop'em into EAX again. *)
CMP EAX, EBX (* See if we could change the 21st bit. *)
JZ @NoMMX (* nopez we could'nt .. CPUID NOT SUPPORTED *)
(* Now check for mmx. ***************************************************)
MOV EAX, 1 (* Call subfunction 1. *)
CPUID (* Execute CPUID *)
AND ECX, $00800000 (* Mask out mmx bit. *)
JZ @NOMMX (* It's a zero .. no mmx. *)
MOV AL, 1 (* Yups ... we got mmx. *)
@NOMMX:
END;
(****************************************************************************)
BEGIN
Write ('þ Mute''s educational VGA engine : ');
IF (MMXSupported = TRUE) OR NOT(ParamSTR(1) = 'NOMMX') THEN BEGIN
WriteLn ('using MMX technology !');
ClearPage := ClearPage_mmx;
CopyPage := CopyPage_mmx;
CopyPageSmudge := CopyPageSmudge_mmx;
MixPages := MixPages_mmx;
MixPages2 := MixPages2_mmx;
MixPages3 := MixPages3_mmx;
Ripple := Ripple_mmx;
END ELSE BEGIN
WriteLn ('using X86 technology !');
ClearPage := ClearPage_x86;
CopyPage := CopyPage_x86;
CopyPageSmudge := CopyPageSmudge_x86;
MixPages := MixPages_x86;
MixPages2 := MixPages2_x86;
MixPages3 := MixPages3_x86;
Ripple := Ripple_x86;
END;
END.