{$A+,G+,R-,S-} UNIT MCGA; { Copyright by Stefan Ohrhallinger in 1991,92,93,94 } { aka ¯The Faker® of AARDVARK } INTERFACE CONST Up=0; Right=1; Down=2; Left=3; PROCEDURE SetPixel(X,Y:Word; C:Byte); FUNCTION GetPixel(X,Y:Word):Byte; PROCEDURE DrawLineH(X1,X2,Y1:Word; C:Byte); PROCEDURE DrawLineV(X1,Y1,Y2:Word; C:Byte); PROCEDURE DrawLine(X1,Y1,X2,Y2:Integer; C:Byte); PROCEDURE SetColor(Nr,R,G,B:Byte); PROCEDURE GetColor(Nr:Byte; VAR R,G,B:Byte); FUNCTION PaintChar(Ch,X,Y:Integer; C:Byte):Boolean; PROCEDURE GrWrite(X,Y:Integer; C:Byte; S:String); PROCEDURE LoadFont(Nr:Byte; Name:String); PROCEDURE SetText(Nr:Byte; MultX,DivX,MultY,DivY:Byte); PROCEDURE DrawPolygon(Count:Integer; VAR P; C:Byte); PROCEDURE Fill(X,Y:Integer; C:Byte); { Nur die selbe Farbe ersetzen } PROCEDURE Flood(X,Y:Integer; C,C2:Byte); { Anf„rben bis zur Randfarbe C2 } PROCEDURE MCGAOn; PROCEDURE MCGAOff; PROCEDURE FillPolygon(Size:Integer; VAR P1; C:Byte); PROCEDURE Ellipse(MX,MY,A,B:Integer; C:Byte); PROCEDURE FillEllipse(MX,MY,A,B:Integer; C:Byte); PROCEDURE Circle(X,Y,R:Integer; C:Byte); PROCEDURE FillCircle(X,Y,R:Integer; C:Byte); PROCEDURE RotateArray(VAR P; Count,MX,MY:Integer; Winkel:Real); PROCEDURE N4eck(N,X,Y,R1,R2:Integer; C:Byte); PROCEDURE Neck(N,X,Y,A,B:Integer; Drehen:Real); PROCEDURE DrawRing(X,Y,R1,R2:Integer; C:Byte); PROCEDURE FillRing(X,Y,R1,R2:Integer; C:Byte); PROCEDURE SetFrameColor(C:Byte); PROCEDURE RecTangle(X1,Y1,X2,Y2:Integer; C:Byte); PROCEDURE GetImage(X1,Y1,X2,Y2:Integer; VAR P); PROCEDURE PutImage(X1,Y1:Integer; VAR P); PROCEDURE PutImagePart(X1,Y1,XS2,YS2:Integer; VAR P); PROCEDURE FillBlock(X1,Y1,X2,Y2:Integer; C:Byte); PROCEDURE ScrollLeft(X1,Y1,X2,Y2:Word); PROCEDURE ScrollRight(X1,Y1,X2,Y2:Word); PROCEDURE ScrollUp(X1,Y1,X2,Y2:Word); PROCEDURE ScrollDown(X1,Y1,X2,Y2:Word); PROCEDURE Scroll(Direction:Byte; X1,Y1,X2,Y2:Word); PROCEDURE SwitchOff; PROCEDURE SwitchOn; PROCEDURE LoadPalette(DateiName:String); PROCEDURE SavePalette(DateiName:String); PROCEDURE LoadScreen(DateiName:String); PROCEDURE SaveScreen(DateiName:String); PROCEDURE BCircle(X,Y,R:Integer; C:Byte); PROCEDURE BFillCircle(X,Y,R:Integer; C:Byte); PROCEDURE Split(Row:Integer); PROCEDURE ScrollText(Nr:Word); PROCEDURE SetStart(S:Word); PROCEDURE VerticalRetrace; PROCEDURE WaitScreen; PROCEDURE WaitRetrace; PROCEDURE SetOffset(B:Byte); PROCEDURE LoadSprite(DateiName:String; VAR P); PROCEDURE SaveSprite(DateiName:String; VAR P); FUNCTION SpriteXSize(Sprite:Pointer):Word; FUNCTION SpriteYSize(Sprite:Pointer):Word; FUNCTION SpriteSize(Sprite:Pointer):Word; PROCEDURE FillScreen(C:Byte); PROCEDURE SetChain4; PROCEDURE ClearChain4; PROCEDURE CharHeight(B:Byte); PROCEDURE Wait4Line; PROCEDURE CLI; PROCEDURE STI; PROCEDURE PutImage4(X1,Y1:Integer; VAR P); PROCEDURE SetWriteMap(Map:Byte); PROCEDURE SetWriteMode(M:Byte); PROCEDURE Unchain; PROCEDURE Rechain; PROCEDURE ClearScreen; PROCEDURE SetModeNr(Nr:Word); PROCEDURE Set16Pal(Nr:Byte); PROCEDURE Init16Pal; PROCEDURE SetLineRepeat(Nr:Byte); PROCEDURE TextMode; PROCEDURE Init13X; PROCEDURE SetReadMap(Map:Byte); PROCEDURE DrawLineH4(X1,X2,Y1:Word; C:Byte); PROCEDURE DrawLineV4(X1,Y1,Y2:Word; C:Byte); PROCEDURE SetHorizOfs(Count:Byte); { PROCEDURE SetModeReg(Reg:String); PROCEDURE SetDoubleLines(Ok:Boolean); PROCEDURE SetPal(VAR A); PROCEDURE ReducePal(VAR A); } IMPLEMENTATION CONST MaxFont=4; FontName:ARRAY[1..MaxFont] OF String[4]=('TRIP','LITT','SANS','GOTH'); VekMax=100; X_zu_Y=0.69; TYPE FontType=RECORD FBuf:ARRAY[0..16000] OF Byte; WPtr:^Word; DataOffs,MinChar,TBStart,TblSize,WidthTbl,VecStart,CUp,CDown:Integer; GLine,Index,CharWidth:Integer; END; VAR Font:ARRAY[1..4] OF ^FontType; FontNr,MX,DX,MY,DY:Byte; CurrMode,OldMode:Byte; PROCEDURE SetPixel(X,Y:Word; C:Byte); BEGIN ASM mov ax,$a000 mov es,ax mov bx,x mov dx,y xchg dh,dl mov al,c mov di,dx shr di,1 shr di,1 add di,dx add di,bx stosb END; END; FUNCTION GetPixel(X,Y:Word):Byte; BEGIN ASM mov ax,$a000 mov es,ax mov bx,x mov dx,y mov di,dx shl di,1 shl di,1 add di,dx mov cl,6 shl di,cl add di,bx mov al,es:[di] mov [bp-1],al END; END; PROCEDURE DrawLineH(X1,X2,Y1:Word; C:Byte); BEGIN ASM mov ax,$a000 mov es,ax mov ax,y1 mov di,ax shl di,1 shl di,1 add di,ax mov cl,6 shl di,cl mov bx,x1 mov dx,x2 cmp bx,dx jl @1 xchg bx,dx @1: inc dx add di,bx mov cx,dx sub cx,bx shr cx,1 mov al,c mov ah,al ror bx,1 jnb @2 stosb ror dx,1 jnb @3 dec cx @3: rol dx,1 @2: rep stosw ror dx,1 jnb @4 stosb @4: END; END; PROCEDURE DrawLineV(X1,Y1,Y2:Word; C:Byte); BEGIN ASM mov ax,x1 mov bx,y1 mov dx,y2 cmp bx,dx jl @1 xchg bx,dx @1: mov di,bx shl di,1 shl di,1 add di,bx mov cl,6 shl di,cl add di,ax mov cx,$a000 mov es,cx mov cx,dx sub cx,bx inc cx mov al,c mov bx,$13f @2: stosb add di,bx loop @2 END; END; PROCEDURE DrawLine(X1,Y1,X2,Y2:Integer; C:Byte); BEGIN ASM mov al,c xor ah,ah mov si,ax mov ax,x1 cmp ax,319 ja @Ende mov bx,x2 cmp bx,319 ja @Ende mov cx,y1 cmp cx,199 ja @Ende mov dx,y2 cmp dx,199 ja @Ende cmp ax,bx jnz @weiter cmp cx,dx jnz @vertical push ax push cx push si call setpixel jmp @ende @weiter:cmp cx,dx jnz @weiter2 push ax push bx push cx push si call drawlineh jmp @ende @vertical:push ax push cx push dx push si call drawlinev jmp @ende @weiter2:cmp cx,dx jbe @1 xchg cx,dx xchg ax,bx @1: mov di,cx shl di,1 shl di,1 add di,cx push si mov si,bx mov bx,dx sub bx,cx mov cl,06 shl di,cl add di,ax mov dx,si pop si sub dx,ax mov ax,$a000 mov es,ax mov ax,si push bp or dx,0 jge @jmp1 neg dx cmp dx,bx jbe @jmp3 mov cx,dx inc cx mov si,dx shr si,1 std mov bp,320 @1c: stosb @1b: or si,si jge @1a add di,bp add si,dx jmp @1b @1a: sub si,bx loop @1c jmp @Ende2 @jmp3: mov cx,bx inc cx mov si,bx neg si sar si,1 cld mov bp,319 @2c: stosb @2b: or si,si jl @2a sub si,bx dec di jmp @2b @2a: add di,bp add si,dx loop @2c jmp @Ende2 @jmp1: cmp dx,bx jbe @jmp4 mov cx,dx inc cx mov si,dx shr si,1 cld mov bp,320 @3c: stosb @3b: or si,si jge @3a add di,bp add si,dx jmp @3b @3a: sub si,bx loop @3c jmp @Ende2 @jmp4: mov cx,bx inc cx mov si,bx neg si sar si,1 std mov bp,321 @4c: stosb @4b: or si,si jl @4a sub si,bx inc di jmp @4b @4a: add di,bp add si,dx loop @4c @Ende2: pop bp cld @Ende: END; END; PROCEDURE SetColor(Nr,R,G,B:Byte); BEGIN Port[$3C8]:=Nr; Port[$3C9]:=R; Port[$3C9]:=G; Port[$3C9]:=B; END; PROCEDURE GetColor(Nr:Byte; VAR R,G,B:Byte); BEGIN Port[$3C7]:=Nr; R:=Port[$3C9]; G:=Port[$3C9]; B:=Port[$3C9]; END; FUNCTION PaintChar(Ch,X,Y:Integer; C:Byte):Boolean; VAR XVec,YVec,Func,GraphX,GraphY:Integer; BEGIN PaintChar:=FALSE; WITH Font[FontNr]^ DO BEGIN IF (ChMinChar+TblSize-1) THEN Exit; Index:=VecStart+FBuf[TBStart+(Ch-MinChar)*2]+FBuf[TBStart+(Ch-MinChar)*2+1]*256; REPEAT XVec:=ShortInt(FBuf[Index]); YVec:=ShortInt(FBuf[Index+1]); Inc(Index,2); Func:=(XVec AND $80) SHR 6+(YVec AND $80) SHR 7; XVec:=XVec AND $7F; YVec:=YVec AND $7F; IF XVec>=$40 THEN XVec:=-128+XVec; IF YVec>=$40 THEN YVec:=-128+YVec; IF MX<>1 THEN XVec:=XVec*MX; IF DX<>1 THEN XVec:=XVec DIV DX; IF MY<>1 THEN YVec:=YVec*MY; IF DY<>1 THEN YVec:=YVec DIV DY; CASE Func OF 2:BEGIN GraphX:=X+XVec; GraphY:=CUp+Y-YVec; END; 3:BEGIN DrawLine(X+XVec,CUp+Y-YVec,GraphX,GraphY,C); GraphX:=X+XVec; GraphY:=CUp+Y-YVec; END; END; UNTIL Func=0; END; PaintChar:=TRUE; END; PROCEDURE GrWrite(X,Y:Integer; C:Byte; S:String); VAR I:Byte; BEGIN WITH Font[FontNr]^ DO BEGIN FOR I:=1 TO Ord(S[0]) DO BEGIN IF X+FBuf[WidthTbl+Ord(S[I])-MinChar]*MX DIV DX>319 THEN BEGIN X:=0; IF Y+(CUp-CDown)*MY DIV DY>319 THEN Exit; Inc(Y,(CUp-CDown)*MY DIV DY); END; IF PaintChar(Ord(S[I]),X,Y,C) THEN Inc(X,(FBuf[WidthTbl+Ord(S[I])-MinChar])*MX DIV DX); END; END; END; PROCEDURE LoadFont(Nr:Byte; Name:String); VAR X:Integer; ChrFile:File; BEGIN New(Font[Nr]); WITH Font[Nr]^ DO BEGIN Assign(ChrFile,Name+'.CHR'); Reset(ChrFile,1); BlockRead(ChrFile,FBuf,FileSize(ChrFile)); Close(ChrFile); X:=0; WHILE (X<$80) AND (FBuf[X]<>$1A) DO Inc(X); Inc(X); DataOffs:=FBuf[X]+FBuf[X+1] SHL 8; TblSize:=FBuf[DataOffs+1]; MinChar:=FBuf[DataOffs+4]; CUp:=FBuf[DataOffs+8]; CDown:=ShortInt(FBuf[DataOffs+$0A]); TBStart:=DataOffs+$10; WidthTbl:=TBStart+TblSize SHL 1; WPtr:=@FBuf[DataOffs+5]; VecStart:=WPtr^+DataOffs; END; END; PROCEDURE SetText(Nr:Byte; MultX,DivX,MultY,DivY:Byte); BEGIN IF (Nr<1) OR (Nr>MaxFont) THEN Exit; IF Font[Nr]=NIL THEN LoadFont(Nr,FontName[Nr]); FontNr:=Nr; MX:=MultX; DX:=DivX; MY:=MultY; DY:=DivY; END; PROCEDURE DrawPolygon(Count:Integer; VAR P; C:Byte); TYPE PunkteArray=ARRAY[1..16383,1..2] OF Integer; VAR A:PunkteArray ABSOLUTE P; I:Integer; BEGIN DrawLine(A[Count,1],A[Count,2],A[1,1],A[1,2],C); FOR I:=2 TO Count DO DrawLine(A[I-1,1],A[I-1,2],A[I,1],A[I,2],C); END; PROCEDURE Fill(X,Y:Integer; C:Byte); { Nur die selbe Farbe ersetzen } VAR C2:Byte; PROCEDURE Suchen(L,R,Y:Integer; UpDown:Byte); VAR X,X2:Integer; BEGIN IF GetPixel(L,Y)=C2 THEN WHILE (L>0) AND (GetPixel(L-1,Y)=C2) DO Dec(L); X:=L; IF GetPixel(R,Y)=C2 THEN WHILE (R<319) AND (GetPixel(R+1,Y)=C2) DO Inc(R); WHILE X<=R DO BEGIN X2:=X; IF GetPixel(X,Y)=C2 THEN BEGIN WHILE (GetPixel(X+1,Y)=C2) AND (X<319) DO Inc(X); DrawLineH(X2,X,Y,C); IF UpDown=2 THEN BEGIN IF Y>0 THEN Suchen(X2,X,Y-1,2); IF Y<199 THEN IF (L>X2) AND (RX2) AND (R>=X) THEN Suchen(X2,L-1,Y+1,1); END; IF UpDown=1 THEN BEGIN IF Y<199 THEN Suchen(X2,X,Y+1,1); IF Y>0 THEN IF (L>X2) AND (RX2) AND (R>=X) THEN Suchen(X2,L-1,Y-1,2); END; END; Inc(X); END; END; BEGIN C2:=GetPixel(X,Y); IF Y<>0 THEN Dec(Y); Suchen(X,X,Y,2); Suchen(X,X,Y+1,1); END; PROCEDURE Flood(X,Y:Integer; C,C2:Byte); { Anf„rben bis zur Randfarbe C2 } PROCEDURE Suchen(L,R,Y:Integer; UpDown:Byte); VAR X,X2:Integer; BEGIN IF GetPixel(L,Y)<>C2 THEN WHILE (L>0) AND (GetPixel(L-1,Y)<>C2) DO Dec(L); X:=L; IF GetPixel(R,Y)<>C2 THEN WHILE (R<319) AND (GetPixel(R+1,Y)<>C2) DO Inc(R); WHILE X<=R DO BEGIN X2:=X; IF GetPixel(X,Y)<>C2 THEN BEGIN WHILE (GetPixel(X+1,Y)<>C2) AND (X<319) DO Inc(X); DrawLineH(X2,X,Y,C); IF UpDown=2 THEN BEGIN IF Y>0 THEN Suchen(X2,X,Y-1,2); IF Y<199 THEN IF (L>X2) AND (RX2) AND (R>=X) THEN Suchen(X2,L-1,Y+1,1); END; IF UpDown=1 THEN BEGIN IF Y<199 THEN Suchen(X2,X,Y+1,1); IF Y>0 THEN IF (L>X2) AND (RX2) AND (R>=X) THEN Suchen(X2,L-1,Y-1,2); END; END; Inc(X); END; END; BEGIN IF Y<>0 THEN Dec(Y); Suchen(X,X,Y,2); Suchen(X,X,Y+1,1); END; PROCEDURE MCGAOn; BEGIN ASM mov ah,$f int $10 mov [offset oldmode],al END; ASM mov ax,$13 int $10 END; END; PROCEDURE MCGAOff; BEGIN ASM mov al,[offset oldmode] xor ah,ah int $10 END; END; PROCEDURE FillPolygon(Size:Integer; VAR P1; C:Byte); TYPE Vektor=RECORD X,Y,XMax,DX,DY,DZ,Z,Spalte:Integer; END; VekPoly=ARRAY[1..VekMax,1..2,1..2] OF Integer; VAR P:ARRAY[1..VekMax,1..2] OF Integer ABSOLUTE P1; Sp:VekPoly; NF:Boolean; V:ARRAY[1..VekMax] OF Vektor; S:ARRAY[1..2*VekMax] OF Integer; I,J,K,N,SX,YRMin,YRMax,YR,XMin,YMin,YMax,I2:Integer; BEGIN IF Size>VekMax THEN Exit; K:=1; FOR I:=1 TO Size DO BEGIN Sp[K,1,1]:=P[I,1]; Sp[K,1,2]:=P[I,2]; IF I=Size THEN BEGIN Sp[K,2,1]:=P[1,1]; Sp[K,2,2]:=P[1,2]; END ELSE BEGIN Sp[K,2,1]:=P[I+1,1]; Sp[K,2,2]:=P[I+1,2]; END; IF Sp[K,2,2]-Sp[K,1,2]<0 THEN BEGIN J:=Sp[K,2,1]; Sp[K,2,1]:=Sp[K,1,1]; Sp[K,1,1]:=J; J:=Sp[K,2,2]; Sp[K,2,2]:=Sp[K,1,2]; Sp[K,1,2]:=J; END; Inc(K); END; YRMin:=199; YRMax:=0; FOR K:=1 TO Size DO FOR I:=1 TO 2 DO BEGIN IF Sp[K,I,2]>YRMax THEN YRMax:=Sp[K,I,2]; IF Sp[K,I,2]199 THEN YRMax:=199; FOR K:=1 TO Size DO WITH V[K] DO BEGIN XMin:=Sp[K,1,1]; YMin:=Sp[K,1,2]; XMax:=Sp[K,2,1]; YMax:=Sp[K,2,2]; DX:=Abs(XMin-XMax); DY:=Abs(YMin-YMax); X:=XMin; Y:=YMin; IF XMinDY THEN I2:=DX ELSE I2:=DY; DZ:=I2 DIV 2; Spalte:=XMin; END; FOR YR:=YRMin TO YRMax DO BEGIN N:=0; FOR K:=1 TO Size DO IF ((Sp[K,1,2]<=YR) AND (YRSp[K,1,2])) THEN BEGIN WITH V[K] DO BEGIN Inc(N); S[N]:=X; SX:=X; REPEAT IF DZ=DX THEN BEGIN DZ:=DZ-DX; Inc(Y); END; IF Y=YR THEN SX:=X; Inc(Spalte,Z); UNTIL (Y>YR) OR (Spalte=XMax); Inc(N); S[N]:=SX; END; END; FOR I:=2 TO N DO FOR K:=N DOWNTO I DO IF S[K-1]>S[K] THEN BEGIN J:=S[K-1]; S[K-1]:=S[K]; S[K]:=J; END; K:=1; WHILE K<=N DO BEGIN IF S[K]<0 THEN S[K]:=0; IF S[K+3]>319 THEN S[K+3]:=319; DrawLineH(S[K],S[K+3],YR,C); K:=K+4; END; END; END; PROCEDURE Ellipse(MX,MY,A,B:Integer; C:Byte); VAR X,Y,X2,J:Integer; BEGIN Dec(B); X2:=A; FOR Y:=0 TO B DO BEGIN X:=Trunc(A/B*Sqrt(Sqr(B)-Sqr(Y-0.5))); FOR J:=X TO X2 DO BEGIN SetPixel(MX+J,MY+Y,C); SetPixel(MX-J,MY+Y,C); SetPixel(MX+J,MY-Y,C); SetPixel(MX-J,MY-Y,C); END; X2:=X; END; Inc(B); FOR J:=0 TO X DO BEGIN SetPixel(MX+J,MY+B,C); SetPixel(MX-J,MY+B,C); SetPixel(MX+J,MY-B,C); SetPixel(MX-J,MY-B,C); END; END; PROCEDURE FillEllipse(MX,MY,A,B:Integer; C:Byte); VAR X,Y,X2,J:Integer; BEGIN Dec(B); X2:=A; DrawLineH(MX-A,MX+A,MY,C); FOR Y:=1 TO B DO BEGIN X:=Trunc(A/B*Sqrt((Sqr(LongInt(B)))-Sqr(Y-0.5))); DrawLineH(MX-X,MX+X,MY+Y,C); DrawLineH(MX-X,MX+X,MY-Y,C); X2:=X; END; END; PROCEDURE Circle(X,Y,R:Integer; C:Byte); BEGIN Ellipse(X,Y,R,Trunc(R*X_zu_Y),C); END; PROCEDURE FillCircle(X,Y,R:Integer; C:Byte); BEGIN FillEllipse(X,Y,R,Round(R*X_zu_Y),C); END; PROCEDURE RotateArray(VAR P; Count,MX,MY:Integer; Winkel:Real); TYPE PunkteArray=ARRAY[1..16383,1..2] OF Integer; VAR A:PunkteArray ABSOLUTE P; I,X,Y:Integer; CosWi,SinWi:Real; BEGIN Winkel:=-Pi*Winkel/180; CosWi:=Cos(Winkel); SinWi:=Sin(Winkel); FOR I:=1 TO Count DO BEGIN X:=A[I,1]-MX; Y:=A[I,2]-MY; A[I,1]:=Round(X*CosWi+Y*SinWi)+MX; A[I,2]:=Round(-X*SinWi+Y*CosWi)+MY; END; END; PROCEDURE N4eck(N,X,Y,R1,R2:Integer; C:Byte); VAR D:ARRAY[0..100] OF Word; I,X1,Y1,X2,Y2:Integer; Pi180:Real; BEGIN Pi180:=Pi/180; FOR I:=0 TO N DO D[I]:=Round(Sin(Pi180*I/N*90)*10000); X1:=Round(D[0]*R1/10000); Y1:=Round(D[N]*R2/10000); FOR I:=1 TO N DO BEGIN X2:=Round(D[I]*R1/10000); Y2:=Round(D[N-I]*R2/10000); DrawLine(X-X1,Y+Y1,X-X2,Y+Y2,C); DrawLine(X+X1,Y+Y1,X+X2,Y+Y2,C); DrawLine(X+X1,Y-Y1,X+X2,Y-Y2,C); DrawLine(X-X1,Y-Y1,X-X2,Y-Y2,C); X1:=X2; Y1:=Y2; END; END; PROCEDURE Neck(N,X,Y,A,B:Integer; Drehen:Real); VAR I:Integer; Winkel,Wi:Real; P:ARRAY[1..100,1..2] OF Integer; BEGIN Winkel:=2*Pi/N; Wi:=Winkel; FOR I:=1 TO N DO BEGIN P[I,1]:=Round(A*Cos(Wi))+X; P[I,2]:=Round(B*Sin(Wi))+Y; Wi:=Wi+Winkel; END; IF Drehen<>0 THEN RotateArray(P,N,X,Y,Drehen); DrawPolygon(N,P,255); END; PROCEDURE DrawRing(X,Y,R1,R2:Integer; C:Byte); TYPE Arr52=ARRAY[1..52,1..2] OF Integer; CONST D:ARRAY[1..14] OF Integer=(0,1205,2393,3546,4647,5681,6631,7485,8230,8855,9350,9709,9927,10000); A:Arr52=( (0,10000),(1205,9927),(2393,9709),(3546,9350),(4647,8855),(5681,8230),(6631,7485), (7485,6631),(8230,5681),(8855,4647),(9350,3546),(9709,2393),(9927,1205), (10000,0),(9927,-1205),(9709,-2393),(9350,-3546),(8855,-4647),(8230,-5681),(7485,-6631), (6631,-7485),(5681,-8230),(4647,-8855),(3546,-9350),(2393,-9709),(1205,-9927), (0,-10000),(-1205,-9927),(-2393,-9709),(-3546,-9350),(-4647,-8855),(-5681,-8230),(-6631,-7485), (-7485,-6631),(-8230,-5681),(-8855,-4647),(-9350,-3546),(-9709,-2393),(-9927,-1205), (-10000,0),(-9927,1205),(-9709,2393),(-9350,3546),(-8855,4647),(-8230,5681),(-7485,6631), (-6631,7485),(-5681,8230),(-4647,8855),(-3546,9350),(-2393,9709),(-1205,9927)); VAR I,X1,Y1,X2,Y2:Integer; A2:Arr52; BEGIN A2:=A; FOR I:=1 TO 52 DO BEGIN A2[I,1]:=X+Round(A2[I,1]/10000*R1); A2[I,2]:=Y+Round(A2[I,2]/10000*R2); END; DrawPolygon(52,A2,C); END; PROCEDURE FillRing(X,Y,R1,R2:Integer; C:Byte); TYPE Arr52=ARRAY[1..52,1..2] OF Integer; CONST D:ARRAY[1..14] OF Integer=(0,1205,2393,3546,4647,5681,6631,7485,8230,8855,9350,9709,9927,10000); A:Arr52=( (0,10000),(1205,9927),(2393,9709),(3546,9350),(4647,8855),(5681,8230),(6631,7485), (7485,6631),(8230,5681),(8855,4647),(9350,3546),(9709,2393),(9927,1205), (10000,0),(9927,-1205),(9709,-2393),(9350,-3546),(8855,-4647),(8230,-5681),(7485,-6631), (6631,-7485),(5681,-8230),(4647,-8855),(3546,-9350),(2393,-9709),(1205,-9927), (0,-10000),(-1205,-9927),(-2393,-9709),(-3546,-9350),(-4647,-8855),(-5681,-8230),(-6631,-7485), (-7485,-6631),(-8230,-5681),(-8855,-4647),(-9350,-3546),(-9709,-2393),(-9927,-1205), (-10000,0),(-9927,1205),(-9709,2393),(-9350,3546),(-8855,4647),(-8230,5681),(-7485,6631), (-6631,7485),(-5681,8230),(-4647,8855),(-3546,9350),(-2393,9709),(-1205,9927)); VAR I,X1,Y1,X2,Y2:Integer; A2:Arr52; BEGIN A2:=A; FOR I:=1 TO 52 DO BEGIN A2[I,1]:=X+Round(A2[I,1]/10000*R1); A2[I,2]:=Y+Round(A2[I,2]/10000*R2); END; FillPolygon(52,A2,C); END; PROCEDURE SetFrameColor(C:Byte); BEGIN ASM mov ax,$1001 mov bh,[bp+offset c] int $10 END; END; PROCEDURE RecTangle(X1,Y1,X2,Y2:Integer; C:Byte); BEGIN DrawLineH(X1,X2,Y1,C); DrawLineH(X1,X2,Y2,C); DrawLineV(X1,Y1,Y2,C); DrawLineV(X2,Y1,Y2,C); END; PROCEDURE GetImage(X1,Y1,X2,Y2:Integer; VAR P); VAR Data:ARRAY[0..64003] OF Byte ABSOLUTE P; I,XS,YS:Word; P2:Pointer ABSOLUTE P; BEGIN XS:=X2-X1; YS:=Y2-Y1; Data[0]:=Lo(XS); Data[1]:=Hi(XS); Data[2]:=Lo(YS); Data[3]:=Hi(YS); FOR I:=0 TO YS DO Move(Ptr($A000,(Y1+I)*320+X1)^,Data[(XS+1)*I+4],XS+1); END; { PROCEDURE PutImage(X1,Y1:Integer; VAR P); VAR Data:ARRAY[0..64003] OF Byte ABSOLUTE P; I,XS,YS:Word; BEGIN XS:=Data[0]+Data[1] SHL 8; YS:=Data[2]+Data[3] SHL 8; FOR I:=0 TO YS DO Move(Data[(XS+1)*I+4],Ptr($A000,(Y1+I)*320+X1)^,XS+1); END; } PROCEDURE PutImage(X1,Y1:Integer; VAR P); VAR Data:ARRAY[0..64003] OF Byte ABSOLUTE P; Adr,I,XS,YS:Word; DataDS,DataSI:Word; BEGIN XS:=Data[0]+Data[1] SHL 8; YS:=Data[2]+Data[3] SHL 8; Adr:=Word(Y1)*320+X1; DataDS:=Seg(Data[4]); DataSI:=Ofs(Data[4]); ASM mov dx,ys inc dx mov bx,xs inc bx mov ax,$a000 mov es,ax mov di,adr mov si,DataSI mov ax,DataDS push ds mov ds,ax cld @1: mov cx,bx rep movsb add di,320 sub di,bx dec dx jnz @1 pop ds END; { FOR I:=0 TO YS DO Move(Data[(XS+1)*I+4],Ptr($A000,(Y1+I)*320+X1)^,XS+1); } END; PROCEDURE PutImagePart(X1,Y1,XS2,YS2:Integer; VAR P); VAR Data:ARRAY[0..64003] OF Byte ABSOLUTE P; Adr,I,XS,YS:Word; DataDS,DataSI:Word; BEGIN XS:=Data[0]+Data[1] SHL 8+1; YS:=Data[2]+Data[3] SHL 8+1; IF (XS2<0) OR (XS2>XS) THEN XS2:=XS; IF (YS2<0) OR (YS2>YS) THEN YS2:=YS; Adr:=Word(Y1)*320+X1; DataDS:=Seg(Data[4]); DataSI:=Ofs(Data[4]); ASM mov dx,ys mov bx,xs2 mov ax,$a000 mov es,ax mov di,adr mov si,DataSI mov ax,DataDS mov cx,xs sub cx,xs2 push ds mov ds,ax mov ax,cx cld @1: mov cx,bx rep movsb add di,320 sub di,bx add si,ax dec dx jnz @1 pop ds END; { FOR I:=0 TO YS DO Move(Data[(XS+1)*I+4],Ptr($A000,(Y1+I)*320+X1)^,XS+1); } END; PROCEDURE FillBlock(X1,Y1,X2,Y2:Integer; C:Byte); VAR Y:Integer; BEGIN FOR Y:=Y1 TO Y2 DO DrawLineH(X1,X2,Y,C); END; PROCEDURE ScrollLeft(X1,Y1,X2,Y2:Word); BEGIN ASM push ds mov ax,$a000 mov es,ax mov ds,ax mov si,[bp+offset y1] mov cx,[bp+offset y2] sub cx,si inc cx mov ax,320 mul si mov bx,[bp+offset x1] add ax,bx mov dx,[bp+offset x2] sub dx,bx inc dx cld @1: mov bx,cx mov di,ax dec di mov si,ax mov cx,dx rep movsb mov cx,bx add ax,320 loop @1 pop ds END; END; PROCEDURE ScrollRight(X1,Y1,X2,Y2:Word); BEGIN ASM push ds mov ax,$a000 mov es,ax mov ds,ax mov si,[bp+offset y1] mov cx,[bp+offset y2] sub cx,si inc cx mov ax,320 mul si mov bx,[bp+offset x1] mov dx,[bp+offset x2] add ax,dx sub dx,bx inc dx std @1: mov bx,cx mov di,ax mov si,ax dec si mov cx,dx rep movsb mov cx,bx add ax,320 loop @1 cld pop ds END; END; PROCEDURE ScrollUp(X1,Y1,X2,Y2:Word); BEGIN ASM push ds mov ax,$a000 mov es,ax mov ds,ax mov si,[bp+offset y1] mov cx,[bp+offset y2] sub cx,si inc cx mov ax,320 mul si mov bx,[bp+offset x1] add ax,bx mov dx,[bp+offset x2] sub dx,bx inc dx cld @1: mov bx,cx mov di,ax sub di,320 mov si,ax mov cx,dx rep movsb mov cx,bx add ax,320 loop @1 pop ds END; END; PROCEDURE ScrollDown(X1,Y1,X2,Y2:Word); BEGIN ASM push ds mov ax,$a000 mov es,ax mov ds,ax mov si,[bp+offset y1] mov cx,[bp+offset y2] mov ax,320 mul cx sub cx,si inc cx mov bx,[bp+offset x1] mov dx,[bp+offset x2] add ax,bx sub dx,bx inc dx cld @1: mov bx,cx mov di,ax mov si,ax sub si,320 mov cx,dx rep movsb mov cx,bx sub ax,320 loop @1 pop ds END; END; PROCEDURE Scroll(Direction:Byte; X1,Y1,X2,Y2:Word); BEGIN CASE Direction OF Up:ScrollUp(X1,Y1,X2,Y2); Right:ScrollRight(X1,Y1,X2,Y2); Down:ScrollDown(X1,Y1,X2,Y2); Left:ScrollLeft(X1,Y1,X2,Y2); END; END; PROCEDURE SwitchOff; ASSEMBLER; ASM mov dx,$3c4 mov al,1 out dx,al inc dx in al,dx or al,$20 out dx,al END; PROCEDURE SwitchOn; ASSEMBLER; ASM mov dx,$3c4 mov al,1 out dx,al inc dx in al,dx and al,$df out dx,al END; PROCEDURE LoadPalette(DateiName:String); VAR Datei:File; RGB:ARRAY[0..255,1..3] OF Byte; I:Byte; BEGIN Assign(Datei,DateiName+'.PAL'); Reset(Datei,1); BlockRead(Datei,RGB,768); SwitchOff; FOR I:=0 TO 255 DO SetColor(I,RGB[I,1],RGB[I,2],RGB[I,3]); SwitchOn; END; PROCEDURE SavePalette(DateiName:String); VAR Datei:File; RGB:ARRAY[0..255,1..3] OF Byte; I:Byte; BEGIN Assign(Datei,DateiName+'.PAL'); Rewrite(Datei,1); FOR I:=0 TO 255 DO GetColor(I,RGB[I,1],RGB[I,2],RGB[I,3]); BlockWrite(Datei,RGB,768); END; PROCEDURE LoadScreen(DateiName:String); VAR Datei:File; RGB:ARRAY[0..255,1..3] OF Byte; I:Byte; BEGIN Assign(Datei,DateiName+'.BLD'); Reset(Datei,1); BlockRead(Datei,RGB,768); SwitchOff; FOR I:=0 TO 255 DO SetColor(I,RGB[I,1],RGB[I,2],RGB[I,3]); BlockRead(Datei,Ptr($A000,0)^,64000); SwitchOn; Close(Datei); END; PROCEDURE SaveScreen(DateiName:String); VAR Datei:File; RGB:ARRAY[0..255,1..3] OF Byte; I:Byte; BEGIN Assign(Datei,DateiName+'.BLD'); Rewrite(Datei,1); FOR I:=0 TO 255 DO GetColor(I,RGB[I,1],RGB[I,2],RGB[I,3]); BlockWrite(Datei,RGB,768); BlockWrite(Datei,Ptr($A000,0)^,64000); Close(Datei); END; PROCEDURE BCircle(X,Y,R:Integer; C:Byte); VAR XX4,XX,YY,D:Integer; BEGIN XX:=0; YY:=R; D:=3-(2*R); WHILE XX<=YY DO BEGIN SetPixel(X+XX,Y+YY,C); SetPixel(X-XX,Y+YY,C); SetPixel(X+XX,Y-YY,C); SetPixel(X-XX,Y-YY,C); SetPixel(X+YY,Y+XX,C); SetPixel(X-YY,Y+XX,C); SetPixel(X+YY,Y-XX,C); SetPixel(X-YY,Y-XX,C); XX4:=XX SHL 2; IF D<0 THEN Inc(D,XX4+6) ELSE BEGIN Inc(D,XX4-YY SHL 2+10); Dec(YY); END; Inc(XX); END; END; PROCEDURE BFillCircle(X,Y,R:Integer; C:Byte); VAR XX4,XX,YY,D:Integer; BEGIN XX:=0; YY:=R; D:=3-(2*R); WHILE XX<=YY DO BEGIN DrawLineH(X-XX,X+XX,Y+YY,C); DrawLineH(X-XX,X+XX,Y-YY,C); DrawLineH(X-YY,X+YY,Y+XX,C); DrawLineH(X-YY,X+YY,Y-XX,C); XX4:=XX SHL 2; IF D<0 THEN Inc(D,XX4+6) ELSE BEGIN Inc(D,XX4-YY SHL 2+10); Dec(YY); END; Inc(XX); END; END; PROCEDURE Split(Row:Integer); BEGIN ASM mov dx,$3d4 mov ax,row mov bh,ah mov bl,ah and bx,201h mov cl,4 shl bx,cl mov ah,al mov al,18h out dx,ax mov al,7 cli out dx,al inc dx in al,dx sti dec dx mov ah,al and ah,0efh or ah,bl mov al,7 out dx,ax mov al,9 cli out dx,al inc dx in al,dx sti dec dx mov ah,al and ah,0bfh shl bh,1 shl bh,1 or ah,bh mov al,9 out dx,ax END; END; PROCEDURE ScrollText(Nr:Word); BEGIN ASM mov ax,nr push es push cx push dx mov cx,$40 mov es,cx mov cl,es:[$85] div cl mov cx,ax mov dx,es:[$63] push dx mov al,$13 cli out dx,al jmp @1 @1: inc dx in al,dx sti mul cl shl ax,1 mov es:[$4e],ax pop dx mov cl,al mov al,$c out dx,ax jmp @2 @2: mov al,$d mov ah,cl out dx,ax jmp @3 @3: mov ah,ch mov al,8 out dx,ax pop dx pop cx pop es END; END; PROCEDURE SetStart(S:Word); BEGIN ASM mov bx,s mov dx,$3d4 mov al,$c mov ah,bh out dx,ax inc ax mov ah,bl out dx,ax END; END; PROCEDURE VerticalRetrace; BEGIN ASM mov dx,3dah @1: in al,dx test al,8 jz @1 @2: in al,dx test al,8 jnz @2 END; END; PROCEDURE WaitScreen; BEGIN ASM mov dx,3dah @1: in al,dx test al,8 jnz @1 END; END; PROCEDURE WaitRetrace; BEGIN ASM mov dx,3dah @1: in al,dx test al,8 jz @1 END; END; PROCEDURE SetOffset(B:Byte); BEGIN ASM mov dx,$3d4 mov al,$13 mov ah,b out dx,ax END; END; PROCEDURE LoadSprite(DateiName:String; VAR P); VAR Datei:File; Size,I:Word; P2:Pointer ABSOLUTE P; BEGIN Assign(Datei,DateiName+'.SPR'); Reset(Datei,1); Size:=FileSize(Datei); GetMem(P2,Size+15); IF Ofs(P2^)<>0 THEN P2:=Ptr(Seg(P2^)+1,0); BlockRead(Datei,P2^,Size); Close(Datei); END; PROCEDURE SaveSprite(DateiName:String; VAR P); VAR A:ARRAY[-4..32000] OF Byte ABSOLUTE P; Datei:File; Size,I:Word; XS,YS:Word; BEGIN XS:=A[-4]+A[-3] SHL 8; YS:=A[-2]+A[-1] SHL 8; Assign(Datei,DateiName+'.SPR'); Rewrite(Datei,1); Size:=(XS+1)*(YS+1)+4; BlockWrite(Datei,A,Size); Close(Datei); END; PROCEDURE FillScreen(C:Byte); BEGIN ASM mov ax,$a000 mov es,ax mov al,c mov ah,al cld xor di,di mov cx,32000 rep stosw END; END; PROCEDURE Unchain; BEGIN PortW[$3C4]:=$0604; PortW[$3D4]:=$0014; PortW[$3D4]:=$E317; PortW[$3C4]:=$0F02; END; PROCEDURE Rechain; BEGIN PortW[$3C4]:=$0E04; PortW[$3C4]:=$0100; PortW[$3C4]:=$0300; PortW[$3D4]:=$4014; PortW[$3D4]:=$A317; END; PROCEDURE ClearScreen; BEGIN PortW[$3C4]:=$0F02; ASM mov ax,$a000 mov es,ax mov cx,16383 db $66 xor ax,ax xor di,di cld db $66 rep stosw END; END; PROCEDURE SetChain4; BEGIN Port[$3CE]:=$05; Port[$3CF]:=Port[$3CF] AND $EF; Port[$3CE]:=$06; Port[$3CF]:=Port[$3CF] AND $FD; Port[$3C4]:=$04; Port[$3C5]:=Port[$3C5] AND $F7; Port[$3D4]:=$14; Port[$3D5]:=Port[$3D5] AND $BF; Port[$3D4]:=$17; Port[$3D5]:=Port[$3D5] OR $40; END; PROCEDURE ClearChain4; BEGIN ASM mov ax,$a000 mov es,ax mov cx,32768 xor di,di cld xor ax,ax rep stosw END; END; PROCEDURE CharHeight(B:Byte); BEGIN Port[$3D4]:=$09; Port[$3D5]:=(Port[$3D5] AND $E0) OR B; END; PROCEDURE Wait4Line; BEGIN ASM mov dx,$3da @1: in al,dx test al,1 jnz @1 @2: in al,dx test al,1 jz @2 END; END; PROCEDURE CLI; ASSEMBLER; ASM cli END; PROCEDURE STI; ASSEMBLER; ASM sti END; PROCEDURE SetWriteMap(Map:Byte); BEGIN Port[$3C4]:=2; Port[$3C5]:=Map; END; PROCEDURE PutImage4(X1,Y1:Integer; VAR P); VAR Data:ARRAY[0..64003] OF Byte ABSOLUTE P; Adr,I,J,K,XS,YS:Word; DataDS,DataSI:Word; BEGIN XS:=Data[0]+Data[1] SHL 8; YS:=Data[2]+Data[3] SHL 8; DataDS:=Seg(Data); FOR J:=0 TO YS DO BEGIN DataSI:=Ofs(Data)+4+(XS+1)*J; FOR K:=0 TO 3 DO BEGIN Adr:=Word(Y1+J)*80+(X1+K) SHR 2; SetWriteMap(1 SHL ((X1+K) AND 3)); ASM push ds mov ax,$a000 mov es,ax mov di,adr mov cx,xs shr cx,2 inc cx mov si,datasi mov ax,datads mov ds,ax mov bx,3 cld @1: movsb add si,bx loop @1 pop ds END; Inc(DataSI); END; END; END; FUNCTION SpriteXSize(Sprite:Pointer):Word; BEGIN ASM push ds lds si,sprite lodsw inc ax mov @result,ax pop ds END; END; FUNCTION SpriteYSize(Sprite:Pointer):Word; BEGIN ASM push ds lds si,sprite lodsw lodsw inc ax mov @result,ax pop ds END; END; FUNCTION SpriteSize(Sprite:Pointer):Word; BEGIN ASM push ds lds si,sprite lodsw inc ax mov bx,ax lodsw inc ax mul bx add ax,4 mov @result,ax pop ds END; END; PROCEDURE SetWriteMode(M:Byte); BEGIN Port[$3CE]:=$05; Port[$3CF]:=(Port[$3CF] AND $FC) OR (M AND 3); END; PROCEDURE SetModeNr(Nr:Word); BEGIN ASM mov ax,nr int $10 END; END; PROCEDURE Set16Pal(Nr:Byte); VAR I:Byte; BEGIN I:=Port[$3DA]; Port[$3C0]:=$34; Port[$3C0]:=Nr; END; PROCEDURE Init16Pal; VAR I:Byte; BEGIN I:=Port[$3DA]; FOR I:=0 TO 15 DO BEGIN Port[$3C0]:=I; Port[$3C0]:=I; END; Port[$3C0]:=$10; Port[$3C0]:=$81; Set16Pal(0); END; PROCEDURE Init13X; BEGIN MCGAOn; Unchain; END; PROCEDURE TextMode; BEGIN ASM mov ax,3 int 10h END; END; PROCEDURE SetLineRepeat(Nr:Byte); BEGIN Port[$3C4]:=9; Port[$3C5]:=(Port[$3C5] AND $F0)+Nr; END; PROCEDURE SetReadMap(Map:Byte); BEGIN Port[$3C4]:=4; Port[$3C5]:=Map; END; PROCEDURE DrawLineH4(X1,X2,Y1:Word; C:Byte); VAR Adresse:LongInt; PROCEDURE DrawLineH4X(X1,X2,Y1:Word; C:Byte); BEGIN ASM mov ax,$a000 mov es,ax mov ax,[bp+offset y1] mov bx,800 mul bx add ax,[bp+offset x1] adc dx,0 mov di,$3cd xchg di,ax xchg ax,dx or al,$40 out dx,al mov bx,[bp+offset x1] mov dx,[bp+offset x2] inc dx mov cx,dx sub cx,bx shr cx,1 mov al,[bp+offset c] mov ah,al ror bx,1 jnb @2 stosb ror dx,1 jnb @3 dec cx @3: rol dx,1 @2: rep stosw ror dx,1 jnb @4 stosb @4: END; END; BEGIN Adresse:=LongInt(Y1)*800; IF (Adresse+X1) SHR 16<>(Adresse+X2) SHR 16 THEN BEGIN DrawLineH4X(X1,65535-Word(Y1*800),Y1,C); DrawLineH4X(Word(-Word(Y1*800)),X2,Y1,C); END ELSE DrawLineH4X(X1,X2,Y1,C); END; PROCEDURE DrawLineV4(X1,Y1,Y2:Word; C:Byte); VAR Adresse:LongInt; Y:Word; A:Byte; PROCEDURE DrawLineV4X(X1,Y1,Y2:Word; C:Byte); BEGIN ASM mov bx,[bp+offset x1] mov ax,[bp+offset y1] mov cx,800 mul cx add ax,bx adc dx,0 mov di,$3cd xchg di,ax xchg ax,dx or al,$40 out dx,al mov dx,[bp+offset y2] mov cx,$a000 mov es,cx mov cx,dx sub cx,[bp+offset y1] inc cx mov al,[bp+offset c] mov bx,799 @2: stosb add di,bx loop @2 END; END; BEGIN Y:=Y1; WHILE (LongInt(Y)*800+X1) SHR 16<>(LongInt(Y2)*800+X1) SHR 16 DO BEGIN A:=(LongInt(Y)*800+X1) SHR 16; DrawLineV4X(X1,Y,(LongInt(A+1)*65536-1-X1) DIV 800,C); Y:=(LongInt(A+1)*65536-1-X1) DIV 800+1; END; DrawLineV4X(X1,Y,Y2,C); END; PROCEDURE SetHorizOfs(Count:Byte); BEGIN Port[$3C0]:=$13; Port[$3C0]:=Count SHL 1; END; { PROCEDURE SetReg(Reg:Word; Index,Value:Byte); VAR B:Byte; BEGIN CASE Reg OF $3C0:BEGIN B:=Port[$3DA]; Port[$3C0]:=Index OR $20; } END.