home *** CD-ROM | disk | FTP | other *** search
- {$A+,B-,D+,L+,N-,E-,O-,R-,S-,V-,G-,F-,I-,X-}
- {$M 16384,0,655360}
-
- {Programmtool zur Realisierung schneller Animationen auf der VGA-Grafik- }
- {karte von: Kai Rohrbacher, 1988-1991, Turbo-Pascal 6.0 }
-
- { Features: }
-
- { - flickerfreie Animation durch page-flipping, Auswertung von Retrace- }
- { signalen und Verwendung eines speziellen VGA-256-Farbengrafikmodus }
- { - Spritebewegung pixelweise (und nicht nur byteweise) moeglich }
- { - beliebiges Hintergrundbild, vor der die Animation geschieht }
- { - volle Unterstuetzung der 256-Farbmoeglichkeiten der VGA-Karte }
- { - verschiedene Spritedarstellungsmoeglichkeiten: }
- { - Sprites koennen pixelweise als durchsichtig gegenueber dem Hintergrund}
- { deklariert werden }
- { - Sprites koennen ihre Farbe in Abhaengigkeit ihres momentanen Hinter- }
- { grundes veraendern ("Schattenfunktion") }
- { - Routine zur exakten Feststellung der Kollision zweier Sprites }
- { - Sprites werden beim Verschwinden an einer der Bildschirmgrenzen korrekt }
- { abgeschnitten }
- { - Verwaltung von bis zu 32767 verschiedenen Sprites (Voreinstellung: 1000)}
- { - gleichzeitige Darstellung von bis zu 32767 Sprites (Voreinstellung: 500)}
- { - maximale Spritegroesse 64k }
- { - maximaler Umfang aller Sprites zusammen nur durch Hauptspeicher begrenzt}
- { - arbeitet mit virtuellen Koordinaten im Bereich -16000..+16000, daher }
- { einfaches horizontales und vertikales Scrolling moeglich }
- { - Scrollbares Hintergrundbild ebenfalls unterstuetzt }
- { - viele unterstuetzende Routinen: zeichnen von Linien (mit eingebautem }
- { Clipping-Algorithmus), Punkten und Grafik-Text (dto.), automatische Ver-}
- { waltungs des Heaps zum Speichern/Laden von Sprites, Hintergrundbildern, }
- { Aendern von Spritedarstellungsmodi waehrend der Laufzeit, Geschwindig- }
- { keitsanpassung an unterschiedlich schnelle Rechner, ... }
-
- UNIT ANIVGA;
- INTERFACE
-
- USES CRT,DOS;
-
- CONST ANIVGAVersion=11; {Versionsnummer}
- NMAX=499;
- XMAX=319;
- YMAX=199;
- LoadMAX=1000; {max. Anzahl an gleichzeitig geladenenen Sprites}
- LINESIZE=(XMAX+1) DIV 4; {Groesse einer Zeile=80 Bytes}
- PAGESIZE=(YMAX+1)*LINESIZE; {200 Zeilen zu je 320/4 Bytes}
- BACKGNDPAGE=2;
- SCROLLPAGE=3;
-
- STATIC=0; {Konstanten fuer Hintergrundart}
- SCROLLING=1;
-
- MaxTiles=10000; {max. Anzahl an Hintergrund-Kacheln}
- StartVirtualX:INTEGER=0; {obere linke Bildschirmecke}
- StartVirtualY:INTEGER=0;
-
- {unterstuetzte Darstellungsmodi der Sprites: }
- Display_NORMAL=0; {normal : durchsichtig fuer Farbe 0}
- Display_FAST =1; {schnell : keine Hintergrundberuecksichtigung}
- Display_SHADOW=2; {Schatten: Farbumsetzung anhand des Hintergrundes}
- Display_SHADOWEXACT=3; {Farbe 0 ist auch fuer Schatten durchsichtig}
- Display_UNKNOWN=255;{Fehlerwert}
-
- {Fehlercodes des Animationspaketes: }
- Err_None=0;
- Err_NotEnoughMemory=1;
- Err_FileIO=2;
- Err_InvalidSpriteNumber=3;
- Err_NoSprite=4;
- Err_InvalidPageNumber=5;
- Err_NoVGA=6;
- Err_NoPicture=7;
- Err_InvalidPercentage=8;
- Err_NoTile=9;
- Err_InvalidTileNumber=10;
- Err_InvalidCoordinates=11;
- Err_BackgroundToBig=12;
- Err_InvalidMode=13;
- Err_InvalidSpriteLoadNumber=14;
- Err_NoPalette=15;
- Err_PaletteWontFit=16;
- Err_InvalidFade=17;
-
- TYPE FontChar=ARRAY[0..5] OF BYTE;
- Font=ARRAY[0..255] OF Fontchar;
- FontOrient=(horizontal,vertical); {moegliche Textausgaberichtungen}
- CONST GraphTextOrientation:FontOrient=horizontal; {aktuelle Ausgaberichtung}
- GraphTextColor:BYTE=white; {aktuelle Textausgabefarben}
- GraphTextBackground:BYTE=white;
- FontHeight=6;
- FontWidth=6;
-
- TYPE Table=ARRAY[0..NMAX] OF INTEGER;
- ColorTable=ARRAY[0..255] OF BYTE;
-
- TYPE PaletteEntry=RECORD red,green,blue:BYTE END;
- Palette=ARRAY[0..255] OF PaletteEntry;
- PalettePtr=^Palette;
-
- CONST DefaultColors:Palette= {Defaultfarben-Palette des 256-Farbmodus}
- ( {ausgelesen mithilfe des BIOS-Aufrufs: }
- (red: 0; green: 0; blue: 0), { MOV AX,1017h ;lese Palettenregister}
- (red: 0; green: 0; blue: 42), { XOR BX,BX ;von Farbe 0 an }
- (red: 0; green: 42; blue: 0), { MOV CX,100h ;alle 256 Farben}
- (red: 0; green: 42; blue: 42), { LES DX,Ziel ;nach ES:DX }
- (red: 42; green: 0; blue: 0), { INT 10h }
- (red: 42; green: 0; blue: 42), {Achtung! Die Werte koenn(t)en nur dann }
- (red: 42; green: 21; blue: 0), {ausgelesen werden, wenn der Grafikmodus}
- (red: 42; green: 42; blue: 42), {bereits aktiv ist, deshalb wurden sie }
- (red: 21; green: 21; blue: 21), {hier "statisch" aufgenommen!}
- (red: 21; green: 21; blue: 63),
- (red: 21; green: 63; blue: 21),
- (red: 21; green: 63; blue: 63),
- (red: 63; green: 21; blue: 21),
- (red: 63; green: 21; blue: 63),
- (red: 63; green: 63; blue: 21),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 0),
- (red: 5; green: 5; blue: 5),
- (red: 8; green: 8; blue: 8),
- (red: 11; green: 11; blue: 11),
- (red: 14; green: 14; blue: 14),
- (red: 17; green: 17; blue: 17),
- (red: 20; green: 20; blue: 20),
- (red: 24; green: 24; blue: 24),
- (red: 28; green: 28; blue: 28),
- (red: 32; green: 32; blue: 32),
- (red: 36; green: 36; blue: 36),
- (red: 40; green: 40; blue: 40),
- (red: 45; green: 45; blue: 45),
- (red: 50; green: 50; blue: 50),
- (red: 56; green: 56; blue: 56),
- (red: 63; green: 63; blue: 63),
- (red: 0; green: 0; blue: 63),
- (red: 16; green: 0; blue: 63),
- (red: 31; green: 0; blue: 63),
- (red: 47; green: 0; blue: 63),
- (red: 63; green: 0; blue: 63),
- (red: 63; green: 0; blue: 47),
- (red: 63; green: 0; blue: 31),
- (red: 63; green: 0; blue: 16),
- (red: 63; green: 0; blue: 0),
- (red: 63; green: 16; blue: 0),
- (red: 63; green: 31; blue: 0),
- (red: 63; green: 47; blue: 0),
- (red: 63; green: 63; blue: 0),
- (red: 47; green: 63; blue: 0),
- (red: 31; green: 63; blue: 0),
- (red: 16; green: 63; blue: 0),
- (red: 0; green: 63; blue: 0),
- (red: 0; green: 63; blue: 16),
- (red: 0; green: 63; blue: 31),
- (red: 0; green: 63; blue: 47),
- (red: 0; green: 63; blue: 63),
- (red: 0; green: 47; blue: 63),
- (red: 0; green: 31; blue: 63),
- (red: 0; green: 16; blue: 63),
- (red: 31; green: 31; blue: 63),
- (red: 39; green: 31; blue: 63),
- (red: 47; green: 31; blue: 63),
- (red: 55; green: 31; blue: 63),
- (red: 63; green: 31; blue: 63),
- (red: 63; green: 31; blue: 55),
- (red: 63; green: 31; blue: 47),
- (red: 63; green: 31; blue: 39),
- (red: 63; green: 31; blue: 31),
- (red: 63; green: 39; blue: 31),
- (red: 63; green: 47; blue: 31),
- (red: 63; green: 55; blue: 31),
- (red: 63; green: 63; blue: 31),
- (red: 55; green: 63; blue: 31),
- (red: 47; green: 63; blue: 31),
- (red: 39; green: 63; blue: 31),
- (red: 31; green: 63; blue: 31),
- (red: 31; green: 63; blue: 39),
- (red: 31; green: 63; blue: 47),
- (red: 31; green: 63; blue: 55),
- (red: 31; green: 63; blue: 63),
- (red: 31; green: 55; blue: 63),
- (red: 31; green: 47; blue: 63),
- (red: 31; green: 39; blue: 63),
- (red: 45; green: 45; blue: 63),
- (red: 49; green: 45; blue: 63),
- (red: 54; green: 45; blue: 63),
- (red: 58; green: 45; blue: 63),
- (red: 63; green: 45; blue: 63),
- (red: 63; green: 45; blue: 58),
- (red: 63; green: 45; blue: 54),
- (red: 63; green: 45; blue: 49),
- (red: 63; green: 45; blue: 45),
- (red: 63; green: 49; blue: 45),
- (red: 63; green: 54; blue: 45),
- (red: 63; green: 58; blue: 45),
- (red: 63; green: 63; blue: 45),
- (red: 58; green: 63; blue: 45),
- (red: 54; green: 63; blue: 45),
- (red: 49; green: 63; blue: 45),
- (red: 45; green: 63; blue: 45),
- (red: 45; green: 63; blue: 49),
- (red: 45; green: 63; blue: 54),
- (red: 45; green: 63; blue: 58),
- (red: 45; green: 63; blue: 63),
- (red: 45; green: 58; blue: 63),
- (red: 45; green: 54; blue: 63),
- (red: 45; green: 49; blue: 63),
- (red: 0; green: 0; blue: 28),
- (red: 7; green: 0; blue: 28),
- (red: 14; green: 0; blue: 28),
- (red: 21; green: 0; blue: 28),
- (red: 28; green: 0; blue: 28),
- (red: 28; green: 0; blue: 21),
- (red: 28; green: 0; blue: 14),
- (red: 28; green: 0; blue: 7),
- (red: 28; green: 0; blue: 0),
- (red: 28; green: 7; blue: 0),
- (red: 28; green: 14; blue: 0),
- (red: 28; green: 21; blue: 0),
- (red: 28; green: 28; blue: 0),
- (red: 21; green: 28; blue: 0),
- (red: 14; green: 28; blue: 0),
- (red: 7; green: 28; blue: 0),
- (red: 0; green: 28; blue: 0),
- (red: 0; green: 28; blue: 7),
- (red: 0; green: 28; blue: 14),
- (red: 0; green: 28; blue: 21),
- (red: 0; green: 28; blue: 28),
- (red: 0; green: 21; blue: 28),
- (red: 0; green: 14; blue: 28),
- (red: 0; green: 7; blue: 28),
- (red: 14; green: 14; blue: 28),
- (red: 17; green: 14; blue: 28),
- (red: 21; green: 14; blue: 28),
- (red: 24; green: 14; blue: 28),
- (red: 28; green: 14; blue: 28),
- (red: 28; green: 14; blue: 24),
- (red: 28; green: 14; blue: 21),
- (red: 28; green: 14; blue: 17),
- (red: 28; green: 14; blue: 14),
- (red: 28; green: 17; blue: 14),
- (red: 28; green: 21; blue: 14),
- (red: 28; green: 24; blue: 14),
- (red: 28; green: 28; blue: 14),
- (red: 24; green: 28; blue: 14),
- (red: 21; green: 28; blue: 14),
- (red: 17; green: 28; blue: 14),
- (red: 14; green: 28; blue: 14),
- (red: 14; green: 28; blue: 17),
- (red: 14; green: 28; blue: 21),
- (red: 14; green: 28; blue: 24),
- (red: 14; green: 28; blue: 28),
- (red: 14; green: 24; blue: 28),
- (red: 14; green: 21; blue: 28),
- (red: 14; green: 17; blue: 28),
- (red: 20; green: 20; blue: 28),
- (red: 22; green: 20; blue: 28),
- (red: 24; green: 20; blue: 28),
- (red: 26; green: 20; blue: 28),
- (red: 28; green: 20; blue: 28),
- (red: 28; green: 20; blue: 26),
- (red: 28; green: 20; blue: 24),
- (red: 28; green: 20; blue: 22),
- (red: 28; green: 20; blue: 20),
- (red: 28; green: 22; blue: 20),
- (red: 28; green: 24; blue: 20),
- (red: 28; green: 26; blue: 20),
- (red: 28; green: 28; blue: 20),
- (red: 26; green: 28; blue: 20),
- (red: 24; green: 28; blue: 20),
- (red: 22; green: 28; blue: 20),
- (red: 20; green: 28; blue: 20),
- (red: 20; green: 28; blue: 22),
- (red: 20; green: 28; blue: 24),
- (red: 20; green: 28; blue: 26),
- (red: 20; green: 28; blue: 28),
- (red: 20; green: 26; blue: 28),
- (red: 20; green: 24; blue: 28),
- (red: 20; green: 22; blue: 28),
- (red: 0; green: 0; blue: 16),
- (red: 4; green: 0; blue: 16),
- (red: 8; green: 0; blue: 16),
- (red: 12; green: 0; blue: 16),
- (red: 16; green: 0; blue: 16),
- (red: 16; green: 0; blue: 12),
- (red: 16; green: 0; blue: 8),
- (red: 16; green: 0; blue: 4),
- (red: 16; green: 0; blue: 0),
- (red: 16; green: 4; blue: 0),
- (red: 16; green: 8; blue: 0),
- (red: 16; green: 12; blue: 0),
- (red: 16; green: 16; blue: 0),
- (red: 12; green: 16; blue: 0),
- (red: 8; green: 16; blue: 0),
- (red: 4; green: 16; blue: 0),
- (red: 0; green: 16; blue: 0),
- (red: 0; green: 16; blue: 4),
- (red: 0; green: 16; blue: 8),
- (red: 0; green: 16; blue: 12),
- (red: 0; green: 16; blue: 16),
- (red: 0; green: 12; blue: 16),
- (red: 0; green: 8; blue: 16),
- (red: 0; green: 4; blue: 16),
- (red: 8; green: 8; blue: 16),
- (red: 10; green: 8; blue: 16),
- (red: 12; green: 8; blue: 16),
- (red: 14; green: 8; blue: 16),
- (red: 16; green: 8; blue: 16),
- (red: 16; green: 8; blue: 14),
- (red: 16; green: 8; blue: 12),
- (red: 16; green: 8; blue: 10),
- (red: 16; green: 8; blue: 8),
- (red: 16; green: 10; blue: 8),
- (red: 16; green: 12; blue: 8),
- (red: 16; green: 14; blue: 8),
- (red: 16; green: 16; blue: 8),
- (red: 14; green: 16; blue: 8),
- (red: 12; green: 16; blue: 8),
- (red: 10; green: 16; blue: 8),
- (red: 8; green: 16; blue: 8),
- (red: 8; green: 16; blue: 10),
- (red: 8; green: 16; blue: 12),
- (red: 8; green: 16; blue: 14),
- (red: 8; green: 16; blue: 16),
- (red: 8; green: 14; blue: 16),
- (red: 8; green: 12; blue: 16),
- (red: 8; green: 10; blue: 16),
- (red: 11; green: 11; blue: 16),
- (red: 12; green: 11; blue: 16),
- (red: 13; green: 11; blue: 16),
- (red: 15; green: 11; blue: 16),
- (red: 16; green: 11; blue: 16),
- (red: 16; green: 11; blue: 15),
- (red: 16; green: 11; blue: 13),
- (red: 16; green: 11; blue: 12),
- (red: 16; green: 11; blue: 11),
- (red: 16; green: 12; blue: 11),
- (red: 16; green: 13; blue: 11),
- (red: 16; green: 15; blue: 11),
- (red: 16; green: 16; blue: 11),
- (red: 15; green: 16; blue: 11),
- (red: 13; green: 16; blue: 11),
- (red: 12; green: 16; blue: 11),
- (red: 11; green: 16; blue: 11),
- (red: 11; green: 16; blue: 12),
- (red: 11; green: 16; blue: 13),
- (red: 11; green: 16; blue: 15),
- (red: 11; green: 16; blue: 16),
- (red: 11; green: 15; blue: 16),
- (red: 11; green: 13; blue: 16),
- (red: 11; green: 12; blue: 16),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0),
- (red: 0; green: 0; blue: 0)
- );
-
- VAR Error:BYTE; {globale Fehlervariable}
- SpriteN:Table;
- SpriteX:Table;
- SpriteY:Table;
- NextSprite:ARRAY[0..LoadMAX] OF WORD;
- SPRITEAD:ARRAY[0..LoadMAX] OF WORD;
- PAGE,PAGEADR,SCROLLADR,BACKGNDADR:WORD;
- Color:BYTE; {Zeichenfarbe fuer Linien}
- ActualColors:Palette; {aktuelle Farbpalette}
- was_cut:BOOLEAN; {TRUE/FALSE, falls "GetImage" clippen musste }
- left_cut, {Var., die durch "GetImage" gesetzt werden und}
- right_cut, {bei "was_cut"=TRUE darueber Auskunft geben, }
- top_cut, {wo und wieviel des Bildes abgeschnitten wer- }
- bottom_cut:WORD; {den musste }
-
- BackgroundMode:BYTE;
- BackTile:ARRAY[0..MaxTiles] OF BYTE; {Kachelnspeicher}
- XTiles,YTiles:INTEGER; {Breite,Hoehe des def. Bereiches}
- BackX1,BackY1,BackX2,BackY2:INTEGER; {Koordinaten des def. Bereiches }
-
- CONST Fade_Squares =0;
- Fade_Moiree1 =1;
- Fade_Moiree2 =2;
- Fade_Moiree3 =3;
- Fade_Moiree4 =4;
- Fade_Moiree5 =5;
- Fade_Moiree6 =6;
- Fade_Moiree7 =7;
- Fade_Moiree8 =8;
- Fade_Moiree9 =9;
- Fade_Moiree10=10;
- Fade_Moiree11=11;
- Fade_Moiree12=12;
- Fade_Moiree13=13;
- Fade_Moiree14=14;
- Fade_SweepInFromTop=15;
- Fade_SweepInFromBottom=16;
- Fade_SweepInFromLeft=17;
- Fade_SweepInFromRight=18;
- Fade_ScrollInFromTop=19;
- Fade_ScrollInFromBottom=20;
- Fade_ScrollInFromLeft=21;
- Fade_ScrollInFromRight=22;
- Fade_Circles =23;
-
- PROCEDURE ShadowTab;
- PROCEDURE SetShadowTab(brightness:BYTE);
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- PROCEDURE GetPalette(VAR pal:Palette);
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- PROCEDURE SetCycleTime(milliseconds:WORD);
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
- PROCEDURE FreeImageMem(p:POINTER);
- PROCEDURE InitGraph;
- PROCEDURE Screen(pa:BYTE);
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- FUNCTION GetPixel(x,y:INTEGER):BYTE;
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE;
- FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE;
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte);
- PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte);
- PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN;
- PROCEDURE Animate;
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- PROCEDURE SetBackgroundMode(mode:BYTE);
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- PROCEDURE FillPage(pa,color:Byte);
- PROCEDURE FillBackground(color:BYTE);
- PROCEDURE GetBackgroundFromPage(pa:Byte);
- PROCEDURE WritePage(name:STRING; pa:BYTE);
- PROCEDURE LoadPage(name:STRING; pa:BYTE);
- PROCEDURE WriteBackgroundPage(name:STRING);
- PROCEDURE LoadBackgroundPage(name:STRING);
- PROCEDURE FadeIn(pa,ti,style:WORD);
- PROCEDURE InitRoutines;
- PROCEDURE CloseRoutines;
- FUNCTION GetErrorMessage:STRING;
-
-
- {--------------------------------------------------------------------------}
-
- IMPLEMENTATION
-
- CONST StartIndex=0;
- EndIndex=StartIndex+3;
- {Offsetadressen der Grafikseiten (in Segment $A000):}
- Offset_Adr:Array[StartIndex..EndIndex] OF WORD=($0000,$3E80,$7D00,$BB80);
- {Segmentadressen der Grafikseiten (bei Offset = 0) :}
- Segment_Adr:ARRAY[StartIndex..EndIndex] OF WORD=($A000,$A3E8,$A7D0,$ABB8);
-
- {Sprite(header)aufbau:
-
- 0..1 DW Plane_0_Daten
- 2..3 DW Plane_1_Daten
- 4..5 DW Plane_2_Daten
- 6..7 DW Plane_3_Daten
- 8..9 DW Breite (in 4er-Gruppen)
- 10..11 DW Hoehe in Zeilen
- 12..15 DB 1,2,4,8 ; Translate-Tabelle fuer Port-Ansteuerung
- 16..17 DW SpriteLength ; Laenge der Spritedatei
- ; jetzt fuer temporaere Variablen reservierter
- ; Bereich:
- 18..19 DW ? ; licutoff_ | hit1xfirst
- 20..21 DW ? ; zeilenadr | hit1yfirst
- 22..23 DW ? ; bildx | hit2xfirst
- 24..25 DW ? ; yoffset_ | hit2yfirst
- 26..27 DW ? ; end_min_start | ueberlappx_1
- 28..29 DW ? ; | ueberlappy_1
- 30..31 DW ? ; | x1
- 32..33 DW ? ; | x2
- 34..35 DW ? ; | y1
- 36..37 DW ? ; | y2
- 38..39 DB 'K','R' ; Kennung als Sprite
- 40 DB 1 ; Versionsnummer
- 41 DB 0 ; Modusnummer fuer Sprite
- 42..43 DW linke_Begrenzungen
- 44..45 DW rechte_Begrenzungen
- 46..47 DW obere_Begrenzungen
- 48..49 DW untere_Begrenzungen
- 50..?? DB Daten
-
- zum Bsp.: xxrxxxxx, mit: r=rot=40, g=gruen=45, b=blau=35, x=weiss=30
- xrgrxxxx
- rbgbrxxx
- }
-
- {Adressen von wichtigen Werten innerhalb des Spriteheaders:}
- Left=42;
- Right=44;
- Top=46;
- Bottom=48;
- Breite=8;
- Hoehe=10;
- Translate=12;
- SpriteLength=16;
- Kennung=38;
- Version=40;
- Modus=41;
-
- {Adressen der temporaeren Variablen fuer die Zeichenroutinen:}
- licutoff_=18;
- zeilenadr=20;
- bildx=22;
- yoffset_=24;
- end_min_start=26;
-
- {Adressen der temporaeren Variablen fuer die Kollisionspruefroutine:}
- hit1xfirst=18;
- hit1yfirst=20;
- hit2xfirst=22;
- hit2yfirst=24;
- ueberlappx_1=26;
- ueberlappy_1=28;
- x1=30;
- x2=32;
- y1=34;
- y2=36;
-
- TranslateTab:ARRAY[0..3] OF BYTE=(1,2,4,8); {Fuer Maskenadressierung}
- PICHeader:STRING[3]='PIC'; {Kennung in Bilderdateien}
- Schatten :BYTE=70; {Default-Helligkeit von Schatten}
-
- TYPE SpriteHeader= RECORD
- Zeiger_auf_Plane:Array[0..3] OF Word;
- Breite_in_4er_Gruppen:WORD;
- Hoehe_in_Zeilen:WORD;
- Translate:Array[1..4] OF Byte;
- SpriteLength:WORD;
- Dummy:Array[1..10] OF Word;
- Kennung:ARRAY[1..2] OF CHAR;
- Version:BYTE;
- Modus:BYTE;
- ZeigerL,ZeigerR,ZeigerO,ZeigerU:Word;
- END;
-
- CONST FontMask:ARRAY[0..7] OF BYTE=($80,$40,$20,$10,8,4,2,1);
- FontData: Font=( {verwendeter Zeichensatz: }
- ( 0, 0, 0, 0, 0, 0), {#0} {selbstgestrickter 6x6 Font}
- ( 0,216, 0,248,112, 0), {#1}
- (248,168,248,136,216,248), {#2}
- ( 0, 80,248,248,112, 32), {#3}
- ( 0, 32,112,248,112, 32), {#4}
- ( 32,112,216,248, 32,112), {#5}
- ( 32,112,248,248, 32,112), {#6}
- ( 0, 32,216,216, 32, 0), {#7}
- (248,216,168,168,216,248), {#8}
- ( 0,112,200,152,112, 0), {#9}
- (248,136,168,168,136,248), {#10}
- ( 56, 24, 32,112,136,112), {#11}
- (112,136,112, 32,248, 32), {#12}
- ( 56, 40, 32, 32,224,224), {#13}
- ( 0,120, 72,120, 72,216), {#14}
- ( 0, 32,168, 80,168, 32), {#15}
- ( 0,128,224,248,224,128), {#16}
- ( 0, 8, 56,248, 56, 8), {#17}
- ( 32,112,168,168,112, 32), {#18}
- ( 0,216,216,216, 0,216), {#19}
- ( 0,120,168,104, 40, 40), {#20}
- ( 24, 32, 16, 40,144, 96), {#21}
- ( 0, 0, 0, 0,248,248), {#22}
- ( 32,112, 32,112, 32,248), {#23}
- ( 0, 32,112,248, 32, 32), {#24}
- ( 0, 32, 32,248,112, 32), {#25}
- ( 0, 32, 16,248, 16, 32), {#26}
- ( 0, 32, 64,248, 64, 32), {#27}
- ( 0, 0,192,248, 0, 0), {#28}
- ( 0, 0, 80,248, 80, 0), {#29}
- ( 0, 0, 0, 32,112,248), {#30}
- ( 0, 0,248,112, 32, 0), {#31}
- ( 0, 0, 0, 0, 0, 0), { }
- ( 0, 48, 48, 48, 0, 48), {!}
- ( 0, 80, 80, 0, 0, 0), {"}
- ( 0, 80,248, 80,248, 80), {#}
- ( 32,120,160,112, 40,240), { $}
- ( 0,200, 16, 32, 64,152), {%}
- ( 0,112,216,112,152,104), {&}
- ( 0, 16, 32, 0, 0, 0), {'}
- ( 0,112,192,192,192,112), {(}
- ( 0,224, 48, 48, 48,224), {)}
- ( 0, 80, 32,248, 32, 80), {*}
- ( 0, 0, 32,248, 32, 0), {+}
- ( 0, 0, 0, 32, 32, 64), {,}
- ( 0, 0, 0,248, 0, 0), {-}
- ( 0, 0, 0, 0, 48, 0), {.}
- ( 4, 8, 16, 32, 64,128), {/}
- ( 0,112,152,168,200,112), {0}
- ( 0, 48,112, 48, 48,120), {1}
- ( 0,240, 24,112,192,248), {2}
- ( 0,240, 24,112, 24,240), {3}
- ( 0,192,208,248, 48, 48), {4}
- ( 0,248,192,240, 24,240), {5}
- ( 0,248,128,248,136,248), {6}
- ( 0,248, 24, 48, 96, 96), {7}
- ( 0,112,216,112,216,112), {8}
- ( 0,112,136,120, 8,112), {9}
- ( 0, 0, 32, 0, 32, 0), {:}
- ( 0, 0, 32, 0, 32, 64), {;}
- ( 0, 24, 48, 96, 48, 24), {<}
- ( 0, 0,248, 0,248, 0), {=}
- ( 0, 96, 48, 24, 48, 96), {>}
- (112,136, 16, 32, 0, 32), {?}
- ( 0,112,136,184,128,120), {@}
- ( 0,112,200,248,200,200), {A}
- ( 0,240,200,240,200,240), {B}
- ( 0,120,192,192,192,120), {C}
- ( 0,240,216,200,216,240), {D}
- ( 0,248,192,240,192,248), {E}
- ( 0,248,192,240,192,192), {F}
- ( 0,120,192,216,200,120), {G}
- ( 0,200,200,248,200,200), {H}
- ( 0,120, 48, 48, 48,120), {I}
- ( 0,248, 8, 8,200,112), {J}
- ( 0,200,208,224,208,200), {K}
- ( 0,192,192,192,192,248), {L}
- ( 0,136,216,168,136,136), {M}
- ( 0,136,200,168,152,136), {N}
- ( 0,112,200,200,200,112), {O}
- ( 0,240,200,240,192,192), {P}
- ( 0, 96,208,208,208,104), {Q}
- ( 0,240,136,240,208,200), {R}
- ( 0,248,192,248, 24,248), {S}
- ( 0,248, 96, 96, 96, 96), {T}
- ( 0,200,200,200,200,248), {U}
- ( 0,200,200,200,200, 48), {V}
- ( 0,136,136,168,248, 80), {W}
- ( 0,136,216,112,216,136), {X}
- ( 0,200,200,112, 48, 48), {Y}
- ( 0,248, 24,112,192,248), {Z}
- ( 0,120, 96, 96, 96,120), {[}
- (128, 64, 32, 16, 8, 4), {\}
- ( 0,120, 24, 24, 24,120), {]}
- ( 32, 80,136, 0, 0, 0), {^}
- ( 0, 0, 0, 0, 0,248), {_}
- ( 64, 32, 0, 0, 0, 0), {`}
- ( 0, 0,112,200,200,120), {a}
- ( 0,128,240,136,136,240), {b}
- ( 0, 0,120,192,192,120), {c}
- ( 0, 8,120,136,136,120), {d}
- ( 0, 0,112,248,128,112), {e}
- ( 0, 24, 32,120, 32, 32), {f}
- ( 0,112,136,120, 8,112), {g}
- ( 0,192,240,200,200,200), {h}
- ( 48, 0, 48, 48, 48, 48), {i}
- ( 24, 0, 24, 24,216,112), {j}
- ( 0,192,208,224,216,216), {k}
- ( 0, 96, 96, 96, 96, 56), {l}
- ( 0, 0,208,248,168,136), {m}
- ( 0, 0,240,200,200,200), {n}
- ( 0, 0,112,200,200,112), {o}
- ( 0, 0,240,200,240,192), {p}
- ( 0, 0,112,152,120, 24), {q}
- ( 0, 0,176,104, 96, 96), {r}
- ( 0, 56, 64, 48,136,112), {s}
- ( 0, 96,248, 96,104, 48), {t}
- ( 0, 0,200,200,200,120), {u}
- ( 0, 0,200,200,200,112), {v}
- ( 0, 0,136,168,168,112), {w}
- ( 0, 0,216, 96, 48,216), {x}
- ( 0, 0,200,248, 8,112), {y}
- ( 0, 0,240, 48,192,248), {z}
- ( 0, 56, 96,192, 96, 56),(*{*)
- ( 0, 16, 16, 0, 16, 16), {|}
- ( 0,224, 48, 24, 48,224),(*}*)
- ( 0,104,144, 0, 0, 0), {~}
- ( 0, 32, 80,136,248, 0), {#127}
- (112,200,128,200,112,192), {#128}
- ( 0,200, 0,200,200,120), {#129}
- ( 24, 32,112,248,128,112), {#130}
- ( 16, 40, 0,120,196,124), {#131}
- (104, 0,112,200,200,120), {#132}
- ( 48, 8,112,136,136,120), {#133}
- ( 16, 40, 16,112,200,120), {#134}
- ( 0,120,192,120, 16, 96), {#135}
- (112, 0,112,248,192,112), {#136}
- ( 80, 0,112,248,128,112), {#137}
- ( 48, 8,112,248,192,112), {#138}
- (104, 0, 48, 48, 48, 48), {#139}
- ( 48, 72, 0, 48, 48, 48), {#140}
- ( 96, 16, 0, 48, 48, 48), {#141}
- (200, 0,112,200,248,200), {#142}
- ( 48, 0,112,200,248,200), {#143}
- (112,248,192,240,192,248), {#144}
- ( 0,208, 40,112,160, 88), {#145}
- ( 0, 56, 80,248,144,152), {#146}
- ( 32, 80, 0,112,200,112), {#147}
- ( 80, 0,112,200,200,112), {#148}
- ( 96, 16, 0,112,200,112), {#149}
- ( 32, 80, 0,200,200,120), {#150}
- ( 96, 16, 0,200,200,120), {#151}
- ( 80, 0,200,248, 8,112), {#152}
- ( 80, 0,112,200,200,112), {#153}
- (200, 0,200,200,200,248), {#154}
- ( 16,120,128,128,120, 16), {#155}
- ( 48, 72,224, 64,136,248), {#156}
- (216, 32,248, 32,248, 32), {#157}
- (192,160,208,184,144,152), {#158}
- ( 48, 40, 96, 48,160, 96), {#159}
- ( 48, 64, 0,112,136,120), {#160}
- ( 48, 64, 0, 32, 32, 32), {#161}
- ( 48, 64, 0,112,200,112), {#162}
- ( 48, 64, 0,200,200,120), {#163}
- (104,144, 0,176, 72, 72), {#164}
- (104,144, 0,200,168,152), {#165}
- (112,144,104, 0,248, 0), {#166}
- (112,136,112, 0,248, 0), {#167}
- ( 32, 0, 32, 64,136,112), {#168}
- ( 0, 0,252,192, 0, 0), {#169}
- ( 0, 0,252, 12, 0, 0), {#170}
- ( 72, 80, 32, 64,168, 40), {#171}
- ( 72, 80, 32, 80,152, 8), {#172}
- ( 48, 0, 48, 48, 48, 0), {#173}
- ( 40, 80,160, 80, 40, 0), {#174}
- (160, 80, 40, 80,160, 0), {#175}
- ( 84,168, 84,168, 84,168), {#176}
- (252,252,252,252,252,252), {#177}
- (168, 84,168, 84,168, 84), {#178}
- ( 16, 16, 16, 16, 16, 16), {#179}
- ( 16, 16, 16,240, 16, 16), {#180}
- ( 16, 16,240, 16,240, 16), {#181}
- ( 40, 40, 40,232, 40, 40), {#182}
- ( 0, 0, 0,248, 40, 40), {#183}
- ( 0, 0,240, 16,240, 16), {#184}
- ( 40, 40,232, 8,232, 40), {#185}
- ( 40, 40, 40, 40, 40, 40), {#186}
- ( 0, 0,248, 8,232, 40), {#187}
- ( 40, 40,232, 8,248, 0), {#188}
- ( 40, 40, 40,248, 0, 0), {#189}
- ( 16, 16,240, 16,240, 0), {#190}
- ( 0, 0, 0,240, 16, 16), {#191}
- ( 16, 16, 16, 28, 0, 0), {#192}
- ( 16, 16, 16,252, 0, 0), {#193}
- ( 0, 0, 0,252, 16, 16), {#194}
- ( 16, 16, 16, 28, 16, 16), {#195}
- ( 0, 0, 0,252, 0, 0), {#196}
- ( 16, 16, 16,252, 16, 16), {#197}
- ( 16, 16, 28, 16, 28, 16), {#198}
- ( 40, 40, 40, 44, 40, 40), {#199}
- ( 40, 40, 44, 32, 60, 0), {#200}
- ( 0, 0, 60, 32, 44, 40), {#201}
- ( 40, 40,236, 0,252, 0), {#202}
- ( 0, 0,252, 0,236, 40), {#203}
- ( 40, 40, 44, 32, 44, 40), {#204}
- ( 0, 0,252, 0,252, 0), {#205}
- ( 40, 40,236, 0,236, 40), {#206}
- ( 16, 16,252, 0,252, 0), {#207}
- ( 40, 40, 40,252, 0, 0), {#208}
- ( 0, 0,252, 0,252, 16), {#209}
- ( 0, 0, 0,252, 40, 40), {#210}
- ( 40, 40, 40, 60, 0, 0), {#211}
- ( 16, 16, 28, 16, 28, 0), {#212}
- ( 0, 0, 28, 16, 28, 16), {#213}
- ( 0, 0, 0, 60, 40, 40), {#214}
- ( 40, 40, 40,252, 40, 40), {#215}
- ( 16, 16,252, 16,252, 16), {#216}
- ( 16, 16, 16,240, 0, 0), {#217}
- ( 0, 0, 28, 16, 16, 16), {#218}
- (252,252,252,252,252,252), {#219}
- ( 0, 0, 0,252,252,252), {#220}
- (192,192,192,192,192,192), {#221}
- ( 12, 12, 12, 12, 12, 12), {#222}
- (252,252,252, 0, 0, 0), {#223}
- ( 0, 0,104,144,144,104), {#224}
- ( 0,112,152,176,136,176), {#225}
- ( 0,248,136,128,128,128), {#226}
- ( 0, 0,248, 80, 80, 80), {#227}
- (248, 72, 32, 64,136,248), {#228}
- ( 0, 0,120,144,144, 96), {#229}
- ( 0, 72, 72,120, 64,192), {#230}
- ( 0, 0,104,176, 32, 32), {#231}
- ( 0,248, 32, 80, 32,248), {#232}
- ( 0,112,136,248,136,112), {#233}
- ( 0,112,136,136, 80,216), {#234}
- ( 56, 64, 32,112,136,112), {#235}
- ( 0, 0, 80,168, 80, 0), {#236}
- ( 0, 8, 80,168, 80,128), {#237}
- ( 0,120,128,248,128,120), {#238}
- ( 0, 0,112,136,136,136), {#239}
- ( 0,248, 0,248, 0,248), {#240}
- ( 0, 32,112, 32, 0,248), {#241}
- ( 64, 32, 16, 32, 64,248), {#242}
- ( 16, 32, 64, 32, 16,248), {#243}
- ( 16, 40, 32, 32, 32, 32), {#244}
- ( 32, 32, 32, 32,160, 64), {#245}
- ( 0, 32, 0,248, 0, 32), {#246}
- (104,144, 0,104,144, 0), {#247}
- ( 96,144, 96, 0, 0, 0), {#248}
- ( 0, 0, 0, 48, 0, 0), {#249}
- ( 0, 0, 0, 16, 0, 0), {#250}
- ( 60, 32, 32,160, 96, 32), {#251}
- (176, 72, 72, 0, 0, 0), {#252}
- (224, 16, 96,128,240, 0), {#253}
- ( 0, 0,112,112, 0, 0), {#254}
- ( 0, 0, 0, 0, 0, 0));{#255}
-
- VAR Steigung:BYTE; {entscheidet, welcher Alg. Anwendung findet}
- DY_mal2,DY_m_DX_mal2:INTEGER;
- oldMode:byte;
- regs:registers;
-
- IsAT:BYTE;
- TimeFlag:BYTE;
- CycleTime:LONGINT;
-
- CRTAddress, StatusReg : WORD;
-
-
- {-----------------------------------------------------}
-
- PROCEDURE ShadowTab; ASSEMBLER;
- {Pseudoprozedur, um Daten der Farbumsetztabelle im Codesegment unterzu-}
- {bringen, AUF KEINEN FALL AUFRUFEN!!! }
- {Defaultwerte entsprechen Abdunkelung auf 70% des Farb-Helligkeitswerts}
- ASM
- DB 254,104,120,124,112,108,114, 24, 20,128,144, 3,136, 5,140, 7
- DB 254,254, 17, 17, 18, 19, 20, 20, 21, 8, 23, 24, 24, 25, 26, 7
- DB 1, 1,107,108, 5,108,109, 4, 4, 4, 6, 6,116,116,117, 2
- DB 2, 2,123,124, 3,124,125, 1,152,155,156,156, 5,156,156,157
- DB 160,163,164,164,164,164,164,165,168,171,172,172, 3,172,172,173
- DB 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
- DB 24, 24, 24, 24, 24, 24, 24, 24,176,177,178,179,180,181,182,183
- DB 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199
- DB 200,201,203,204,204,204,205,207,208,209,211,212,212,212,213,215
- DB 216,217,219,220,220,220,221,223,246,227,228,228,228,228,228,229
- DB 234,235,236,236,236,236,236,237,242,243,244,244,244,244,244,245
- DB 254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254
- DB 254,254,254,254,254,254,254,254, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
- DB 17, 17, 17, 17, 17, 17, 17, 17,254,254,254,254,254,254,254, 7
- END;
-
- PROCEDURE CS_TranslateTab; ASSEMBLER;
- {kleine Pseudoprozedur, um die Umsetztabelle fuer die Bitmaske auch im}
- {Codesegment zu haben}
- ASM
- DB 1,2,4,8
- END;
-
- PROCEDURE SetShadowTab(brightness:BYTE);
- { in: brightness = gewuenschte Helligkeit der Farben im Schattenbereich,}
- { in Prozent zu der Helligkeit ihrer Originalfarben }
- {out: ShadowTab = (Naeherungs-)Farbtabelle fuer gewuenschte Abdunkelung}
- { Schatten = neue Helligkeit (Schatten ist globale Variable!) }
- {rem: Defaultwert in ShadowTab ist 70% Helligkeit der Ursprungsfarben! }
- { Diese Routine dauert ihre Zeit (ca. 4 sec auf 8MHz-AT!) }
-
- VAR neue_Tabelle:ColorTable;
- p1:POINTER;
-
- BEGIN
- IF (brightness<0) OR (brightness>100)
- THEN BEGIN
- Error:=Err_InvalidPercentage;
- exit
- END;
- p1:=@neue_Tabelle; {Trick, da der Assembler nicht mit dem SS-Segment klarkommt}
- ASM
- MOV CX,256 {aeusserer Schleifenzaehler}
- LES DI,p1 {ES:DI=^neue_Tabelle[i] }
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
-
- @outerloop:
- LODSB {AL=tempColors[i].red}
- MUL brightness {wird ueber Stack adressiert!}
- MOV DL,100
- DIV DL {AL=tempColors[i].red*brightness DIV 100}
- MOV BL,AL {BL := AL = neuer Rotanteil}
-
- LODSB {dto., fuer gruen}
- MUL brightness
- MOV DL,100
- DIV DL
- MOV BH,AL {...nach BH}
-
- LODSB {dto., fuer blau}
- MUL brightness
- MOV DL,100
- DIV DL
- MOV DH,AL {...nach DH}
-
- {BL/BH/DH = RGB-Anteile der Farbe, fuer die eine Naeherung zu finden ist}
- PUSH CX
- PUSH SI
- PUSH DI
- PUSH BP
-
- MOV DI,65535 {bisher gefundenes minimales Fehlerquadrat}
- MOV CX,256 {alle 256 Default-Farben durchsehen}
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
- @searchloop:
- MOV AL,BL {Differenz im Rotanteil berechnen}
- SUB AL,[SI]
- JL @noNewMin {neue Farbe darf nicht heller sein!}
- MUL AL {Fehlerquadrat berechnen}
- MOV BP,AX
-
- MOV AL,BH {dto., fuer Gruenanteil}
- SUB AL,[SI+1]
- JL @noNewMin
- MUL AL
- ADD BP,AX
- JC @noNewMin {mordsmaessige Abweichungen sofort ignorieren}
-
- MOV AL,DH {dto., fuer Blauanteil}
- SUB AL,[SI+2]
- JL @noNewMin
- MUL AL
- ADD AX,BP
- JC @noNewMin
-
- CMP AX,DI {bessere Approximation gefunden?}
- JAE @noNewMin {nein}
- MOV DI,AX {ja, Fehlerquadrat und Farbe merken}
- MOV DL,CL
- OR DI,DI {Fehlerquadrat = 0?}
- JZ @ColorDone {ja, bessere Naeherung koennen wir nicht mehr finden!}
-
- @noNewMin:
- ADD SI,3
- LOOP @searchloop
-
- CMP DI,65535 {keine Farbe gefunden?}
- JNE @ColorDone {doch, fertig!}
- MOV CX,256 {nein, also nochmal suchen}
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
- @searchloop2:
- LODSB
- SUB AL,BL {Diff ≈±2^6 -> Quadrat ≈±2^12 -> 3*Quadrat<MaxInt}
- IMUL AL {also kein Overflow moeglich}
- MOV BP,AX
-
- LODSB {dto., fuer Gruenanteil}
- SUB AL,BH
- IMUL AL
- ADD BP,AX
-
- LODSB {dto., fuer Blauanteil}
- SUB AL,DH
- IMUL AL
- ADD AX,BP
-
- CMP AX,DI {bessere Approximation gefunden?}
- JAE @noNewMin2 {nein}
- MOV DI,AX {ja, Fehlerquadrat und Farbe merken}
- MOV DL,CL
-
- @noNewMin2:
- LOOP @searchloop2
-
-
- @ColorDone: {100h-DL = gefundene optimale Farbe}
- POP BP
- POP DI {ES:DI=^neue_Tabelle[i] }
- POP SI {DS:SI=^ActualColors[i] }
- POP CX
-
- MOV AL,DL {in neue_Tabelle[i] eintragen}
- NEG AL {AL=100h-DL = beste Naeherung}
- STOSB
-
- DEC CX {Ersatz fuer "LOOP @outerloop"; naechste Farbe!}
- JCXZ @fertig
- JMP @outerloop
- @fertig:
-
- END; {of ASM}
- MOVE(neue_Tabelle,@ShadowTab^,256); {Farbtabelle uebernehmen}
- Schatten:=brightness
- END;
-
- PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
- { in: pal = Zeiger auf zu setzende Palette }
- { update = TRUE/FALSE fuer: ShadowTab neu/nicht neu berechnen}
- {out: ActualColors = aktuelle Farbpalette }
- {rem: Palette wurde uebernommen und evtl. ShadowTab neuberechnet }
- BEGIN
- IF @pal<>@ActualColors
- THEN ActualColors:=pal; {Farbpalette in ActualColors uebernehmen}
- ASM
- MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
-
- CLI
-
- mov dx,StatusReg
- @WaitNotVSyncLoop:
- in al,dx
- and al,8
- jnz @WaitNotVSyncLoop
- @WaitVSyncLoop:
- in al,dx
- and al,8
- jz @WaitVSyncLoop
-
- MOV DX,3C8h
- XOR AL,AL
- OUT DX,AL
- INC DX
-
- MOV CX,256
- @L1:
- LODSB
- OUT DX,AL
- LODSB
- OUT DX,AL
- LODSB
- OUT DX,AL
- LOOP @L1
-
- STI
- END; {of ASM}
- IF update THEN SetShadowTab(Schatten)
- END;
-
- PROCEDURE GetPalette(VAR pal:Palette); ASSEMBLER;
- { in: pal = Zeiger auf Palette-Speicher}
- {out: pal = momentan aktuelle Palette }
- ASM
- CLI
- XOR AL,AL
- MOV DX,3C7h
- OUT DX,AL
- LES DI,pal
- MOV CX,768
- MOV DX,3C9h
- @L1:
- IN AL,DX
- STOSB
- LOOP @L1
- STI
- END;
-
- FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
- { in: name = Name des zu ladenden Palette-Files (Typ: "*.PAL" )}
- { number = Nummer, die die erste Farbe aus diesem File bekommen soll }
- { ActualColors = gerade aktuelle Farbpalette}
- {out: Anzahl der aus dem File gelesenen Farben (0 = Fehler trat auf) }
- { pal = aus dem File gelesene Farbpalette, evtl. ergaenzt}
- {rem: Alle nicht ueberschriebenen Farben werden in "pal" auf die Werte der}
- { gerade aktuellen Farben "ActualColors" gesetzt; die Palette wurde }
- { nur geladen, nicht gesetzt!}
- LABEL quitloop;
- VAR len:LONGINT;
- f:File;
- i,count:WORD;
- TempPal:Palette;
- flag:BOOLEAN;
- BEGIN
- count:=0; {Zahl der bisher eingelesenen Paletteneintraege}
- assign(f,name);
- {$I-} reset(f,1); {$I+}
- if (ioresult<>0)
- THEN BEGIN {Datei existiert nicht oder nicht unter diesem Pfad}
- Error:=Err_FileIO;
- LoadPalette:=0; exit
- END;
- len:=filesize(f); {Dateilaenge ermitteln}
- if (len mod 3<>0) OR (len>3*256) OR (len<3)
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
- IF len+number*3>3*256
- THEN BEGIN
- Error:=Err_PaletteWontFit;
- goto quitloop;
- END;
-
- TempPal:=ActualColors; {temporaere Palette mit aktuellen Farben vorbesetzen}
- {$I-}
- blockread(f,TempPal[number],len);
- {$I+}
-
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quitloop;
- END;
-
- flag:=FALSE;
- FOR i:=number TO Pred(number+(len DIV 3))
- DO flag:=flag OR (TempPal[i].red>63)
- OR (TempPal[i].green>63)
- OR (TempPal[i].blue>63);
- IF flag
- THEN BEGIN
- Error:=Err_NoPalette;
- goto quitloop;
- END;
-
- {Alles ging gut: Palette zurueckgeben}
- pal:=TempPal;
- count:=len DIV 3;
-
- quitloop: ;
- close(f);
- LoadPalette:=count
- END;
-
- {Nun folgen die Codestuecke, die Verwendung finden, um ein Sprite auf den}
- {Schirm zu bringen; die Schnittstelle ist fuer alle gleich: }
- { in: CX = Anzahl Bytes, die von... }
- { DS:SI = (Zeiger auf Quelladresse) nach... }
- { ES:BX = (Zeiger auf Zieladresses) zu bringen sind; }
- { DI = Bitplane (0..3) (=X-Koordinate AND 3) }
- { Die Bitmaske fuer den richtigen Schreibe-Planezugriff wurde bereits}
- { gesetzt, eine evtl. noetige Leseplane dagegen nicht! }
- { Die Routinen koennen sicher sein, dass CX<>0 ist }
- {rem: Jede dieser Routinen MUSS EXAKT 16 Bytes lang und VOLL RELOKATIBEL }
- { sein, sowie die Register BP,DS,ES unveraendert lassen!!!!!!!!!!!!! }
- { Ausserdem muessen die einzelnen Routinen zur Unterscheidbarkeit in }
- { ihren ersten zwei Bytes paarweise verschieden sein! }
-
- PROCEDURE Modus0; ASSEMBLER;
- {Modus 0 betrachtet die Farbe 0 als durchsichtig fuer den Hintergrund}
- ASM
- INC CX
- STC {BX so verringern, dass es zusammen mit SI zugleich}
- SBB BX,SI {als Zielindex verwendet werden kann}
- @L1:
- LODSB {Spritebyte holen }
- OR AL,AL {ist es gleich 0? }
- LOOPZ @L1 {ja, nichts zu tun}
- JCXZ @L2 {alle Bytes durch?}
- MOV ES:[BX+SI],AL {nein, uebertragen}
- JMP @L1 {short} {naechstes Byte }
- @L2:
- END;
-
- PROCEDURE Modus1; ASSEMBLER;
- {Modus 1 schreibt die Daten sofort ohne weitere Untersuchung auf den Schirm}
- ASM
- MOV DI,BX {DI setzen, damit Stringbefehle verwendet werden koennen}
- XOR AX,AX {AX:=0 setzen}
- SHR CX,1 {Anzahl zu uebertragender Woerter}
- REP MOVSW {Daten auf einen Satz uebertragen}
- ADC CX,AX {noch ein einzelnes Byte uebrig? }
- REP MOVSB
- MOV AX,AX {4 Fuellbytes; schneller als 4 NOPs}
- MOV AX,AX
- END;
-
- PROCEDURE Modus2Work; ASSEMBLER;
- {Fortsetzung von Modus2 - all das, was nicht mehr in 16 Bytes unterzubringen}
- {war, kommt hierher}
- ASM
- OUT DX,AX {Lesezugriff auf passende Plane ermoeglichen}
-
- PUSH DS {DS zeigt noch auf Spritedaten, muss aber auf}
- {Hintergrund zeigen! }
- MOV AX,ES {DS:SI := ES:DI (Quellzeiger:=Zielzeiger) }
- MOV DS,AX
- MOV SI,DI
- MOV BX,OFFSET ShadowTab {Zeiger auf Farbumsetztabelle setzen }
-
- @L4:
- LODSB {Hintergrundfarbe holen... }
- SEGCS XLAT {...mit Farbtabelle umsetzen}
- STOSB {...und auf aktueller Seite darstellen}
- LOOP @L4
-
- POP DS
- END;
-
- PROCEDURE Modus2; ASSEMBLER;
- {Modus 2 ist fuer "Schatten" und aehnliches gedacht: hierbei werden die }
- {eigentlichen Spritedaten ignoriert und stattdessen die Hintergrunddaten}
- {gelesen, die sich an der Spriteposition befinden und deren Farbwerte }
- {gegen die der Farbtabelle "ShadowTab" ersetzt (um bspw. Schatten zu er-}
- {zeugen, muesste diese Tabelle zu jeder Farbe eine dunklere enthalten) }
- ASM
- MOV AX,DI {Bitplane fuer Lesezugriff nach AX bringen}
- MOV DI,BX {fuer Stringbefehle die Zieladresse nach DI bringen}
- MOV AH,AL {Bitplane ins Highbyte bringen}
- MOV AL,4
- MOV DX,3CEh
- MOV SI,OFFSET Modus2Work {fieser Trick: "CALL Modus2Work" wuerde (da re-}
- CALL SI {lativ codiert) zu falscher Adresse verzweigen!}
- END;
-
- PROCEDURE Modus3Work; ASSEMBLER;
- {Fortsetzung von Modus3 - all das, was nicht mehr in 16 Bytes unterzubringen}
- {war, kommt hierher}
- ASM
- STC
- SBB BX,SI {Quell-/Zieldaten beide mit nur 1 Indexregister ansprechen}
- MOV DX,BP {BP-Register retten}
- MOV BP,BX
- MOV BX,OFFSET ShadowTab {Zeiger auf Farbumsetztabelle setzen }
-
- @L1:
- LODSB {Spritedatum holen... }
- OR AL,AL { (Farbe 0 ignorieren, da "durchsichtig") }
- LOOPZ @L1
- JCXZ @L2
- MOV AL,ES:[BP+SI] {Hintergrundfarbe holen... }
- SEGCS XLAT {...mit Farbtabelle umsetzen}
- MOV ES:[BP+SI],AL {...und auf aktueller Seite darstellen}
- JMP @L1
- @L2:
- MOV BP,DX {alten Inhalt von BP wiederherstellen}
- END;
-
- PROCEDURE Modus3; ASSEMBLER;
- {Modus 3 ist ebenfalls fuer "Schatten" gedacht: hierbei werden alle Sprite- }
- {punkte, deren Farbe <>0 ist beruecksichtigt: die Hintergrundfarbe, die sich}
- {unter diesen Punkten befindet, wird gegen den korrespondierenden Farbwert }
- {aus der Tabelle "ShadowTab" ersetzt. }
- {In anderen Worten: dieser Modus entspricht dem Modus 2, mit dem Unter- }
- {schied, dass die Spritefarbe 0 als fuer den Schatten durchsichtig betrach- }
- {tet wird! }
- ASM
- MOV DX,3CEh {Zugriff auf Leseplane vorbereiten:}
- MOV AX,DI
- MOV AH,AL {Leseplane nach AH bringen}
- MOV AL,4
- OUT DX,AX {Lesezugriff auf passende Plane ermoeglichen}
- INC CX {Anzahl Bytes um 1 erhoehen (wg. LODSB) }
- MOV AX,OFFSET Modus3Work {Trick damit Code relokatibel wird!}
- CALL AX
- END;
-
- PROCEDURE Adressen; ASSEMBLER;
- {Tabelle der Startadressen der 3 Routinen im Codesegment}
- ASM
- DW OFFSET Modus0
- DW OFFSET Modus1
- DW OFFSET Modus2
- DW OFFSET Modus3
- END;
-
-
- PROCEDURE GADR; ASSEMBLER;
- {Tabelle der Grafikzeilen-Startadressen (Offset-Anteil)}
- ASM
- DW $0000,$0050,$00A0,$00F0,$0140,$0190,$01E0,$0230
- DW $0280,$02D0,$0320,$0370,$03C0,$0410,$0460,$04B0
- DW $0500,$0550,$05A0,$05F0,$0640,$0690,$06E0,$0730
- DW $0780,$07D0,$0820,$0870,$08C0,$0910,$0960,$09B0
- DW $0A00,$0A50,$0AA0,$0AF0,$0B40,$0B90,$0BE0,$0C30
- DW $0C80,$0CD0,$0D20,$0D70,$0DC0,$0E10,$0E60,$0EB0
- DW $0F00,$0F50,$0FA0,$0FF0,$1040,$1090,$10E0,$1130
- DW $1180,$11D0,$1220,$1270,$12C0,$1310,$1360,$13B0
- DW $1400,$1450,$14A0,$14F0,$1540,$1590,$15E0,$1630
- DW $1680,$16D0,$1720,$1770,$17C0,$1810,$1860,$18B0
- DW $1900,$1950,$19A0,$19F0,$1A40,$1A90,$1AE0,$1B30
- DW $1B80,$1BD0,$1C20,$1C70,$1CC0,$1D10,$1D60,$1DB0
- DW $1E00,$1E50,$1EA0,$1EF0,$1F40,$1F90,$1FE0,$2030
- DW $2080,$20D0,$2120,$2170,$21C0,$2210,$2260,$22B0
- DW $2300,$2350,$23A0,$23F0,$2440,$2490,$24E0,$2530
- DW $2580,$25D0,$2620,$2670,$26C0,$2710,$2760,$27B0
- DW $2800,$2850,$28A0,$28F0,$2940,$2990,$29E0,$2A30
- DW $2A80,$2AD0,$2B20,$2B70,$2BC0,$2C10,$2C60,$2CB0
- DW $2D00,$2D50,$2DA0,$2DF0,$2E40,$2E90,$2EE0,$2F30
- DW $2F80,$2FD0,$3020,$3070,$30C0,$3110,$3160,$31B0
- DW $3200,$3250,$32A0,$32F0,$3340,$3390,$33E0,$3430
- DW $3480,$34D0,$3520,$3570,$35C0,$3610,$3660,$36B0
- DW $3700,$3750,$37A0,$37F0,$3840,$3890,$38E0,$3930
- DW $3980,$39D0,$3A20,$3A70,$3AC0,$3B10,$3B60,$3BB0
- DW $3C00,$3C50,$3CA0,$3CF0,$3D40,$3D90,$3DE0,$3E30
- END;
-
-
- FUNCTION AT:BOOLEAN;
- { in: - }
- {out: TRUE/FALSE, wenn die Maschine (mindestens) ein AT ist}
- BEGIN
- AT:=MEM[$F000:$FFFE]=$FC
- END;
-
-
- PROCEDURE SetCycleTime(milliseconds:WORD);
- { in: Mindestzeit eines Animationszyklus in Millisekunden}
- {out: CycleTime := dieser Wert in Mikrosekunden}
- { TimeFlag := $80}
- {rem: Fuer den ersten Animationszyklus nach Aufruf dieser Routine}
- { gilt wg. TimeFlag:=$80 die Zeitbedingung noch nicht! }
- { Schaltet der Benutzer (durch Angabe von milliseconds=0) die}
- { Zeitueberwachung explizit ab, so wird das durch IsAT:=$80, }
- { d.h.: "Rechner ist ein PC" vorgetaeuscht. Sonst ist IsAT=0 }
- BEGIN
- TimeFlag:=$80;
- CycleTime:=LONGINT(milliseconds)*LONGINT(1000);
- IF (milliseconds<>0) AND AT
- THEN IsAT:=0 {ja, Zeitueberwachung soll benutzt werden }
- ELSE IsAT:=$80 {nein, keine moeglich oder nicht gewuenscht}
- END;
-
- PROCEDURE SetSpriteCycle(nr,len:WORD);
- { in: nr = Spriteladenummer des ersten Sprites des Zyklus }
- { len = Laenge des zu definierenden Spritezyklus }
- {out: NextSprite[nr] bis NextSprite[nr+len-1] wurden so gesetzt,}
- { dass sie im Ring aufeinander zeigen, d.h.: sie bilden }
- { einen Spritezyklus}
- {rem: Soll der Zyklus aus nicht direkt aufeinanderfolgenden }
- { (physikalischen) Sprites gebildet werden, so muessen die }
- { entsprechenden Eintraege in NextSprite[] manuell gemacht }
- { werden }
- { Diese Routine verwendet SpriteLADEnummern!}
- VAR i:WORD;
- BEGIN
- IF (nr<1) OR (nr+len-1>LoadMAX)
- THEN Error:=Err_InvalidSpriteLoadNumber
- ELSE BEGIN
- FOR i:=nr TO nr+len-2 DO NextSprite[i]:=SUCC(i);
- NextSprite[PRED(nr+len)]:=nr {letztes Sprite zeigt auf erstes}
- END;
- END;
-
-
- FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
- { in: (x1,y1) = linke obere Ecke des zu sichernden Bildausschnittes }
- { (x2,y2) = rechte untere Ecke dazu (alles virtuelle Koordinaten!) }
- { pa = Grafikseite, von der der Ausschnitt zu sichern ist (0..2) }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- {out: Zeiger auf Heapbereich, der den kopierten Bildausschnitt enthaelt }
- { left_cut= evtl. noetiger linker Cutoff des Bildausschnittes (gibt an,}
- { um wieviel Punkte der Ausschnitt links ausserhalb des Bild-}
- { schirm ragte) }
- { right_cut,top_cut,bottom_cut = dto., fuer andere Raender }
- { was_cut = TRUE/FALSE, falls ein zurechtstutzen des Bildausschnittes }
- { noetig war/nicht noetig war }
- {rem: Der benoetigte Speicher wird von der Routine automatisch reserviert }
- { Sollte dies nicht moeglich sein (oder liegt der Bildausschnitt gaenz-}
- { lich ausserhalb des sichtbaren Bereichs), so wird NIL zurueckgegeben!}
- { Nur wenn "was_cut" TRUE ist, sind die Werte der globalen "..._cut" }
- { Variablen <>0 gesetzt worden, d.h.: ist der Ausschnitt _ganz_ ausser-}
- { halb des Bildes (also zurueckgegebener Zeiger=NIL), dann liefert die }
- { Routine trotzdem "was_cut"=FALSE!}
- VAR len,breite,hoehe,StartAdr,actualAdr,SegmAdr:WORD;
- p:POINTER;
- BEGIN
- was_cut:=FALSE; left_cut:=0; right_cut:=0; top_cut:=0; bottom_cut:=0;
- dec(x1,StartVirtualX); {Bildschirmkoordinaten berechnen}
- dec(y1,StartVirtualY);
- IF (x1>XMAX) or (y1>YMAX) or (x2<0) or (y2<0) or (x1>x2) or (y1>y2)
- THEN BEGIN {Bildausschnitt nicht auf dem Bildschirm}
- GetImage:=NIL;
- exit
- END;
- {Ausschnitt auf Bildschirm zurechtklippen:}
- IF x1<0 THEN BEGIN left_cut :=-x1; x1:=0; was_cut:=TRUE END;
- IF y1<0 THEN BEGIN top_cut:=-y1; y1:=0; was_cut:=TRUE END;
- IF x2>XMAX THEN BEGIN right_cut :=x2-XMAX; x2:=XMAX; was_cut:=TRUE END;
- IF y2>YMAX THEN BEGIN bottom_cut:=y2-YMAX; y2:=YMAX; was_cut:=TRUE END;
-
- breite:=SUCC(x2-x1); hoehe:=SUCC(y2-y1);
- len:=breite*hoehe+2*2; {1 Pixel=1 Byte; dazu: 2 Woerter fuer breite & hoehe}
- IF len>MaxAvail
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- GetImage:=NIL;
- exit
- END;
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE) {Seitennummer muss 0..2 sein}
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- GetImage:=NIL;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- GetMem(p,len); {Speicher auf dem Heap besorgen}
- ASM
- CLD
- LES DI,p {ES:DI = Zeiger auf den besorgten Speicher}
- MOV AX,breite
- STOSW {Breite zuerst ablegen...}
- MOV AX,hoehe
- STOSW {...gefolgt von der Hoehe, danach dann die Daten}
-
- MOV BX,AX {BX:=hoehe (fuer spaeter) }
- MOV SI,y1
- SHL SI,1
- MOV SI,CS:[OFFSET gadr + SI] {SI:=y1*LINESIZE}
- MOV AX,x1
- MOV DL,AL
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI:=Offsetanteil der Startadresse}
- MOV StartAdr,SI
- MOV actualAdr,SI
- AND DL,3
- MOV AH,DL
- MOV AL,4
- MOV DX,3CEh
- OUT DX,AX {Startplane anwaehlen}
- MOV DS,SegmAdr
-
- {DS:SI = Zeiger auf erstes zu speicherndes Byte; ES:DI = Zieladr. dafuer}
- {AH = Startplane, AL = 4, BX = abzuarbeitende Zeilenanzahl}
-
- MOV DX,breite
- ADD DX,3
- SHR DX,1
- SHR DX,1 {DX = Anzahl zu sichernde Bytes je Zeile}
-
- @L1:
- MOV CX,DX {Daten einer Zeile abspeichern}
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr {Quellzeiger um 1 Grafikzeile weitersetzen}
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX {Zeilenzaehler verringern}
- JNE @L1
-
- INC AH {naechste Plane anwaehlen}
- CMP AH,4
- JNE @nowrap1 {wrap in den Bitplanes bedeutet: Startadresse}
- MOV AH,0 {um 1 Adresse weitersetzen! }
- INC StartAdr
- @nowrap1:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L2:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L2
-
- INC AH
- CMP AH,4
- JNE @nowrap2
- MOV AH,0
- INC StartAdr
- @nowrap2:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- INC DX
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L3:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L3
-
- INC AH
- CMP AH,4
- JNE @nowrap3
- MOV AH,0
- INC StartAdr
- @nowrap3:
- MOV DX,3CEh
- OUT DX,AX
- MOV BX,hoehe
- MOV DX,breite
- SHR DX,1
- SHR DX,1
- MOV SI,StartAdr
- MOV actualAdr,SI
-
- @L4:
- MOV CX,DX
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- MOV SI,actualAdr
- ADD SI,LINESIZE
- MOV actualAdr,SI
- DEC BX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
- GetImage:=p
- END;
-
- PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
- { in: (x,y) = linke obere Ecke des Zieles (in virtuellen Koordinaten) }
- { p = Zeiger auf (durch GetImage erstellten) Bildausschnitt }
- { pa = Grafikseite, in die der Bildausschnitt kopiert werden soll}
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- {out: - }
- {rem: Der Bildausschnitt wurde zur Bildschirmdarstellung zurechtgeklippt}
- { Bei Uebergabe von NIL als Zeiger stellt die Routine gar nichts dar}
- { Dies hilft fuer eine direkte Uebernahme der von GetImage gelie- }
- { ferten Werte! }
- VAR breite,hoehe,SegmAdr,actualAdr,StartAdr,breite1,breite2,breite3,breite4,
- licut_div4,topcut,pl_adr1,pl_adr2,pl_adr3,pl_adr4:WORD;
- licutoff,temp:INTEGER;
- BEGIN
- IF p=NIL THEN exit;
- dec(x,StartVirtualX); {Bildschirmkoordinaten berechnen}
- dec(y,StartVirtualY);
- IF (x>XMAX) or (y>YMAX) THEN exit;
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END
- ELSE SegmAdr:=Segment_Adr[pa];
- breite:=MEMW[SEG(p^):OFS(p^)];
- hoehe :=MEMW[SEG(p^):OFS(p^)+2];
- IF (x+breite<=0) or (y+hoehe<=0) THEN exit;
- IF x<0 THEN BEGIN licutoff:=-x; x:=0 END
- ELSE licutoff:=0;
- IF y<0 THEN BEGIN
- topcut:=-y;
- y:=0
- END
- ELSE topcut:=0;
-
- breite1:=(breite + 3) shr 2; {Breite einer Zeile fuer die erste, zweite,}
- breite2:=(breite + 2) shr 2; {dritte und vierte Bitplane}
- breite3:=(breite + 1) shr 2;
- breite4:=(breite + 0) shr 2;
-
- {Anfangsadressen der 4 Bitplanes berechnen; dabei evtl. linken cutoff mit}
- {einbeziehen (plus 4 Bytes zum ueberspringen von "breite" und "hoehe" }
- licut_div4:=licutoff shr 2;
- pl_adr1:=4 +licut_div4 +topcut*breite1;
- pl_adr2:=4 +licut_div4 +topcut*breite2 +hoehe*breite1;
- pl_adr3:=4 +licut_div4 +topcut*breite3 +hoehe*(breite1+breite2);
- pl_adr4:=4 +licut_div4 +topcut*breite4 +hoehe*(breite1+breite2+breite3);
-
- {licutoff mod 4 gibt an, in welcher Reihenfolge die Punkte aus dem Heap }
- {gelesen werden muessen: 0 = Planereihenfolge (1,2,3,4); 1=(2,3,4,1); }
- {2=(3,4,1,2); 3=(4,1,2,3); zu beachten ist, dass die Breiten der einzel-}
- {nen Bitplanetabellen natuerlich mit diesen verbunden bleibt und deshalb}
- {mitgetauscht werden muss!}
- ASM
- CLD
- MOV AX,licutoff
- AND AL,3
- OR AL,AL
- JE @no_exchange
- CMP AL,1
- JNE @L10
-
- MOV AX,pl_adr2 {Verschiebung um 1 Bit: }
- MOV BX,pl_adr3 {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
- MOV CX,pl_adr4
- MOV DX,pl_adr1 {wrap-around, deshalb: Adresse um 1 erhoehen, was }
- INC DX {einer Weitersetzung um 4 Bildpunkte entspricht }
- MOV pl_adr1,AX {(z.B.: Pixel (1,5,9,...),(2,6,10,...),(3,7,11,...)}
- MOV pl_adr2,BX {und (0,4,8,...); letztere Bitplane wird um 1 Byte }
- MOV pl_adr3,CX {weitergesetzt: liefert (richtige) (4,8,12,...) }
- MOV pl_adr4,DX {(Planes abwechselnd von oben nach unten lesen!) }
- MOV AX,breite2 {Jetzt Planebreiten: }
- MOV BX,breite3 {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
- MOV CX,breite4
- MOV DX,breite1
- JMP @store
-
- @L10:
- CMP AL,2
- JNE @L20
-
- MOV AX,pl_adr3 {Verschiebung um 2 Bit: }
- MOV BX,pl_adr4 {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
- MOV CX,pl_adr1
- INC CX
- MOV DX,pl_adr2
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite3 {dto. fuer Planebreiten: }
- MOV BX,breite4 {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
- MOV CX,breite1
- MOV DX,breite2
- JMP @store
- @L20:
- MOV AX,pl_adr4 {Verschiebung um 3 Bit: }
- MOV BX,pl_adr1 {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
- INC BX
- MOV CX,pl_adr2
- INC CX
- MOV DX,pl_adr3
- INC DX
- MOV pl_adr1,AX
- MOV pl_adr2,BX
- MOV pl_adr3,CX
- MOV pl_adr4,DX
- MOV AX,breite4 {dto. fuer Planebreiten: }
- MOV BX,breite1 {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
- MOV CX,breite2
- MOV DX,breite3
- @store:
- MOV breite1,AX
- MOV breite2,BX
- MOV breite3,CX
- MOV breite4,DX
-
- @no_exchange: {jetzt gilt: (pl_adr?,breite?) enthalten die Source-}
- {Bitplanes/-breiten in der richtigen Reihenfolge }
-
- MOV AX,topcut
- SUB hoehe,AX {Hoehe um evtl. oberen cutoff korrigieren}
- MOV AX,licutoff
- SUB breite,AX {dto. fuer Breite und linken cutoff}
-
- MOV AX,x {falls Ausschnitt ueber rechten Bildschirmrand}
- ADD AX,breite {ragen wuerde: rechten cutoff bestimmen }
- SUB AX,XMAX+1
- JLE @no_recutoff
- SUB breite,AX {AX Punkte rechts abschneiden}
- @no_recutoff:
-
- MOV AX,y {genau dasselbe fuer unteren Bildschirmrand}
- ADD AX,hoehe
- SUB AX,YMAX+1
- JLE @no_bocutoff
- SUB hoehe,AX {AX Zeilen unten abschneiden}
- @no_bocutoff:
-
-
- LDS SI,p
- ADD pl_adr2,SI {Offsetanteil des Zeigers zu den Planeadr. addieren}
- ADD pl_adr3,SI
- ADD pl_adr4,SI
-
- ADD SI,pl_adr1 {breite,hoehe und Teile oberhalb des Bildschirms}
- MOV ES,SegmAdr
-
- MOV DI,y
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI:=y*LINESIZE}
- MOV AX,x
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI:=y*LINESIZE +(x DIV 4)}
- MOV StartAdr,DI
- MOV actualAdr,DI
-
- AND BX,3 {Startplane:=x mod 3}
- MOV AH,CS:[OFFSET CS_TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {als Schreibplane anwaehlen}
-
- MOV DX,hoehe
- MOV DI,actualAdr
-
- {DS:SI = Zeiger auf Daten, ES:DI = Zieladresse dafuer auf dem Schirm,}
- {AH = Bitmaske fuer Zugriff, AL = 2 }
- MOV BX,breite
- ADD BX,3
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L1:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite1
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L1
-
-
- SHL AH,1 {naechste Bitplane anwaehlen; bei einem wrap von}
- CMP AH,16 {Bitplane 3 zu Bitplane 0 muss dabei die Start- }
- JNE @nowrap1 {adresse um 1 Byte weitergesetzt werden }
- MOV AH,1
- INC StartAdr
- @nowrap1:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr2
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L2:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite2
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L2
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap2
- MOV AH,1
- INC StartAdr
- @nowrap2:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr3
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- INC BX
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L3:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite3
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L3
-
-
- SHL AH,1
- CMP AH,16
- JNE @nowrap3
- MOV AH,1
- INC StartAdr
- @nowrap3:
- MOV DX,3C4h
- OUT DX,AX
- MOV SI,pl_adr4
- MOV DI,StartAdr
- MOV actualAdr,DI
- MOV DX,hoehe
- MOV BX,breite
- SHR BX,1
- SHR BX,1
- mov cx,bx
- @L4:
- push si
- SHR CX,1 {schneller als "REP MOVSB"}
- REP MOVSW
- ADC CX,0
- REP MOVSB
- pop si
- mov cx,bx
- add si,breite4
- MOV DI,actualAdr
- ADD DI,LINESIZE
- MOV actualAdr,DI
- DEC DX
- JNE @L4
-
- MOV AX,SEG @DATA
- MOV DS,AX
- END;
-
- END;
-
- PROCEDURE FreeImageMem(p:POINTER);
- { in: p = Zeiger auf per GetImage() gespeichertes Bild}
- {out: - }
- {rem: Der fuer das Bild reservierte Heap-Speicher wurde freigegeben}
- BEGIN
- IF p<>NIL THEN FreeMem(p,MEMW[Seg(p^):Ofs(p^)]*MEMW[Seg(p^):Ofs(p^)+2] + 2*2)
- END;
-
- PROCEDURE Screen(pa:BYTE);
- { in: pa = anzuzeigende Bildschirmseite (0..3) }
- {out: - }
- {rem: Es wurde auf die Darstellung der Grafikseite pa umgeschaltet }
- { Dabei wurde NICHT auf irgendwelche Retrace-Signale synchronisiert}
- { Sinnvoll sind nur die Seiten 0 oder 1, es findet aber keine }
- { Ueberpruefung statt!}
- BEGIN
- ASM
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-Startadress-Register}
- CLI {Darf keinenfalls unterbrochen werden!}
- OUT DX,AL
- INC DX
- {Realisiere "AX:=Offset_Adr[pa]":}
- MOV BL,pa
- MOV SI,BX
- AND SI,3 {Page-Wert *2 (da Worteintraege!)}
- SHL SI,1 {dazu Startadresse des Feldes addieren}
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. Verschiebung korrigieren}
- LODSW {und Wert holen}
- OUT DX,AL {LB der neuen Startadresse setzen}
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {HB der neuen Startadresse setzen}
- OUT DX,AL
- STI
- END;
- END;
-
- PROCEDURE InitGraph;
- { in: PAGE = aktuelle Grafikseite}
- {out: - }
- {rem: Schaltet die VGA-Karte in den 320x200x256x4-Modus; ACHTUNG! }
- { Dieser Modus ist verschieden vom Modus $13 der VGA!!! }
- { Dabei wird auf die Darstellung der Seite 1-PAGE geschaltet }
- { Es werden die Defaultfarben des Modus $13 gesetzt! }
- BEGIN
- ASM
- MOV AX,0013h {Mit BIOS Grafikmodus $13 (=320x200x256) setzen }
- INT 10h
- MOV DX,03C4h {im Sequenzer das Speichermodusregister auswaehlen}
- MOV AL,04
- OUT DX,AL
- INC DX {Daten ueber das zugehoerige Datenregister lesen }
- IN AL,DX
- AND AL,0F7h {Bit 3:=0:4 Planes nicht chainen}
- OR AL,04 {Bit 2:=1:kein odd/even-Mechan. }
- OUT DX,AL {Neuen Wert wirksam machen }
- MOV DX,03C4h {S.o.: Sequenzerregister2 (=Map-Maske) waehlen,...}
- MOV AL,02
- OUT DX,AL
- INC DX
- MOV AL,0Fh {...und Zugriff auf alle 4 Bitmaps erlauben }
- OUT DX,AL
- MOV AX,0A000h {Ab Segment A000h nun 8000h logische Woerter= }
- MOV ES,AX {4*8000h physikalische Woerter (wg. den 4 Bit- }
- SUB DI,DI {planes) auf 0 setzen }
- MOV AX,DI
- MOV CX,8000h
- CLD
- REP STOSW
-
- MOV DX,CRTAddress {im CRT-Controller das underline-location-Re- }
- MOV AL,14h {gister auswaehlen, den Wert aus dem zugehoerigen }
- OUT DX,AL {Datenregister auslesen: }
- INC DX
- IN AL,DX
- AND AL,0BFh {Bit 6:=0: keine Doppelwortadressierung von Daten }
- OUT DX,AL {im Bildschirmspeicher durchfuehren }
- DEC DX
- MOV AL,17h {Mode-control-Register auswaehlen }
- OUT DX,AL
- INC DX
- IN AL,DX
- OR AL,40h {Bit 6:=1: Adressierung des Speichers=lineares Bitfeld}
- OUT DX,AL
- END;
- Screen(1-PAGE); {sichtbar ist immer die nichtaktuelle Grafikseite}
- SetPalette(DefaultColors,FALSE) {Standardpalette setzen, sicher ist sicher}
- END;
-
-
- PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
- { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
- { Color = Farbe (0..255) }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- { pa = Grafikseite, auf der gezeichnet werden soll (0..2) }
- {out: - }
- {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2) }
- { in der Farbe COLOR gezeichnet; die Routine fuehrt dabei selber die }
- { Umrechnung der angeg. Koordinaten in absolute Bildschirmkoordinaten }
- { sowie evtl. notwendige Clipping-Schritte aus. }
- { Die Linie wird NICHT automatisch in den Hintergrund uebernommen, }
- { d.h.: sie ist nur fuer einen Animationszyklus sichtbar (soll sie }
- { permanent bleiben, so muss sie in den Hintergrund gezeichnet werden!)}
- { (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
- { zufuehren, da die gezeichnete Linie sonst sofort wieder verschwindet)}
- CONST CodeLinks =$7; {%0111}
- CodeRechts=$B; {%1011}
- CodeOben =$D; {%1101}
- CodeUnten =$E; {%1110}
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE
- {zuerst Linie auf sichtbaren Bereich zurechtklippen; dazu Sutherland-}
- {Cohen-Algorithmus verwenden: 4 Bit-Code fuer links|rechts|oben|unten}
- ASM
- CLD
- MOV CL,$F {mit %1111 anfangen}
- MOV AX,x2
- SUB AX,StartVirtualX {x2 in absolute Koordinaten umrechnen}
- MOV x2,AX
- OR AX,AX {x2<0 ?}
- JL @GC1Punkt2 {ja, Flag fuer "Punkt links vom Fenster" belassen}
- AND CL,CodeLinks {nein, Flag ruecksetzen}
- @GC1Punkt2:
- CMP AX,XMAX {x2>XMAX ?}
- JG @GC2Punkt2 {ja, Flag fuer "Punkt rechts vom Fenster" belassen}
- AND CL,CodeRechts {nein, Flag ruecksetzen}
- @GC2Punkt2:
- MOV AX,y2
- SUB AX,StartVirtualY {y2 in absolute Koordinaten umrechnen}
- MOV y2,AX
- OR AX,AX {y2<0 ?}
- JL @GC3Punkt2 {ja, Flag fuer "Punkt oberhalb des Fensters" bel.}
- AND CL,CodeOben {nein, Flag ruecksetzen}
- @GC3Punkt2:
- CMP AX,YMAX {y2>YMAX ?}
- JG @GC4Punkt2 {ja, Flag fuer "Punkt unterhalb des Fensters" bel.}
- AND CL,CodeUnten
- @GC4Punkt2: {CL enthaelt jetzt den Gebietscode fuer Punkt 2}
-
- MOV AX,x1
- SUB AX,StartVirtualX {x1 in absolute Koordinaten umrechnen}
- MOV x1,AX
- MOV AX,y1
- SUB AX,StartVirtualY {y1 in absolute Koordinaten umrechnen}
- MOV y1,AX
-
- @Punkt1:
- MOV CH,$F {mit %1111 anfangen}
- MOV AX,x1
- OR AX,AX {x1<0 ?}
- JL @GC1Punkt1 {ja, Flag fuer "Punkt links vom Fenster" belassen}
- AND CH,CodeLinks {nein, Flag ruecksetzen}
- @GC1Punkt1:
- CMP AX,XMAX {x1>XMAX ?}
- JG @GC2Punkt1 {ja, Flag fuer "Punkt rechts vom Fenster" belassen}
- AND CH,CodeRechts {nein, Flag ruecksetzen}
- @GC2Punkt1:
- MOV AX,y1
- OR AX,AX {y1<0 ?}
- JL @GC3Punkt1 {ja, Flag fuer "Punkt oberhalb des Fensters" bel.}
- AND CH,CodeOben {nein, Flag ruecksetzen}
- @GC3Punkt1:
- CMP AX,YMAX {y1>YMAX ?}
- JG @GC4Punkt1 {ja, Flag fuer "Punkt unterhalb des Fensters" bel.}
- AND CH,CodeUnten
- @GC4Punkt1: {CH enthaelt jetzt den Gebietscode fuer Punkt 1}
-
- {CL enthaelt den Gebietscode fuer Punkt 2, CH den fuer Punkt 1}
-
- MOV AX,CX
- AND AL,AH {Code1 AND Code2 <>0 ?}
- JNZ @LineReady {ja, Linie ganz ausserhalb des Windows}
- MOV AX,CX
- OR AL,AH {Code1 OR Code2 =0 ?}
- JZ @DrawLine {ja, Linie ganz innerhalb des Windows}
-
- {Nun eigentliches Clipping vornehmen: }
- MOV AX,CX
- OR AH,AH {Code1 =0 ?}
- JNZ @CL3 {nein, alles ok}
- MOV AX,x1 {ja, Punkte vertauschen!}
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
- XCHG CL,CH
- @CL3:
- MOV AL,CH {AL:=Code1}
- MOV BX,x2
- SUB BX,x1 {BX:=x2-x1}
- MOV SI,y2
- SUB SI,y1 {SI:=y2-y1}
- TEST AL,NOT CodeLinks {Punkt1 links des Windows?}
- JZ @CL4 {nein}
- {ja, neue Koordinaten berechnen: y1:=y1+(y2-y1)/(x2-x1)*(WindowX1-X1) }
- {und x1:=WindowX1 (dabei ist WindowX1 = 0) }
- XOR AX,AX
- XCHG AX,x1 {x1:=0}
- NEG AX {AX:=-x1old}
- IMUL SI
- IDIV BX
- ADD y1,AX
- JMP @Punkt1
-
- @CL4:
- TEST AL,NOT CodeRechts {Punkt1 rechts des Windows?}
- JZ @CL5 {nein}
- {ja, berechne: y1:=y1+(y2-y1)/(x2-x1)*(WindowX2-X1), x1:=WindowX2 }
- { (wobei WindowX2=XMAX) }
- MOV AX,XMAX
- SUB AX,x1
- IMUL SI
- IDIV BX
- ADD y1,AX
- MOV x1,XMAX
- JMP @Punkt1
-
- @CL5:
- TEST AL,NOT CodeOben {Punkt1 oberhalb des Windows?}
- JZ @CL6 {nein}
- {ja, berechne x1:=x1+(x2-x1)/(y2-y1)*(WindowY1-y1), y1:=WindowY1 }
- { (wobei WindowY1=0) }
- XOR AX,AX
- XCHG AX,y1
- NEG AX
- IMUL BX
- IDIV SI
- ADD x1,AX
- JMP @Punkt1
-
- @CL6:
- TEST AL,NOT CodeUnten {Punkt unterhalb des Windows?}
- JZ @Punkt1 {nein}
- {ja, berechne x1:=x1+(x2-x1)/(y2-y1)*(WindowY2-y1), y1:=WindowY2 }
- { (wobei WindowY2=YMAX) }
- MOV AX,YMAX
- SUB AX,y1
- IMUL BX
- IDIV SI
- ADD x1,AX
- MOV y1,YMAX
- JMP @Punkt1
-
- {Hier gilt: die beiden Punkte wurden auf den sichtbaren Bereich zurecht-}
- {gestutzt; sollte die Gerade keinen sichtbaren Teil besitzen, so wurde }
- {direkt zu @LineReady verzweigt! }
- @DrawLine:
- PUSH BP
- MOV Steigung,0 {Flag zuruecksetzen}
- MOV CX,x2
- SUB CX,x1 {Punkt1 rechts von Punkt2 ?}
- JGE @posDX {nein}
- NEG CX {ja, Punkte vertauschen}
- MOV AX,x1
- XCHG AX,x2
- MOV x1,AX
- MOV AX,y1
- XCHG AX,y2
- MOV y1,AX
-
- @posDX:
- MOV DI,y1
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI] {DI:=y1*LINESIZE}
- MOV AX,x1
- MOV BL,AL
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI:=y1*LINESIZE+(x1 DIV 4) }
-
- AND BX,3 {BX:=(x1 AND 4) }
- MOV DH,[OFFSET TranslateTab + BX] {Maske fuer VRAM-Zugriff holen}
- MOV DL,2
-
- MOV BL,pa {BH=0 -> BX=Zeichenseite}
- SHL BX,1
- ADD BX,OFFSET Segment_Adr -StartIndex*2
- MOV ES,[BX]
-
- {ES:DI=Zeiger auf Grafikadresse von Punkt1, DX=Zugriffsmaske dafuer}
- MOV SI,LINESIZE
- MOV BX,y2
- SUB BX,y1 {Punkt1 unterhalb von Punkt2 ?}
- JG @posDY {nein}
- NEG BX {ja, deltaY und Zeileninkrement negieren}
- NEG SI
-
- @posDY:
- CMP BX,CX {deltaY>deltaX ?}
- JLE @flach {nein: geringe Steigung, <=1 }
- XCHG BX,CX {ja, deltas vertauschen und Flag setzen}
- MOV Steigung,1
-
- {Jetzt Bresenham-Parameter berechnen: 2*DY, 2*DY-DX, 2*(DY-DX) }
- @flach:
- SHL BX,1
- MOV DY_mal2,BX
- SUB BX,CX
- MOV BP,BX {BP:=2*DY-DX}
- SUB BX,CX
- MOV DY_m_DX_mal2,BX
- INC CX {CX:=Anzahl Pixel}
- MOV BL,Color
- MOV BH,1
- CMP Steigung,0 {steile Linie?}
- JNZ @high1 {ja}
-
- @low1: {nein}
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX {richtige Bitplane anwaehlen}
- MOV DX,AX {Maske wieder nach DX retten}
- MOV AL,BL {Farbe fuer Punkt holen}
- STOSB {Punkt setzen}
- SHL DH,1 {Maske fuer naechsten Punkt berechnen }
- CMP DH,16 {noch mit derselben Adresse ansprechbar? }
- JE @nextbyte1 {nein, Adr. muss(te) um 1 erhoeht werden }
- DEC DI {ja, Erhoehung von DI rueckgaengig machen }
- @low1b:
- OR BP,BP
- JGE @low2
- ADD BP,DY_mal2
- LOOP @low1
- JMP @raus
- @nextbyte1:
- MOV DH,BH {Maske auf 1 zuruecksetzen}
- JMP @low1b {Rest wie gehabt}
-
- @low2:
- ADD BP,DY_m_DX_mal2
- ADD DI,SI
- LOOP @low1
- JMP @raus
-
-
- @high1:
- MOV AX,3C4h
- XCHG AX,DX
- OUT DX,AX
- MOV DX,AX
- MOV AL,BL
- @high1b:
- OR BP,BP
- JGE @high2
- ADD BP,DY_mal2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1b
- JMP @raus
-
- @high2:
- ADD BP,DY_m_DX_mal2
- SHL DH,1
- CMP DH,16
- JE @nextbyte2
- MOV ES:[DI],AL
- ADD DI,SI
- LOOP @high1
- JMP @raus
- @nextbyte2:
- MOV DH,BH
- STOSB
- ADD DI,SI
- LOOP @high1
-
- @raus:
- POP BP
- @LineReady:
- END;
- END;
-
- PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
- { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
- { Color = Farbe (0..255) }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- {out: - }
- {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2) }
- { in der Farbe COLOR in den Hintergrundspeicher gezeichnet; die Rou- }
- { tine fuehrt dabei selber alle notwendigen Umrechnungen und Clipping-}
- { schritte aus. }
- { Die Linie wird NICHT sofort sichtbar, sondern erst im naechsten Ani-}
- { mationszyklus (dann allerdings permanent)! (Deshalb ist es sinnvoll,}
- { diese Routine VOR dem Aufruf von ANIMATE auszufuehren, da dann alle }
- { Aenderungen (durch ANIMATE) sofort sichtbar werden) }
- { Da als Hintergrundseite BACKGNDADR verwendet wird, ist die Verwen- }
- { dung der Routine nur fuer den Hintergrundmodus STATIC sinnvoll! }
- BEGIN
- Line(x1,y1,x2,y2,BACKGNDPAGE)
- END;
-
- FUNCTION GetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
- { PAGEADR= Grafikseite(nsegment), aus der gelesen werden soll }
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke }
- {out: Farbe des Punktes}
- {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird }
- { "0" als Ergebniswert zurueckgeliefert}
- { Achtung! Da PAGEADR immer die nichtsichtbare Grafikseite }
- { bezeichnet, liest diese Routine auch von dort die Punkte ein!}
- ASM
- XOR AL,AL {AL mit 0 vorbesetzen}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BL,3 {BL = X MOD 4 = Leseplane}
- MOV AL,4
- MOV AH,BL
- MOV DX,3CEh
-
- MOV ES,PAGEADR
- CLI
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
- FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke }
- {out: Farbe des Punktes der Hintergrundseite}
- {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird }
- { "0" als Ergebniswert zurueckgeliefert}
- { Da als Hintergrundseite BACKGNDADR verwendet wird, ist die }
- { Routine nur fuer den Hintergrundmodus STATIC sinnvoll! }
- ASM
- XOR AL,AL {AL mit 0 vorbesetzen}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BL,3 {BL = X MOD 4 = Leseplane}
- MOV AL,4
- MOV AH,BL
- MOV DX,3CEh
- MOV ES,BACKGNDADR
- CLI
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
- FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE; ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
- { pa = Grafikseite (0..3), von der der Punkt ausgelesen }
- { werden soll}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke }
- {out: Farbe des Punktes der Hintergrundseite}
- {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird }
- { "0" als Ergebniswert zurueckgeliefert}
- { Soll von der gerade SICHTBAREN Seite gelesen werden, so ist }
- { beim Aufruf als Seite "1-PAGE" anzugeben! }
- { Sinnvolle Werte fuer "pa" sind nur 0 und 1 (und evtl. BACK- }
- { GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es }
- { findet jedoch keine Ueberpruefung statt!}
- ASM
- XOR AL,AL {AL mit 0 vorbesetzen}
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3 {BL = X MOD 4 = Leseplane; BH = 0}
- MOV AL,4
- MOV AH,BL
- MOV BL,pa {BH=0 -> BX = Grafikseite}
- AND BX,3 {nur Seiten 0..3}
- SHL BX,1
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV ES,[BX]
-
- CLI
- MOV DX,3CEh
- OUT DX,AX
- MOV AL,ES:[DI]
- STI
- @offscrn:
- END;
-
-
- PROCEDURE PutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
- { color = Farbwert fuer den zu zeichnenden Punkt}
- { 1-PAGE = Grafikseite, auf der gezeichnet werden soll}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
- {out: - }
- {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet }
- { und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
- { Der Punkt wird NICHT automatisch in den Hintergrundspeicher ueber- }
- { nommen, d.h.: er ist nur einen Animationszyklus lang sichtbar! }
- { (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
- { zufuehren, da der gezeichnete Punkt sonst sofort wieder verschwindet)}
- ASM
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
-
- MOV BX,1 {ES:=Segment_Adr[1-PAGE], denn 1-PAGE=sichtbare Seite}
- SUB BX,PAGE
- SHL BX,1
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV ES,[BX]
-
- CLI
- OUT DX,AX
- MOV AL,color
- STOSB
- STI
- @offscrn:
- END;
-
- PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
- { color = Farbwert fuer den zu zeichnenden Punkt}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
- {out: - }
- {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet und}
- { in den Hintergrund gezeichnet (sofern er im sichtbaren Bereich liegt) }
- { Der Punkt wird NICHT sofort sichtbar, sondern erst nach einem Anima- }
- { tionszyklus (dann aber permanent) (Deshalb ist es sinnvoll, diese Rou- }
- { tine VOR dem Aufruf von ANIMATE auszufuehren, so dass evtl. Aenderungen}
- { des Hintergrundes "sofort" sichtbar werden!) }
- { Da als Hintergrundseite BACKGNDADR verwendet wird, ist die Verwendung }
- { der Routine nur fuer den Hintergrundmodus STATIC sinnvoll!}
- ASM
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV ES,BACKGNDADR
- CLI
- OUT DX,AX
- MOV AL,color
- STOSB
- STI
- @offscrn:
- END;
-
- PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte); ASSEMBLER;
- { in: x,y = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
- { color = Farbwert fuer den zu zeichnenden Punkt}
- { pa = Grafikseite (0..3), auf der gezeichnet werden soll }
- { PAGEADR= Grafikseite(nsegment), auf der gezeichnet werden soll}
- { StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
- {out: - }
- {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet }
- { und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
- { Soll auf die gerade SICHTBARE Seite gezeichnet werden, so ist}
- { beim Aufruf als Seite "1-PAGE" anzugeben! }
- { Auch hier gilt, dass der gezeichnete Punkt NICHT automatisch }
- { in den Hintergrundspeicher uebernommen wird, d.h.: er ist nur}
- { bis zum naechsten Animationszyklus (= Aufruf von ANIMATE) }
- { sichtbar! (Deshalb ist es sinnvoll, diese Routine NACH Aufruf}
- { von ANIMATE auszufuehren, da der gezeichnete Punkt sonst so- }
- { fort wieder verschwindet!) }
- { Sinnvolle Werte fuer "pa" sind nur 0 und 1 (und evtl. BACK- }
- { GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es }
- { findet jedoch keine Ueberpruefung statt!}
- ASM
- MOV DI,y
- SUB DI,StartVirtualY {y in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP DI,YMAX
- JG @offscrn
- MOV BX,x
- SUB BX,StartVirtualX {x in absolute Koordinaten umrechnen}
- JS @offscrn
- CMP BX,XMAX
- JG @offscrn
- SHL DI,1
- MOV DI,CS:[OFFSET gadr + DI]
- {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
- MOV AX,BX
- SHR AX,1
- SHR AX,1
- ADD DI,AX {DI = Y*LINESIZE+(X SHR 2) }
- AND BX,3
- MOV AH,[OFFSET TranslateTab + BX]
- MOV AL,2
- MOV DX,3C4h
- MOV BL,pa {BH=0 -> BX=Grafikseite}
- SHL BX,1
- ADD BX,OFFSET Segment_Adr+StartIndex*2
- MOV ES,[BX]
-
- CLI
- OUT DX,AX
- MOV AL,color
- STOSB
- STI
- @offscrn:
- END;
-
-
- PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
- { in: (x,y) = (virtuelle) Startkoordinaten des auszugebenden Textes}
- { s = auszugebender Textstring }
- { pa = Grafikseite, auf der der Text ausgegeben werden soll }
- { GraphTextColor=Textfarbe }
- { GraphTextBackground=Farbe fuer Texthintergrund;ist dieser Wert}
- { =GraphTextColor, so werden nur die Textpixel gezeichnet}
- { und die umgebenden Pixel unveraendert gelassen (=nor- }
- { males Verhalten von TurboPascal's OutText-Routinen!) }
- { GraphTextOrientation="vertical" oder "horizontal" }
- { StartVirtualX,StartVirtualY = linke obere Bildschirmecke }
- {out: Text wurde auf dem Bildschirm ausgegeben }
- VAR z,b,bit,i:BYTE;
- data:Fontchar;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber;
- exit
- END;
- FOR i:=1 TO Length(s) DO
- BEGIN
- data:=FontData[ord(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=data[z];
- FOR bit:=0 TO FontWidth-1 DO
- IF b and FontMask[bit]<>0
- THEN PagePutPixel(x+bit,y+z,GraphTextColor,pa)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,FontWidth)
- ELSE INC(y,FontHeight);
- END;
- END;
-
- PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
- {rem: Wie OutTextXY(), aber es wird in den Hintergrund geschrieben und}
- { nicht in die durch PAGEADR spezifizierte Seite! }
- { Da als Hintergrundseite BACKGNDADR verwendet wird, ist die }
- { Routine nur fuer den Hintergrundmodus STATIC sinnvoll!}
- VAR z,b,bit,i:BYTE;
- data:Fontchar;
- BEGIN
- FOR i:=1 TO Length(s) DO
- BEGIN
- data:=FontData[ord(s[i])];
- FOR z:=0 TO FontHeight-1 DO
- BEGIN
- b:=data[z];
- FOR bit:=0 TO FontWidth-1 DO
- IF b and FontMask[bit]<>0
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextColor)
- ELSE IF (GraphTextColor<>GraphTextBackground)
- THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
- END;
- IF GraphTextOrientation=horizontal
- THEN INC(x,FontWidth)
- ELSE INC(y,FontHeight);
- END;
- END;
-
-
- FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN; ASSEMBLER;
- { in: s1,s2 = Spritepositionsnummern zweier Sprites}
- { SpriteN[s1],SpriteX[s1],SpriteY[s1] = Spritedaten von Sprite s1 }
- { SpriteN[s2],SpriteX[s2],SpriteY[s2] = Spritedaten von Sprite s2 }
- {out: TRUE/FALSE fuer "Sprites kollidieren"/"Sprites kollidieren nicht" }
- {rem: Diese Ueberpruefung geschieht punktgenau und ist unabhaengig davon,}
- { ob die Sprites z.Z. gerade sichtbar sind oder nicht. }
- { Inaktive Sprites (SpriteN[s?]=0) koennen nicht miteinander kollid. }
- { Ein Sprite kann nicht mit sich selbst kollidieren (s1=s2 -> FALSE) }
- ASM
- MOV SI,s1 {1.Parameter s1 vom Stack holen}
- MOV DI,s2 {2.Parameter s2 vom Stack holen}
- CMP SI,DI
- JE @NOHIT1 {Sprite kann sich nicht selbst treffen}
- SHL SI,1
- mov cx,[SI + OFFSET SpriteN]
- jcxz @NOHIT1 {Sprite <>0, d.h.: ueberhaupt aktiv?}
- SHL DI,1
- MOV BX,[DI + OFFSET SpriteN]
- OR BX,BX {dto. fuer anderes Sprite}
- JNE @PRUEF2
- @NOHIT1:
- JMP @NOHIT7 {inaktive Sprites koennen auch nicht}
- {kollidieren -> FALSE zurueckgeben }
- {hier: SI (DI) = Zeiger auf 1. (2.) Sprite in ?WRTD[..] ,}
- { CX (BX) = Spritenummer von Sprite 1 (2) }
- {(etwas spaeter wird dann DS (ES) = Segment der Spr.daten von Spr.1 (2) )}
- @PRUEF2:
- MOV AX,[SI + OFFSET SpriteY]
- MOV DX,[DI + OFFSET SpriteY]
- mov si,[SI + OFFSET SpriteX] {SI=x1}
- mov di,[DI + OFFSET SpriteX] {DI=x2}
- shl bx,1 {BX=Spritenummer2*2}
- mov es,[BX + OFFSET SPRITEAD] {ES=Segment der Spritedaten2}
- mov bx,cx {(CX=Spritenummer1)}
- shl bx,1 {BX=Spritenummer1*2}
- MOV ds,[BX + OFFSET SPRITEAD]
-
- mov [y1],ax
- mov [y2],dx
- sub dx,ax
- mov CS:WORD PTR @y2_y1+1,dx
- mov [x1],si
- mov [x2],di
- mov dx,di
- sub dx,si
- mov CS:WORD PTR @x2_x1+1,dx
- mov ax,es:[Left] {AX=Zeiger auf linke Randdaten}
- mov CS:WORD PTR @lirand2+1,ax
- mov ax,es:[Right] {AX=Zeiger auf rechte Randdaten}
- mov CS:WORD PTR @rerand2+1,ax
- mov ax,es:[Top] {AX=Zeiger auf obere Randdaten}
- mov CS:WORD PTR @orand2+1,ax
- mov ax,es:[Bottom] {AX=Zeiger auf untere Randdaten}
- mov CS:WORD PTR @urand2+1,ax
- mov ax,es:[Breite] {AX=max. Breite in 4er-Gruppen}
- shl al,1
- shl al,1
- mov CS:WORD PTR @breite2+1,ax {*4 = Breite in Punkten}
- mov ax,es:[Hoehe]
- mov CS:WORD PTR @hoehe2+1,ax {Hoehe von Sprite2 in Punkten}
-
- MOV AX,[Left] {AX=Zeiger auf linke Randdaten}
- MOV CS:WORD PTR @LIRAND1+1,AX
- MOV AX,[Right] {AX=Zeiger auf rechte Randdaten}
- MOV CS:WORD PTR @RERAND1+1,AX
- MOV AX,[Top] {AX=Zeiger auf obere Randdaten}
- MOV CS:WORD PTR @ORAND1+1,AX
- MOV AX,[Bottom] {AX=Zeiger auf untere Randdaten}
- MOV CS:WORD PTR @URAND1+1,AX
- MOV BX,[Breite] {BX=max. Breite in 4er-Gruppen}
- SHL BX,1
- SHL BX,1 {*4 = Breite in Punkten}
- MOV CS:WORD PTR @BREITE1+2,BX
-
- lea bx,[si+bx-1] {BX:=x1+breite1-1 (=x1last)}
- @breite2:
- mov bp,1234h {Dummywert}
- mov cx,bp {CX=breite2 brauchen wir spaeter nochmal}
- lea bp,[di+bp-1] {BP:=x2+breite2-1 (=x2last)}
- cmp bx,bp
- jle @noex1
- mov bp,bx
- @noex1: {hier: BP=max(x1last,x2last) (=maxx)}
- cmp si,di
- jle @X1_klgl_X2
- xchg si,di
- @X1_klgl_X2: {hier: SI=min(x1,x2) (=minx)}
- stc
- sbb si,bp {SI:=minx-maxx-1=-(maxx-minx+1)}
- @breite1:
- add cx,1234h {(Dummywert) CX:=breite1+breite2}
- add cx,si {CX:=breite1+breite2-(maxx-minx+1)}
- dec cx {CX:=breite1+breite2-(maxx-minx+1)-1 (=ueberlappx-1)}
- js @NOHIT2 {kein Treffer, wenn ueberlappx<=0}
- mov [ueberlappx_1],cx
-
- mov ax,[Hoehe]
- mov bx,ax {BX:=hoehe1}
- mov di,[y1] {DI:=y1}
- add ax,di {AX:=y1+hoehe1}
- dec ax {AX:=y1+hoehe1-1 (=y1last)}
- @hoehe2:
- mov si,1234h
- mov dx,[y2]
- add dx,si {DX:=y2+hoehe2}
- dec dx {DX:=y2+hoehe2-1 (=y2last)}
- cmp ax,dx
- jge @noex2
- mov ax,dx
- @noex2: {hier: AX=max(y1last,y2last) (=maxy)}
- mov dx,[y2]
- cmp di,dx {(DI=y1)}
- jle @noex3
- mov di,dx
- @noex3: {hier: DI=min(y1,y2) (=miny)}
- sub di,ax {DI:=miny-maxy=-(maxy-miny)}
- lea ax,[bx+si-2] {AX:=hoehe1+hoehe2-2}
- add ax,di {AX:=hoehe1+hoehe2-(maxy-miny+1)-1 (=ueberlappy-1)}
- js @NOHIT2 {kein Treffer, wenn ueberlappy<=0}
- mov [ueberlappy_1],ax
-
- {hier: AX=ueberlappy-1, CX=ueberlappx-1}
- @x2_x1:
- mov dx,1234h {Dummywert}
- xor bx,bx {ab jetzt: BX=0 !}
- or dx,dx
- js @X2_X1_kl_0 {if x2-x1>=0 then...}
- mov [hit2xfirst],bx {...hit2xfirst:=0}
- mov [hit1xfirst],dx {...hit1xfirst:=x2-x1}
- jmp @Yhits {SHORT}
-
- {Sprungleiste fuer NOHIT (passt hier gut hin)}
- @NOHIT2:
- JMP @NOHIT7
-
- {jetzt wieder normales Programm}
- @X2_X1_kl_0: {else (x2-x1<0)...}
- mov [hit1xfirst],bx {...hit1xfirst:=0}
- neg dx {DX:=x1-x2}
- mov [hit2xfirst],dx {...hit2xfirst:=x1-x2}
-
- @Yhits: {hier: AX=ueberlappy-1}
- @y2_y1:
- mov dx,1234h {Dummywert}
- or dx,dx
- js @Y2_Y1_kl_0 {if y2-y1>=0 then...}
- mov [hit2yfirst],bx {...hit2yfirst:=0}
- mov [hit1yfirst],dx {...hit1yfirst:=y2-y1}
- jmp @iterate {SHORT}
- @Y2_Y1_kl_0: {else (y2-y1<0)...}
- mov [hit1yfirst],bx {...hit1yfirst:=0}
- neg dx {DX:=y1-y2}
- mov [hit2yfirst],dx {...hit2yfirst:=y1-y2}
-
- {Nun werden iterativ die ueberlappenden Zeilen und Spalten exakt geprueft}
- @iterate:
- mov cx,[ueberlappy_1] {Anzahl der zu vergleichenden Zeilen -1}
- shl cx,1 {*2, da Word-Werte!}
- @lirand1:
- mov si,1234h {Dummywert}
- @lirand2:
- mov di,1234h {Dummywert}
- @rerand1:
- mov bx,1234h {Dummywert}
- @rerand2:
- mov bp,1234h {Dummywert}
- sub bx,si {BX:=rerand1-lirand1}
- sub bp,di {BP:=rerand2-lirand2}
- mov ax,[hit1yfirst]
- shl ax,1
- add si,ax {SI:=1.Zeile, in der Sp.1 mit Sp.2 ueberlappt}
- mov ax,[hit2yfirst]
- shl ax,1
- add di,ax {DI:=1.Zeile, in der Sp.2 mit Sp.1 ueberlappt}
- add si,cx {dto., letzte Zeile}
- add di,cx
- @one_line:
- mov ax,[si] {DS:AX:=x1li[Zeile]}
- mov dx,es:[di] {ES:DX:=x2li[Zeile]}
- add ax,[x1] {AX:=x1li[Zeile]+x1 (=c)}
- add dx,[x2] {DX:=x2li[Zeile]+x2 (=d)}
- cmp ax,dx
- jge @C_grgl_D
- mov ax,dx
- @C_grgl_D: {hier: AX=max(c,d)}
- mov cx,[si+bx] {DS:CX:=x1re[Zeile]}
- mov dx,es:[di+bp] {ES:DX:=x2re[Zeile]}
- add cx,[x1] {CX:=x1re[Zeile]+x1 (=a)}
- add dx,[x2] {DX:=x2re[Zeile]+x2 (=b)}
- cmp cx,dx
- jle @A_klgl_B
- mov cx,dx
- @A_klgl_B: {hier: CX=min(a,b)}
- cmp cx,ax {min(a,b)>=max(c,d) ?}
- jge @found_Xhit {ja: Treffer in X-Richtung gefunden!}
- dec si {naechste Zeile (-> Word-Werte!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappy_1]
- jns @one_line
- {kein Treffer in X-Richtung -> ueberhaupt kein Treffer!}
- jmp @NOHIT7
-
- {ansonsten: Treffer in X-Ri., jetzt noch Y-Ri. pruefen (analog zu oben) und }
- {"Treffer!" nur dann ausgeben, falls auch mind. 1 Treffer in Y-Ri. existiert}
- @found_Xhit:
- mov cx,[ueberlappx_1] {Anzahl der zu vergleichenden Spalten -1}
- shl cx,1 {*2, da Word-Werte!}
- @orand1:
- mov si,1234h {Dummywert}
- @orand2:
- mov di,1234h {Dummywert}
- @urand1:
- mov bx,1234h {Dummywert}
- @urand2:
- mov bp,1234h {Dummywert}
- sub bx,si {BX:=urand1-orand1}
- sub bp,di {BP:=urand2-orand2}
- mov ax,[hit1xfirst]
- shl ax,1 {*2, da Word-Werte!}
- add si,ax {SI:=orand1+2*hit1xfirst}
- mov ax,[hit2xfirst]
- shl ax,1 {*2, da Word-Werte!}
- add di,ax {DI:=orand2+2*hit2xfirst}
- add si,cx
- add di,cx
- @one_column: mov ax,[si] {AX:=y1ob[Spalte]}
- cmp ax,16000 {Dummywert fuer "leere Spalte"?}
- je @next_column {ja, also sicherlich kein Treffer}
- mov dx,es:[di] {DX:=y2ob[Spalte]}
- cmp dx,16000 {auch 2.Sprite pruefen: "leere Spalte"?}
- je @next_column {ja, kein Treffer}
- add ax,[y1] {AX:=y1ob+y1 (=c)}
- add dx,[y2] {DX:=y2ob+y2 (=d)}
- cmp ax,dx
- jge @C_grgl_D2
- mov ax,dx
- @C_grgl_D2: {hier: AX=max(c,d)}
- mov cx,[si+bx] {DS:CX:=y1un[Spalte]}
- mov dx,es:[di+bp] {ES:DX:=y2un[Spalte]}
- add cx,[y1] {CX:=y1un+y1 (=a)}
- add dx,[y2] {DX:=y2un+y2 (=b)}
- cmp cx,dx
- jle @A_klgl_B2
- mov cx,dx
- @A_klgl_B2: {hier: CX=min(a,b)}
- cmp cx,ax {min(a,b)>=max(c,d) ?}
- jge @HIT2 {ja: Treffer gefunden!}
- @next_column:
- dec si {nein, naechste Spalte (-> Word-Werte!)}
- dec si
- dec di
- dec di
- dec WORD PTR [ueberlappx_1]
- jns @one_column
-
- @NOHIT7:
- XOR AX,AX {als Ergebnis 0 = FALSE zurueckgeben}
- JMP @TREFF_END {SHORT}
- @HIT2:
- MOV AX,1 {als Ergebnis 1 = TRUE zurueckgeben}
-
- @TREFF_END:
- {$IFOPT G+}
- mov bp,sp {nur noetig fuer Compilerschalter G+!}
- {$ENDIF}
- mov dx,seg @DATA {sonst wird BP von TP wiederhergestellt}
- mov ds,dx
- END;
-
-
- PROCEDURE Animate;
- { in: PAGEADR = aktuelle Grafikseite(nadresse),auf der gezeichnet werden soll}
- { BACKGNDADR = Hintergrundseite(nadresse) }
- { BACKGROUNDMODE = STATIC/SCROLLING fuer festen/scrollbaren Hintergrund }
- { SpriteN[] = Spritenummern der darzustellenden Sprites }
- { SpriteX[],SpriteY[] = deren zugehoergigen (virtuellen) Koordinaten}
- { StartVirtualX,StartVirtualY = obere linke Bildschirmecke }
- { (PAGE = aktuell dargestellte Grafikseite) }
- {out: PAGE = 0/1, wenn PAGE vorher 1/0 war }
- { PAGEADR = neue, aktuelle Grafikseite(nadresse) }
- {rem: Animate loescht den Inhalt der alten Grafik (mithilfe der Hintergrund- }
- { seite), zeichnet alle sichtbaren Sprites, synchronisiert auf das dis- }
- { playenable-Signal und schaltet dann auf die so fertiggestellte Seite um}
- VAR offsetXTiles,offsetYTiles,offsetXPix,offsetYPix:INTEGER;
- leftcut,rightcut,topcut,bottomcut,tiles:WORD;
- x,y,xpix,ypix,xtil,ytil,actindex,randindex,index:INTEGER;
- offscreenFlag:BYTE;
- yt,xt:INTEGER;
- BEGIN
- ASM
- CLD
- {zuerst das Hintergrundbild auf die aktuelle Seite kopieren:}
- CMP BackgroundMode,STATIC {welcher Hintergrundmodus?}
- JE @static_bckgnd
- JMP @scrolling_bckgnd
-
- @static_bckgnd:
- MOV AX,0F02h {alle 4 Planes gleichzeitig beschreiben}
- MOV DX,3C4h
- OUT DX,AX
- MOV AX,4105h {Schreibmodus 1 waehlen}
- MOV DX,3CEh
- OUT DX,AX
-
- MOV ES,PAGEADR {Grafikseite mit Hintergrundmuster fuellen}
- MOV DS,BACKGNDADR
- XOR SI,SI
- MOV DI,SI
- MOV CX,PAGESIZE
-
- REP MOVSB
-
- MOV AX,SEG @DATA
- MOV DS,AX
- MOV AX,4005h {Writemode 0 setzen}
- MOV DX,3CEh
- OUT DX,AX
-
- JMP @Sprites_zeichnen
-
- {---------------------------------}
-
- @scrolling_bckgnd: {ab hier: Hintergrund aus Kacheln zusammensetzen}
- MOV AX,StartVirtualY
- MOV BX,AX {AX=BX=StartVirtualY}
- SUB AX,BackY1
- ADD AX,15 {offsetYTiles:=(StartVirtualY-BackY1+15) DIV 16}
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV offsetYTiles,AX
- MOV ytil,AX {ytil:=offsetYTiles}
- DEC AX
- IMUL XTiles
- MOV actIndex,AX {actIndex:=(ytil-1)*XTiles, "+xtil" kommt spaeter}
-
- MOV AX,16
- SUB AX,BX {BX=StartVirtualY}
- AND AX,$F
- MOV ypix,AX {ypix:=(16-StartVirtualY) AND $F}
- SUB AX,200
- AND AX,$F
- MOV bottomcut,AX {bottomcut:=(ypix-200) AND $F}
-
- AND BX,$F {offsetYPix:=topcut:=StartVirtualY AND $F}
- MOV topcut,BX
- MOV offsetYPix,BX
-
- MOV AX,StartVirtualX
- MOV BX,AX {AX=BX=StartVirtualX}
- SUB AX,BackX1
- ADD AX,15 {offsetXTiles:=(StartVirtualX-BackX1+15) DIV 16}
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV offsetXTiles,AX
- MOV xtil,AX {xtil:=offsetXTiles}
- ADD actIndex,AX {actIndex:=(ytil-1)*XTiles+xtil}
-
- MOV AX,16
- SUB AX,BX {BX=StartVirtualX}
- AND AX,$F
- MOV xpix,AX {xpix=rightcut:=(16-StartVirtualX) AND $F}
- MOV rightcut,AX
-
- AND BX,$F {offsetXPix:=leftcut:=StartVirtualX AND $F}
- MOV leftcut,BX
- MOV offsetXPix,BX
-
- MOV AX,(XMAX+1)/16-1
- SUB BL,1 {C=1, wenn leftcut=0}
- ADC AX,0
- MOV tiles,AX {tiles:=19+ord(leftcut=0)}
-
-
- CMP topcut,0 {wenn topcut=0 ist, braucht die oberste}
- JE @do_innertiles {Tilezeile nicht gesondert gezeichnet werden}
-
- {oberste Tilezeile:}
- MOV DX,xtil
- MOV xt,DX
- MOV AX,ytil
- DEC AX
- MOV yt,AX
- MOV CL,1
- JS @offscreen
- CMP AX,YTiles
- JAE @offscreen
- DEC CL
- @offscreen: {CL=0/1 fuer offscreenFlag=false/true=(yt<0) OR (yt>=YTiles)}
- MOV offscreenFlag,CL
-
- CMP leftcut,0 {wenn leftcut=0 ist, muss die linke obere}
- JE @do_upperinnertiles {Ecke nicht gesondert gezeichnet werden }
-
- {linke obere Eck-Tile zeichnen:} {CL=offscreenFlag, DX=xt}
- XOR SI,SI {Tileindex bestimmen:}
- DEC CL {IF offscreenFlag OR (xt-1<0) OR (xt-1>=XTiles) }
- JZ @go1 { THEN index:=0 ELSE index:=actIndex}
- DEC DX
- JS @go1
- CMP DX,XTiles
- JAE @go1
- MOV SI,actIndex {=yt*XTiles+(xt-1)}
- @go1:
-
- {PROCEDURE DrawUpperLeftTile(leftcut,topcut:INTEGER; index:WORD);}
- { in: leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
- { topcut = dto., oben}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR bei (0,0) gezeichnet}
- {rem: Tile wurde links und oben entsprechend geschnitten}
- { leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
- { topcut muss zwischen 0 und 15 liegen, 16 ist verboten}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,topcut
- MOV CX,16
- SUB CX,SI {CX:=16-topcut = Anzahl zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1 {fuer jede oben abgeschnittene Zeile 4 Bytes}
- ADD SI,AX {zur (Offset-)Quelladresse in Page 3 addieren}
-
- XOR DI,DI {die erste Zieladresse ist DI:=0*LINESIZE+(0 div 4)=0}
-
- MOV AX,leftcut
- MOV BX,AX {Kopie von leftcut in BX aufbewahren}
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI um cutoff in Bytes weitersetzen=leftcut div 4}
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16+3
- SUB BP,BX {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
- {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3CEh
- AND BL,3
- MOV AH,BL {AH:=leftcut mod 4}
- MOV AL,4
-
- JNE @mode0a {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
- { Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge- }
- { fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die }
- { "11b" werden also beim Rechtsschieben eh abgeschnitten!}
- MOV AX,4105h
- OUT DX,AX {WriteMode 1 waehlen}
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig bearbeiten}
- OUT DX,AX
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- {Quell- und Zieladresse nicht mehr retten}
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4a1:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4a1
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @UpperLeftTileDone
-
- @mode0a:
- OUT DX,AX {aktuelle Leseplane waehlen}
- PUSH AX {und fuer spaeter merken}
-
- MOV DX,3C4h
- MOV AX,0102h {Schreibplane 0 waehlen}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane0_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane0_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile1a:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile1a
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0202h {Schreibplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap1a
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap1a:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane1_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane1_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane1_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile2a:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile2a
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0402h {Schreibplane 2 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap2a
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap2a:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane2_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane2_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane2_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile3a:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile3a
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0802h {Schreibplane 3 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap3a
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap3a:
- OUT DX,AX
-
-
- DEC BP {BP:=16-leftcut}
- @lastplane1:
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- {Quell- und Zieladresse nicht mehr retten}
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4a:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4a
-
- @UpperLeftTileDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- {Nun alle anderen oberen Kacheln, die nur oben (aber nicht seitlich)}
- {abgeschnitten sind: }
- @do_upperinnertiles:
- MOV AX,xpix
- MOV x,AX
- INC actIndex
-
- @repeat1: {Schleife wird genau "tiles" mal durchlaufen}
- MOV CL,offscreenFlag
- XOR SI,SI {Tileindex bestimmen:}
- DEC CL {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
- JZ @go2 { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
- MOV DX,xt
- OR DX,DX
- JS @go2
- CMP DX,XTiles
- JAE @go2
- MOV SI,actIndex
- @go2:
-
-
- {PROCEDURE DrawUpperTile(x,topcut:INTEGER; index:WORD);}
- { in: (x,0) = linke obere Ecke der zu zeichnenden Tile,}
- { topcut= Anzahl abzuschneidende Zeilen}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile muss links, rechts (und unten) ganz auf dem Bildschirm sein}
- { topcut muss im Stapel liegen (da DS andersweitig belegt wird!)}
- { topcut muss Werte zwischen 0..15 haben, 16 ist unzulaessig!}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1 {Das ist zugleich die (Offset-)Quelladresse in Page 3}
-
- MOV SI,topcut {Dazu kommen die oben abgeschnittenen Zeilen:}
- MOV CX,16 {fuer jede Zeile 4 Bytes}
- SUB CX,SI {CX:=16-topcut = zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1
- ADD SI,AX {SI = Zeiger auf erstes zu kopierendes Tilebyte}
-
- {Die erste Zieladresse ist DI:=0*LINESIZE+(x div 4) = x div 4}
- MOV DI,x
- MOV BX,DI {Kopie von X in BX aufbewahren}
- SHR DI,1
- SHR DI,1
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,CX
- SHL BP,1
- SHL BP,1 {BP := (zu zeichnende Zeilen)*4 }
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3 {BX:=Start-Schreibplane (Start-LESEplane=0)}
- JNE @mode0b {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
- MOV AH,0Fh {alle 4 Planes gleichzeitig bearbeiten}
- OUT DX,AX
- MOV AX,4105h
- MOV DX,3CEh
- OUT DX,AX {WriteMode 1 waehlen}
- MOV BX,CX {BX:=CX=zu zeichnende Zeilen}
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenzahl}
- @eineZeile4b1:
- MOVSB {kein MOVSW, da Writemode 1!}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile4b1
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @UpperTileDone
-
- @mode0b:
- MOV AH,CS:[OFFSET CS_TranslateTab+BX]
- OUT DX,AX
- PUSH AX {aktuelle Schreibplane merken}
-
- MOV DX,3CEh
- MOV AX,0004h {aktuelle Leseplane 0 waehlen}
- OUT DX,AX
-
- MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
- MOV BX,CX {zu zeichnende Zeilenzahl nach BX retten}
- @eineZeile1b:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile1b
-
- MOV AX,0104h {DX=3CEh -> Leseplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1b
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap1b:
- OUT DX,AX
- PUSH AX
- SHL BX,1 {DI wieder auf Ursprungsadresse zuruecksetzen:}
- SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
- SHR BX,1 {verringern (N.B.: BX=zu zeichnende Zeilen)}
- SUB SI,BP {SI auch zuruecksetzen}
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenanzahl}
- @eineZeile2b:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile2b
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2b
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap2b:
- OUT DX,AX {DX=3C4h -> Schreibplane setzen}
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h {Leseplane 2 setzen}
- OUT DX,AX
- SHL BX,1 {DI wieder auf Ursprungsadresse zuruecksetzen:}
- SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
- SHR BX,1 {verringern (N.B.: BX=zu zeichnende Zeilen)}
- SUB SI,BP {SI auch zuruecksetzen}
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenzahl}
- @eineZeile3b:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile3b
-
- MOV AX,0304h
- OUT DX,AX {DX=3CEh -> Leseplane 3 waehlen}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3b
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap3b:
- OUT DX,AX {DX=3C4h -> Schreibplane setzen}
- SHL BX,1 {DI wieder auf Ursprungsadresse zuruecksetzen:}
- SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
- SHR BX,1 {verringern (N.B.: BX=zu zeichnende Zeilen)}
- SUB SI,BP {SI auch zuruecksetzen}
-
-
- @lastPlane2:
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenzahl}
- @eineZeile4b:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile4b
-
- @UpperTileDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- INC xt {Tilezaehler in X-Richtung erhoehen}
- INC actIndex {wg. actIndex=yt*XTiles+xt auch actIndex erhoehen}
- MOV AX,x {aktuelle X-Koord. auch weitersetzen: x:=x+16}
- ADD AX,16
- MOV x,AX
- CMP AX,XMAX+1-16
- JBE @repeat1 {bis rechte obere Ecke erreicht}
-
- {Jetzt obere rechte Eck-Kachel - falls nicht schon gezeichnet:}
- CMP AX,XMAX+1
- JE @label1
-
- MOV CL,offscreenFlag {ja, Ecke muss noch gezeichnet werden}
- XOR SI,SI {Tileindex bestimmen:}
- DEC CL {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
- JZ @go3 { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
- MOV DX,xt
- OR DX,DX
- JS @go3
- CMP DX,XTiles
- JAE @go3
- MOV SI,actIndex
- @go3:
-
-
- {PROCEDURE DrawUpperRightTile(x,rightcut,topcut:INTEGER; index:WORD);}
- { in: (x,0) = linke obere Ecke der zu zeichnenden Tile}
- { rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
- { topcut = dto., oben}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile wurde rechts und oben entsprechend geschnitten}
- { topcut muss zwischen 0 und 15 liegen, 16 ist verboten}
- { rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
- { rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
- { rightcut := x+15-xmax }
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,topcut
- MOV CX,16
- SUB CX,SI {CX:=16-topcut = Anzahl zu zeichnende Zeilen}
- SHL SI,1
- SHL SI,1 {fuer jede oben abgeschnittene Zeile 4 Bytes}
- ADD SI,AX {zur (Offset-)Quelladresse in Page 3 addieren}
-
- MOV DI,x {erste Zieladresse ist DI:=0*LINESIZE +(x div 4)=x div 4}
- MOV BX,DI {Kopie von x nach BX}
- SHR DI,1
- SHR DI,1
-
- MOV AX,rightcut
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16+3
- SUB BP,AX {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
- {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
- MOV AH,AL {rightcut nach AH retten}
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3
-
- JNE @mode0c {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
- AND AH,3 {wir WriteMode1 verwenden!}
- JNE @mode0c
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
- MOV AH,0Fh
- OUT DX,AX {alle 4 Planes gleichzeitig bearbeiten}
- MOV DX,3CEh
- MOV AX,4105h {WriteMode 1 waehlen}
- OUT DX,AX
- SUB BP,3 {BP auf die richtige Groesse bringen}
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- {Quell- und Zieladresse nicht mehr retten}
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4c1:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4c1
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @UpperRightDone
-
- @mode0c:
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- OUT DX,AX {aktuelle Schreibplane waehlen}
- PUSH AX {und fuer spaeter merken}
-
- MOV DX,3CEh
- MOV AX,0004h {Leseplane 0 waehlen}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane0_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane0_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile1c:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile1c
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3CEh
- MOV AX,0104h {Leseplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1c
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap1c:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane1_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane1_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane1_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile2c:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile2c
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3CEh
- MOV AX,0204h {Leseplane 2 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2c
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap2c:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane2_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane2_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane2_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile3c:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile3c
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3CEh
- MOV AX,0304h {Leseplane 3 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3c
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap3c:
- OUT DX,AX
- {Wert nicht mehr pushen!}
-
-
- DEC BP {BP:=16-rightcut}
- @lastplane3:
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- {Quell- und Zieladresse nicht mehr retten}
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4c:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4c
-
- @UpperRightDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- @label1:
- MOV AX,actIndex {actIndex fuer naechste Tilezeile justieren:}
- STC {actIndex:=actIndex-tiles+1}
- SBB AX,tiles
- MOV actIndex,AX
-
- {Jetzt alle vollstaendig im Inneren des Bildschirms gelegenen }
- {(d.h.: nicht abgeschnittene) Tiles zeichnen:}
- @do_innertiles:
- MOV AX,ypix
- MOV y,AX
- MOV AX,actIndex
- ADD AX,XTiles
- MOV RandIndex,AX
- INC AX
- MOV actIndex,AX
-
- @repeat2:
- MOV AX,ytil
- MOV CL,1
- OR AX,AX
- JS @go4
- CMP AX,YTiles
- JAE @go4
- DEC CL
- @go4:
- MOV offscreenFlag,CL
- MOV AX,xpix
- MOV x,AX
- MOV AX,offsetXTiles
- MOV xtil,AX
-
- @repeat3:
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go5
- OR AX,AX
- JS @go5
- CMP AX,XTiles
- JAE @go5
- MOV SI,actIndex
- @go5:
-
-
- {PROCEDURE DrawInnerTile(x,y:INTEGER; index:WORD);}
- { in: (x,y) = linke obere Ecke der zu zeichnenden Tile,}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile muss ganz auf dem Bildschirm sein, es findet}
- { kein Clipping statt}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,AX {Das ist zugleich die (Offset-)Quelladresse in Page 3}
-
- MOV DI,y {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {Kopie von X in BX aufbewahren}
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3 {BX:=Start-Schreibplane (Start-LESEplane=0)}
- JNE @mode0d {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
- MOV AH,0Fh {alle 4 Planes gleichzeitig bearbeiten}
- OUT DX,AX
- MOV AX,4105h
- MOV DX,3CEh
- OUT DX,AX {WriteMode 1 waehlen}
- MOV BX,4
-
- MOV AX,LINESIZE-4
- MOV BX,4 {16 Punkte = 4 Bytes}
- MOV CX,BX {kein "MOVSW", da Writemode1!}
- REP MOVSB {1.Zeile zeichnen}
- ADD DI,AX {DI auf naechste Zeile setzen}
- MOV CX,BX
- REP MOVSB {2.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {3.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {4.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {5.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {6.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {7.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {8.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {9.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {10.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {11.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {12.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {13.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {14.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {15.Zeile}
- ADD DI,AX
- MOV CX,BX
- REP MOVSB {16.Zeile}
-
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @InnerTileDone
-
- @mode0d:
- MOV AH,CS:[OFFSET CS_TranslateTab+BX]
- OUT DX,AX
- PUSH AX {aktuelle Schreibplane merken}
-
- MOV DX,3CEh
- MOV AX,0004h {aktuelle Leseplane 0 waehlen}
- OUT DX,AX
-
- MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
-
- MOVSW {16 horizontale Punkte = 4 Bytes pro Zeile}
- MOVSW {1.Zeile zeichnen}
- ADD DI,AX {DI auf naechste Zeile setzen}
- MOVSW {2.Zeile}
- MOVSW
- ADD DI,AX
- MOVSW
- MOVSW {3.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {4.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {5.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {6.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {7.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {8.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {9.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {10.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {11.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {12.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {13.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {14.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {15.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {16.Zeile}
- ADD DI,AX
-
- MOV AX,0104h {DX=3CEh -> Leseplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1d
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap1d:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {DI wieder auf Ursprungsadresse zuruecksetzen}
- SUB SI,16*4 {SI auch}
-
-
- MOV AX,LINESIZE-4
- MOVSW
- MOVSW {1.Zeile zeichnen}
- ADD DI,AX {DI auf naechste Zeile setzen}
- MOVSW
- MOVSW {2.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {3.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {4.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {5.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {6.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {7.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {8.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {9.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {10.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {11.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {12.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {13.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {14.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {15.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {16.Zeile}
- ADD DI,AX
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2d
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap2d:
- OUT DX,AX {DX=3C4h -> Schreibplane setzen}
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h {Leseplane 2 setzen}
- OUT DX,AX
- SUB DI,16*LINESIZE
- SUB SI,16*4
-
-
- MOV AX,LINESIZE-4
- MOVSW
- MOVSW {1.Zeile zeichnen}
- ADD DI,AX {DI auf naechste Zeile setzen}
- MOVSW
- MOVSW {2.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {3.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {4.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {5.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {6.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {7.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {8.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {9.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {10.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {11.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {12.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {13.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {14.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {15.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {16.Zeile}
- ADD DI,AX
-
- MOV AX,0304h
- OUT DX,AX {DX=3CEh -> Leseplane 3 waehlen}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3d
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap3d:
- OUT DX,AX {DX=3C4h -> Schreibplane setzen}
- SUB DI,16*LINESIZE
- SUB SI,16*4
-
-
- @lastPlane4:
- MOV AX,LINESIZE-4
- MOVSW
- MOVSW {1.Zeile zeichnen}
- ADD DI,AX {DI auf naechste Zeile setzen}
- MOVSW
- MOVSW {2.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {3.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {4.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {5.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {6.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {7.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {8.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {9.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {10.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {11.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {12.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {13.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {14.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {15.Zeile}
- ADD DI,AX
- MOVSW
- MOVSW {16.Zeile}
-
-
- @InnerTileDone:
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- INC actIndex
- MOV AX,xtil
- INC AX
- MOV xtil,AX
- MOV DX,x
- ADD DX,16
- MOV x,DX
- CMP DX,XMAX+1-16
- JBE @repeat3
-
- INC ytil
- MOV AX,actIndex
- SUB AX,tiles
- ADD AX,XTiles
- MOV actIndex,AX
- MOV AX,y
- ADD AX,16
- MOV y,AX
- CMP AX,YMAX+1-16
- JBE @repeat2
-
- {Jetzt die untere rechte Tile - falls sie nicht bereits schon gezeichnet}
- {wurde: }
- CMP bottomcut,0
- JE @do_raender
- MOV DX,offsetXTiles
- MOV xt,DX
- MOV AX,ytil
- MOV yt,AX
- MOV CL,1
- OR AX,AX
- JS @go6
- CMP AX,YTiles
- JAE @go6
- DEC CL
- @go6:
- MOV offscreenFlag,CL
- CMP leftcut,0
- JE @label2
- XOR SI,SI
- DEC CL
- JZ @go7
- DEC DX {DX=xt-1}
- JS @go7
- CMP DX,XTiles
- JAE @go7
- MOV SI,actIndex
- DEC SI
- @go7:
-
- {PROCEDURE DrawLowerLeftTile(y,leftcut,bottomcut:INTEGER; index:WORD);}
- { in: (0,y) = linke obere Ecke der zu zeichnenden Tile}
- { leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
- { bottomcut = dto., unten}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile wurde links und unten entsprechend geschnitten}
- { leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
- { bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
- { bottomcut koennte auch ausgerechnet werden ueber:}
- { bottomcut:=y+15-ymax}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,AX {Das ist zugleich die (Offset-)Quelladresse in Page 3}
-
- MOV DI,y {erste Zieladresse ist DI:=y*LINESIZE+(0 div 4)=y*LINESIZE}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
-
- MOV AX,leftcut
- MOV BX,AX {Kopie von leftcut in BX aufbewahren}
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI um cutoff in Bytes weitersetzen=leftcut div 4}
-
- MOV CX,16
- SUB CX,bottomcut {CX:=16-bottomcut = zu zeichnende Zeilen}
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16+3
- SUB BP,BX {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
- {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3CEh
- AND BL,3
- MOV AH,BL {AH:=leftcut mod 4}
- MOV AL,4
-
- JNE @mode0e {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
- { Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge- }
- { fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die }
- { "11b" werden also beim Rechtsschieben eh abgeschnitten!}
- MOV AX,4105h
- OUT DX,AX {WriteMode 1 waehlen}
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig bearbeiten}
- OUT DX,AX
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4d1:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4d1
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LowerLeftTileDone
-
- @mode0e:
- OUT DX,AX {aktuelle Leseplane waehlen}
- PUSH AX {und fuer spaeter merken}
-
- MOV DX,3C4h
- MOV AX,0102h {Schreibplane 0 waehlen}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane0_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane0_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile1d:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile1d
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0202h {Schreibplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap1e
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap1e:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane1_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane1_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane1_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile2d:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile2d
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0402h {Schreibplane 2 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap2e
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap2e:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane2_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane2_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane2_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile3d:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile3d
- POP CX
- POP BP
- POP DI
- POP SI
-
- MOV DX,3C4h
- MOV AX,0802h {Schreibplane 3 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap3e
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap3e:
- OUT DX,AX
- {Wert nicht mehr pushen!}
-
-
- DEC BP {BP:=16-leftcut}
- @lastplane5:
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4d:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4d
-
- @LowerLeftTileDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- @label2:
- MOV AX,xpix
- MOV x,AX
-
- {Jetzt die unteren Tiles, die nicht seitlich abgeschnitten sind:}
- @repeat4:
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go8
- MOV AX,xt
- OR AX,AX
- JS @go8
- CMP AX,XTiles
- JAE @go8
- MOV SI,actIndex
- @go8:
-
- {PROCEDURE DrawLowerTile(x,y,bottomcut:INTEGER; index:WORD);}
- { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
- { bottomcut = Anzahl der unten abzuschneidenden Tile-Zeilen}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile wurde unten entsprechend geschnitten}
- { bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten!}
- { bottomcut koennte auch ausgerechnet werden ueber:}
- { bottomcut:=y+15-ymax}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,AX {Das ist zugleich die (Offset-)Quelladresse in Page 3}
-
- MOV DI,y {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {Kopie von X in BX aufbewahren}
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV CX,16
- SUB CX,bottomcut {CX:=zu zeichnende Zeilenzahl = 16-bottomcut}
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,CX
- SHL BP,1
- SHL BP,1 {BP := (zu zeichnende Zeilen)*4 }
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3 {BX:=Start-Schreibplane (Start-LESEplane=0)}
- JNE @mode0f {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
- MOV AH,0Fh {alle 4 Planes gleichzeitig bearbeiten}
- OUT DX,AX
- MOV AX,4105h
- MOV DX,3CEh
- OUT DX,AX {WriteMode 1 waehlen}
- MOV BX,CX {BX:=CX=zu zeichnende Zeilen}
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenzahl}
- @eineZeile4e1:
- MOVSB {keine "MOVSW", da Writemode1!}
- MOVSB
- MOVSB
- MOVSB
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile4e1
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LowerTileDone
-
- @mode0f:
- MOV AH,CS:[OFFSET CS_TranslateTab+BX]
- OUT DX,AX
- PUSH AX {aktuelle Schreibplane merken}
-
- MOV DX,3CEh
- MOV AX,0004h {aktuelle Leseplane 0 waehlen}
- OUT DX,AX
-
- MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
- MOV BX,CX {zu zeichnende Zeilenzahl nach BX retten}
- @eineZeile1e:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile1e
-
- MOV AX,0104h {DX=3CEh -> Leseplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1f
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap1f:
- OUT DX,AX
- PUSH AX
- SHL BX,1 {DI wieder auf Ursprungsadresse zuruecksetzen:}
- SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
- SHR BX,1 {verringern (N.B.: BX=zu zeichnende Zeilen)}
- SUB SI,BP {SI auch zuruecksetzen}
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenanzahl}
- @eineZeile2e:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile2e
-
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2f
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap2f:
- OUT DX,AX {DX=3C4h -> Schreibplane setzen}
- PUSH AX
- MOV DX,3CEh
- MOV AX,0204h {Leseplane 2 setzen}
- OUT DX,AX
- SHL BX,1 {DI wieder auf Ursprungsadresse zuruecksetzen:}
- SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
- SHR BX,1 {verringern (N.B.: BX=zu zeichnende Zeilen)}
- SUB SI,BP {SI auch zuruecksetzen}
-
-
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenzahl}
- @eineZeile3e:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile3e
-
- MOV AX,0304h
- OUT DX,AX {DX=3CEh -> Leseplane 3 waehlen}
- MOV DX,3C4h
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3f
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap3f:
- OUT DX,AX {DX=3C4h -> Schreibplane setzen}
- SHL BX,1 {DI wieder auf Ursprungsadresse zuruecksetzen:}
- SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
- SHR BX,1 {verringern (N.B.: BX=zu zeichnende Zeilen)}
- SUB SI,BP {SI auch zuruecksetzen}
-
-
- @lastPlane6:
- MOV AX,LINESIZE-4
- MOV CX,BX {CX:=zu zeichnende Zeilenzahl}
- @eineZeile4e:
- MOVSW
- MOVSW
- ADD DI,AX {DI auf naechste Zeile setzen}
- LOOP @eineZeile4e
-
- @LowerTileDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- INC xt
- INC actIndex
- MOV AX,x
- ADD AX,16
- MOV x,AX
- CMP AX,XMAX+1-16
- JBE @repeat4
-
- {Jetzt evtl. noch die untere rechte Eck-Tile:}
- CMP AX,XMAX+1
- JE @do_raender
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go9
- MOV AX,xt
- OR AX,AX
- JS @go9
- CMP AX,XTiles
- JAE @go9
- MOV SI,actIndex
- @go9:
-
- {PROCEDURE DrawLowerRightTile(x,y,rightcut,bottomcut:INTEGER; index:WORD);}
- { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
- { rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
- { bottomcut = dto., unten}
- { bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
- { bottomcut koennte auch ausgerechnet werden ueber:}
- { bottomcut:=y+15-ymax}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile wurde rechts und unten entsprechend geschnitten}
- { rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
- { rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
- { rightcut := x+15-xmax }
- { bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
- { bottomcut koennte auch ausgerechnet werden ueber:}
- { bottomcut:=y+15-ymax}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,AX {Das ist zugleich die (Offset-)Quelladresse in Page 3}
-
- MOV DI,y {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {Kopie von x nach BX}
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV AX,rightcut
- MOV CX,16
- SUB CX,bottomcut {CX:=16-bottomcut = zu zeichnende Zeilen}
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16+3
- SUB BP,AX {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
- {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
- MOV AH,AL {rightcut nach AH retten}
-
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3
-
- JNE @mode0g {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
- AND AH,3 {wir WriteMode1 verwenden!}
- JNE @mode0g
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
- MOV AH,0Fh
- OUT DX,AX {alle 4 Planes gleichzeitig bearbeiten}
- MOV DX,3CEh
- MOV AX,4105h {WriteMode 1 waehlen}
- OUT DX,AX
- SUB BP,3 {BP auf die richtige Groesse bringen}
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BX:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4g1:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4g1
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LowerRightTileDone
-
- @mode0g:
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- OUT DX,AX {aktuelle Schreibplane waehlen}
- PUSH AX {und fuer spaeter merken}
-
- MOV DX,3CEh
- MOV AX,0004h {Leseplane 0 waehlen}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane0_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane0_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile1f:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile1f
- POP CX
- POP BP
- POP DI
- POP SI
-
-
- MOV DX,3CEh
- MOV AX,0104h {Leseplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1g
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap1g:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+2-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane1_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane1_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane1_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile2f:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile2f
- POP CX
- POP BP
- POP DI
- POP SI
-
-
- MOV DX,3CEh
- MOV AX,0204h {Leseplane 2 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2g
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap2g:
- OUT DX,AX
- PUSH AX
-
-
- DEC BP {BP:=16+1-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane2_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane2_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane2_Zeile}
-
- PUSH SI {Quell- und Zieladresse fuer weitere Planes retten}
- PUSH DI
- PUSH BP {BP retten}
- PUSH CX {CX = Zeilenzaehler retten}
- MOV BP,CX {BP:=Zeilenzaehler}
- @eineZeile3f:
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BP
- JNZ @eineZeile3f
- POP CX
- POP BP
- POP DI
- POP SI
-
-
- MOV DX,3CEh
- MOV AX,0304h {Leseplane 3 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3g
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap3g:
- OUT DX,AX
- {Wert nicht mehr pushen!}
-
-
- DEC BP {BP:=16-rightcut}
- @lastplane7:
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BX:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV BX,CX {BX:=Zeilenzaehler}
- @eineZeile4g:
- MOV CX,BP {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {eine Zeile uebertragen}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- DEC BX
- JNZ @eineZeile4g
-
- @LowerRightTileDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- {Nun noch die Kacheln links und/oder rechts entlang des Bildschirmrandes:}
- @do_raender:
- CMP leftcut,0 {oder rightcut, denn da 320 durch 16 teilbar ist,}
- JE @ende {ist leftcut=0 <=> rightcut=0 }
-
- MOV AX,offsetXTiles
- DEC AX
- MOV xt,AX
- MOV AX,ypix
- MOV y,AX
- INC tiles
- MOV AX,offsetYTiles
- MOV yt,AX
-
- @repeat5:
- MOV CL,1
- OR AX,AX
- JS @go10
- CMP AX,YTiles
- JAE @go10
- DEC CL
- @go10:
- MOV offscreenFlag,CL
- XOR SI,SI
- DEC CL
- JZ @go11
- MOV AX,xt
- OR AX,AX
- JS @go11
- CMP AX,XTiles
- JAE @go11
- MOV SI,RandIndex
- @go11:
-
-
- {PROCEDURE DrawLeftTile(y,leftcut:INTEGER; index:WORD);}
- { in: (0,y) = linke obere Ecke der zu zeichnenden Tile}
- { leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile wurde links entsprechend geschnitten}
- { leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,AX {Das ist zugleich die (Offset-)Quelladresse in Page 3}
-
- MOV DI,y {erste Zieladresse ist DI:=y*LINESIZE+(0 div 4)=y*LINESIZE}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
-
- MOV AX,leftcut
- MOV BX,AX {Kopie von leftcut in BX aufbewahren}
- SHR AX,1
- SHR AX,1
- ADD SI,AX {SI um cutoff in Bytes weitersetzen=leftcut div 4}
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16+3
- SUB BP,BX {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
- {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3CEh
- AND BL,3
- MOV AH,BL {AH:=leftcut mod 4}
- MOV AL,4
-
- JNE @mode0h {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
- { Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge- }
- { fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die }
- { "11b" werden also beim Rechtsschieben eh abgeschnitten!}
- MOV AX,4105h
- OUT DX,AX {WriteMode 1 waehlen}
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig bearbeiten}
- OUT DX,AX
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV CX,BP {CX:=Bytes_je_Plane2_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BP
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.Zeile}
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @LeftTileDone
-
- @mode0h:
- OUT DX,AX {aktuelle Leseplane waehlen}
- PUSH AX {und fuer spaeter merken}
-
- MOV DX,3C4h
- MOV AX,0102h {Schreibplane 0 waehlen}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane0_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane0_Zeile}
-
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BX
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.Zeile}
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3C4h
- MOV AX,0202h {Schreibplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap1h
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap1h:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {DI und SI wieder zuruecksetzen}
- SUB SI,16*4
-
-
- DEC BP {BP:=16+2-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane1_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane1_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane1_Zeile}
-
- MOV CX,BX {CX:=Bytes_je_Plane1_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BX
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.Zeile}
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3C4h
- MOV AX,0402h {Schreibplane 2 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap2h
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap2h:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {DI und SI wieder zuruecksetzen}
- SUB SI,16*4
-
-
- DEC BP {BP:=16+1-leftcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane2_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane2_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane2_Zeile}
-
- MOV CX,BX {CX:=Bytes_je_Plane2_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BX
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.Zeile}
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3C4h
- MOV AX,0802h {Schreibplane 3 waehlen}
- OUT DX,AX
-
- MOV DX,3CEh {naechste Leseplane:}
- POP AX
- INC AH
- AND AH,3 {um 1 erhoehen MOD 4}
- JNE @nowrap3h
- INC SI {nach Plane 3 kommt wieder Plane 0, aber}
- {die Quelladresse hat sich um 1 Byte erhoeht}
- @nowrap3h:
- OUT DX,AX
- {Wert nicht mehr pushen!}
- SUB DI,16*LINESIZE {DI und SI wieder zuruecksetzen}
- SUB SI,16*4
-
-
-
- DEC BP {BP:=16-leftcut}
- @lastplane8:
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV CX,BP {CX:=Bytes_je_Plane2_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BP
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.Zeile}
-
- @LeftTileDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- MOV CL,offscreenFlag
- XOR SI,SI
- DEC CL
- JZ @go12
- MOV AX,xt
- MOV DX,tiles
- ADD AX,DX
- JS @go12
- CMP AX,XTiles
- JAE @go12
- MOV SI,RandIndex
- ADD SI,DX
- @go12:
-
-
- {PROCEDURE DrawRightTile(x,y,rightcut:INTEGER; index:WORD);}
- { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
- { rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
- { SI = index = Tilenummer}
- {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
- {rem: Tile wurde rechts entsprechend geschnitten}
- { rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
- { rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
- { rightcut := x+15-xmax }
- MOV AH,[OFFSET BackTile +SI] {AH:=BackTile[index]}
- XOR AL,AL
-
- SHR AH,1 {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
- RCR AL,1 {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
- SHR AH,1 {rechtsschieben!}
- RCR AL,1
- MOV SI,AX {Das ist zugleich die (Offset-)Quelladresse in Page 3}
-
- MOV DI,y {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
- SHL DI,1
- MOV DI,CS:[OFFSET GADR + DI]
- MOV AX,x
- MOV BX,AX {Kopie von x nach BX}
- SHR AX,1
- SHR AX,1
- ADD DI,AX
-
- MOV CX,rightcut
-
- {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
- {verwendet werden!}
- PUSH BP {wird beim Verlassen der Prozedur gebraucht!}
- MOV BP,16+3
- SUB BP,CX {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
- {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
-
-
- MOV ES,PAGEADR {(Segment-)Zieladresse ist aktive Grafikseite}
- MOV DS,SCROLLADR {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
-
- MOV DX,3C4h
- MOV AL,2
- AND BX,3
-
- JNE @mode0i {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
- AND CX,3 {wir WriteMode1 verwenden!}
- JNE @mode0i
-
- {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
- MOV AH,0Fh
- OUT DX,AX {alle 4 Planes gleichzeitig bearbeiten}
- MOV DX,3CEh
- MOV AX,4105h {WriteMode 1 waehlen}
- OUT DX,AX
- SUB BP,3 {BP auf die richtige Groesse bringen}
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV CX,BP {CX:=Bytes_je_Plane2_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BP
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.Zeile}
-
- {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
- MOV AX,4005h
- MOV DX,3CEh
- OUT DX,AX
- {---}
- JMP @RightTileDone
-
- @mode0i:
- MOV AH,CS:[OFFSET CS_TranslateTab +BX]
- OUT DX,AX {aktuelle Schreibplane waehlen}
- PUSH AX {und fuer spaeter merken}
-
- MOV DX,3CEh
- MOV AX,0004h {Leseplane 0 waehlen}
- OUT DX,AX
-
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane0_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane0_Zeile}
-
- MOV CX,BX {CX:=Bytes_je_Plane0_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BX
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.Zeile}
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3CEh
- MOV AX,0104h {Leseplane 1 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap1i
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap1i:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {DI und SI wieder zuruecksetzen}
- SUB SI,16*4
-
-
- DEC BP {BP:=16+2-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane1_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane1_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane1_Zeile}
-
- MOV CX,BX {CX:=Bytes_je_Plane1_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BX
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.Zeile}
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3CEh
- MOV AX,0204h {Leseplane 2 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap2i
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap2i:
- OUT DX,AX
- PUSH AX
- SUB DI,16*LINESIZE {DI und SI wieder zuruecksetzen}
- SUB SI,16*4
-
-
- DEC BP {BP:=16+1-rightcut}
- MOV BX,BP
- SHR BX,1
- SHR BX,1 {BX:=Bytes_je_Plane2_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BX { := LINESIZE-Bytes_je_Plane2_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BX { := 4-Bytes_je_Plane2_Zeile}
-
- MOV CX,BX {CX:=Bytes_je_Plane2_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BX
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BX
- REP MOVSB {16.Zeile}
- ADD DI,AX
- ADD SI,DX
-
-
- MOV DX,3CEh
- MOV AX,0304h {Leseplane 3 waehlen}
- OUT DX,AX
-
- MOV DX,3C4h {naechste Schreibplane:}
- POP AX
- SHL AH,1
- CMP AH,16
- JNE @nowrap3i
- MOV AH,1 {nach Plane 3 kommt wieder Plane 0, aber}
- INC DI {die Zieladresse hat sich um 1 Byte erhoeht}
- @nowrap3i:
- OUT DX,AX
- {Wert nicht mehr pushen!}
- SUB DI,16*LINESIZE {DI und SI wieder zuruecksetzen}
- SUB SI,16*4
-
-
-
- DEC BP {BP:=16-rightcut}
- @lastplane9:
-
- SHR BP,1 {BP direkt verwenden}
- SHR BP,1 {BP:=Bytes_je_Plane3_Zeile}
-
- MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
- SUB AX,BP { := LINESIZE-Bytes_je_Plane3_Zeile}
- MOV DX,4 {Korrekturfaktor fuer Tilezeilenquelladressen}
- SUB DX,BP { := 4-Bytes_je_Plane3_Zeile}
-
- MOV CX,BP {CX:=Bytes_je_Plane2_Zeile}
- REP MOVSB {1.Zeile}
- ADD DI,AX {DI auf naechste Zielzeile setzen}
- ADD SI,DX {SI auf naechste Tilequellzeile setzen}
- MOV CX,BP
- REP MOVSB {2.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {3.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {4.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {5.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {6.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {7.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {8.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {9.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {10.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {11.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {12.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {13.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {14.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {15.Zeile}
- ADD DI,AX
- ADD SI,DX
- MOV CX,BP
- REP MOVSB {16.Zeile}
-
- @RightTileDone:
- POP BP
- MOV AX,SEG @Data {DS wiederherstellen}
- MOV DS,AX
-
- MOV AX,RandIndex
- ADD AX,XTiles
- MOV RandIndex,AX
- MOV AX,yt
- INC AX
- MOV yt,AX
- MOV DX,y
- ADD DX,16
- MOV y,DX
- CMP DX,YMAX+1-16
- JBE @repeat5
- @ende:
-
-
- {------- ab hier: Sprites auf aktuelle Grafikseite bringen}
- @Sprites_zeichnen:
- MOV SI,NMAX*2
- PUSH BP {BP nachher wieder poppen!}
-
- @zeichne:
-
- {DS = normales Datensegment, ES = Grafikseitensegment, }
- {SI = Spritepositionsnummer*2 }
- @SZeich:
- MOV BX,[SI + OFFSET SpriteN] {BX=SpriteN[?]=Spriteladenummer}
- SHL BX,1 {BX = Spriteladenummer*2}
-
- {Jetzt: "SpriteN[?]:=SpriteN[NextSprite[?]]" berechnen:}
- MOV BX,[BX + OFFSET NextSprite] {AX=NextSprite[SpriteN[?]]}
- MOV [SI + OFFSET SpriteN],BX {als neue SpriteN[?] uebernehmen}
- SHL BX,1
-
-
- JNZ @aktiv
- JMP @noSprite
-
-
- @aktiv:
- PUSH SI {Spritepositionsnummer*2 retten}
-
- MOV DX,[SI + OFFSET SpriteX] {if SpriteX>xmax then skip_sprite }
- SUB DX,StartVirtualX {virtuelle -> absolute Koordinaten}
- CMP DX,XMAX
- JLE @L0
- @ToSprite_fertig: {Sprungleiste zu @Sprite_fertig}
- JMP @Sprite_fertig
- @L0:
- MOV CS:WORD PTR @akt_SpriteX+1,DX
- MOV DI,[SI + OFFSET SpriteY] {DI = SpriteY_virtuell}
- SUB DI,StartVirtualY {DI = SpriteY (absolut!)}
- MOV DS,[BX + OFFSET SPRITEAD] {!!!DS = ^Spritedaten !!!}
- MOV AX,[Breite] {AX = Breite in 4er-Gruppen}
- MOV CS:WORD PTR @max_Breite+1,AX
- MOV SI,AX {SI = dto.}
- SHL AX,1
- SHL AX,1 {AX = max_Breite_in_Punkten}
- ADD AX,DX {AX = max_Breite_in_Punkten+SpriteX}
- JS @ToSprite_fertig
- MOV BX,DI {if SpriteY>=0 then starty:=+SpriteY}
- NEG DI { else starty:=-SpriteY}
- MOV BP,DI
- JG @Top_cut
- XOR DI,DI
- @Top_cut: {DI = starty, BP = -SpriteY}
- MOV AX,[Hoehe] {AX = Hoehe (in Zeilen) }
- CMP DI,AX {if starty>=Hoehe then skip_sprite}
- JGE @ToSprite_fertig
- ADD BP,YMAX {BP = -SpriteY+ymax}
- JL @ToSprite_fertig {(etwas frei:) }
- CMP AX,BP {if Hoehe+SpriteY>ymax }
- JG @To_then { then [ endy:=199-SpriteY }
- DEC AX { if endy<0 then skip_sprite ] }
- MOV BP,AX { else endy:=Hoehe-1 }
-
- {BP = endy, SI=[@max_Breite+1] = max_Breite_in_4er_Gruppen, }
- {DI = starty, BX = SpriteY, DX=[@akt_SpriteX+1] = SpriteX, }
- {DS = ^Spritedaten, ES = ^Grafikseite}
- @To_then:
- MOV AX,BP
- SUB BP,DI
-
- SHL BP,1
- MOV [End_min_Start],BP {= (endy-starty)*2 =Yaktuell*2}
- ADD BX,AX
- SHL BX,1
- MOV BX,CS:[OFFSET gadr + BX] {BX=zeilenadr:=(endy+SpriteY)*LINESIZE}
- MOV [zeilenadr],BX {auch nach [zeilenadr] }
- MOV BP,DX
- MUL SI {AX = endy*max_breite_in_4er =yoffset}
- MOV [yoffset_],AX {auch nach [yoffset_]}
- SHL DI,1 {DI = starty*2}
- MOV CS:WORD PTR @Starty_2+1,DI {auch nach [@Starty_2+1] }
-
- {kleiner Einschub: anhand des Modusbytes des Sprites entscheiden, ob}
- {eine andere Routine zur Darstellung des Sprites als die gerade ak- }
- {tive benoetigt wird und wenn ja, diese in Position bringen! }
- {Verwendete Register: AX und SI }
- MOV AL,[Modus] {Modusbyte des Sprites holen}
- XOR AH,AH
- SHL AX,1
- MOV SI,AX
- MOV SI,CS:[OFFSET Adressen +SI] {Pointer auf zugehoerige Routine holen}
- MOV AX,CS:[SI]
- CMP AX,CS:[WORD PTR @Patch1] {ist diese Routine bereits aktiv?}
- JE @no_newcode {ja, nix zu tun}
- PUSH DS {nein, kopiere die Routine an die}
- PUSH CS {entsprechenden Stellen}
- POP DS
- MOV [WORD PTR @Patch1],AX
- MOV [WORD PTR @Patch2],AX
- MOV [WORD PTR @Patch3],AX
- MOV [WORD PTR @Patch4],AX
- INC SI
- INC SI
- LODSW
- MOV [WORD PTR @Patch1+2],AX
- MOV [WORD PTR @Patch2+2],AX
- MOV [WORD PTR @Patch3+2],AX
- MOV [WORD PTR @Patch4+2],AX
- LODSW
- MOV [WORD PTR @Patch1+4],AX
- MOV [WORD PTR @Patch2+4],AX
- MOV [WORD PTR @Patch3+4],AX
- MOV [WORD PTR @Patch4+4],AX
- LODSW
- MOV [WORD PTR @Patch1+6],AX
- MOV [WORD PTR @Patch2+6],AX
- MOV [WORD PTR @Patch3+6],AX
- MOV [WORD PTR @Patch4+6],AX
- LODSW
- MOV [WORD PTR @Patch1+8],AX
- MOV [WORD PTR @Patch2+8],AX
- MOV [WORD PTR @Patch3+8],AX
- MOV [WORD PTR @Patch4+8],AX
- LODSW
- MOV [WORD PTR @Patch1+10],AX
- MOV [WORD PTR @Patch2+10],AX
- MOV [WORD PTR @Patch3+10],AX
- MOV [WORD PTR @Patch4+10],AX
- LODSW
- MOV [WORD PTR @Patch1+12],AX
- MOV [WORD PTR @Patch2+12],AX
- MOV [WORD PTR @Patch3+12],AX
- MOV [WORD PTR @Patch4+12],AX
- LODSW
- MOV [WORD PTR @Patch1+14],AX
- MOV [WORD PTR @Patch2+14],AX
- MOV [WORD PTR @Patch3+14],AX
- MOV [WORD PTR @Patch4+14],AX
-
- POP DS {DS wiederherstellen}
- @no_newcode:
-
-
- {(AX=)[yoffset_] = yoffset }
- { BX=[zeilenadr] = (endy+SpriteY)*LINESIZE}
- { DI=[@Starty_2+1] = starty*2}
- {(SI=[@max_Breite+1] = max_Breite_in_4er_) }
- { BP = SpriteX}
- { DS = ^Spritedaten}
- { ES = ^Grafikseite}
- { [end_min_start] = (endy-starty)*2 =Yaktuell*2}
- { [@max_Breite+1] = max_Breite_in_4er_Gruppen }
- { [@akt_SpriteX+1] = SpriteX}
- @eine_Zeile:
- MOV SI,[end_min_start] {SI = Yaktuell*2 }
- ADD SI,DI {startx:=sprite[WORD PTR sprite[L]+ }
- MOV DI,SI { (Yaktuell+starty)*2] }
- ADD SI,[Left]
- MOV SI,[SI] {SI = startx, DI = (Yaktuell+starty)*2}
- MOV AX,BP
- ADD AX,SI {AX=bildschirmstartx:=SpriteX+startx }
- CMP AX,XMAX {if bildschirmstartx>xmax then skip_zeile}
- JG @ToZeile_fertig
- MOV CX,SI {CX=startx}
- OR AX,AX {licutoff_in_Punkten:=startx}
- JGE @L1 {if bildschirmstartx<0 then }
- SUB SI,AX { [dec(startx,bildschirmstartx) }
- XOR AX,AX { bildschirmstartx:=0 }
- MOV CX,BP { licutoff_in_Punkten:=-SpriteX] }
- NEG CX
- @L1: {CX=[licutoff_]= licutoff_in_Punkten, }
- MOV [licutoff_],CX {SI = startx, AX = bildschirmstartx }
- ADD DI,[Right]
- MOV DI,[DI] {DI=endx:=sprite[WORD PTR sprite[R]+ }
- { (Yaktuell+starty)*2] }
- MOV DX,BP
- NEG DX {DX = -SpriteX }
- MOV BP,DI
- SUB BP,SI {BP = endx-startx }
- SUB DX,DI
- ADD DX,XMAX {DX=ueberhang:=xmax-(SpriteX+endx) }
- JNS @kein_Ueberhang_rechts
- ADD BP,DX
- @kein_Ueberhang_rechts: {BP = sichtbare Breite dieser Zeile -1}
- OR BP,BP
- JNS @L6
- @ToZeile_fertig:
- JMP @Zeile_fertig {if Breite<=0 then skip_zeile }
- @L6:
- ADD BP,4
-
- { AX = bildschirmstartx}
- { BX=[zeilenadr] = (endy+SpriteY)*LINESIZE }
- { CX=[licutoff_] = licutoff_in_Punkten}
- {(DX = (negativer) ueberhang (falls Wert<0) ) }
- {(SI = startx) }
- {(DI = endx) }
- { BP = Breite fuer diese Zeile in Punkten +3 }
- { DS = ^Spritedaten}
- { ES = ^Grafikseite}
- { [@max_Breite+1] = max_Breite_in_4er_) }
- { [end_min_start] = (endy-starty)*2 =Yaktuell*2}
- { [@Starty_2+1] = starty*2}
- { [@max_Breite+1] = max_Breite_in_4er_Gruppen, }
- { [@akt_SpriteX+1] = SpriteX}
- MOV [bildx],AX {bildschirmstartx retten}
- MOV DX,CX {DX = licutoff_in_Punkten}
- MOV CX,BP
- SHR CX,1
- SHR CX,1 {CX = Breite DIV 4}
- JCXZ @Plane1
-
- {SI=Quellzeiger:=sprite[WORD PTR (licutoff_in_Punkten+0 AND 3)*2 }
- { +(licutoff_in_Punkten+0) DIV 4 +yoffset }
- MOV SI,DX
- AND SI,3
- SHL SI,1 {SI = ((licutoff_in_Punkten+0) AND 3)*2}
- MOV SI,[SI]
- MOV DI,DX
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_] {SI = sprite[WORD PTR (licutoff_...)] }
- { +(licutoff_in_Punkten+i) DIV 4 }
- { +yoffset }
-
- {DI=Zielzeiger:=(bildschirmstartx+0) DIV 4 +zeilenadr}
- MOV DI,AX {DI = bildschirmstartx }
- SHR DI,1
- SHR DI,1
- ADD DI,BX
- MOV BL,AL
- AND BX,3 {BX = (bildschirmstartx+i) AND 3 }
- MOV AH,Translate[BX] {AH = 1,2,4,8 fuer BX=0,1,2,3 }
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX {Plane auswaehlen}
-
- XCHG BX,DI
- {CX Bytes von DS:SI nach ES:BX uebertragen }
- {Hierher kommt die Routine zur Datenuebertragung!}
- @Patch1:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane1:
- MOV DX,[bildx]
- INC DX {DX = bildschirmstartx+1}
- MOV BX,DX
- SHR BX,1
- SHR BX,1 {BX=zielzeiger:=(bildschirmstartx+1) }
- ADD BX,[zeilenadr] { DIV 4 +zeilenadr }
- MOV CX,BP
- DEC CX {CX = Breite dieser Zeile +3 -1 }
- SHR CX,1
- SHR CX,1 {CX = Bytes_zu_moven fuer i=1 }
- JCXZ @Plane2
- MOV DI,[licutoff_]
- INC DI {DI = (licutoff_in_Punkten+1) }
- MOV SI,DI
- AND SI,3
- SHL SI,1 {SI = ((licutoff_in_Punkten+1) AND 3)*2}
- MOV SI,[SI] {SI = sprite[WORD PTR licutoff_...] }
- SHR DI,1 { +(licutoff_in_Punkten+1) DIV 4 }
- SHR DI,1 { +yoffset }
- ADD SI,DI
- ADD SI,[yoffset_] {SI = Quellzeiger, }
- {DI = (licutoff_in_Punkten+1) DIV 4 }
-
- MOV DI,DX {DI = bildschirmstartx+1}
- AND DI,3 {DI = (bildschirmstartx+1) AND 3 }
- MOV AH,Translate[DI] {Maske fuer Portzugriff laden}
- MOV AL,2
- MOV DX,3C4h {Plane anwaehlen}
- OUT DX,AX
-
- {Hierher kommt die Routine zur Datenuebertragung!}
- @Patch2:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane2:
- MOV DX,[bildx]
- ADD DX,2
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,2
- SHR CX,1
- SHR CX,1
- JCXZ @Plane3
- MOV DI,[licutoff_]
- ADD DI,2
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = bildschirmstartx+2}
- AND DI,3 {DI = (bildschirmstartx+1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {Hierher kommt die Routine zur Datenuebertragung!}
- @Patch3:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Plane3:
- MOV DX,[bildx]
- ADD DX,3
- MOV BX,DX
- SHR BX,1
- SHR BX,1
- ADD BX,[zeilenadr]
- MOV CX,BP
- SUB CX,3
- SHR CX,1
- SHR CX,1
- JCXZ @Zeile_fertig
- MOV DI,[licutoff_]
- ADD DI,3
- MOV SI,DI
- AND SI,3
- SHL SI,1
- MOV SI,[SI]
- SHR DI,1
- SHR DI,1
- ADD SI,DI
- ADD SI,[yoffset_]
-
- MOV DI,DX {DI = bildschirmstartx+3}
- AND DI,3 {DI = (bildschirmstartx+1) AND 3 }
- MOV AH,Translate[DI]
- MOV AL,2
- MOV DX,3C4h
- OUT DX,AX
-
- {Hierher kommt die Routine zur Datenuebertragung!}
- @Patch4:
- db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-
- @Zeile_fertig:
- MOV AX,[yoffset_]
- @max_Breite:
- SUB AX,1234
- MOV [yoffset_],AX
- MOV BX,[zeilenadr]
- SUB BX,LINESIZE
- MOV [zeilenadr],BX
- SUB WORD PTR [end_min_start],2
- JS @Sprite_fertig
-
- @Starty_2:
- MOV DI,1234
- @akt_SpriteX:
- MOV BP,1234
- JMP @eine_Zeile
-
- @Sprite_fertig:
- POP SI
- MOV AX,SEG @Data
- MOV DS,AX
-
- @noSprite:
- DEC SI
- DEC SI
- JS @fertig
- JMP @zeichne
- @fertig:
-
- POP BP
-
- {Die Grafikseite ist nun fertiggestellt und muss noch angezeigt werden:}
- cli
- mov dx,StatusReg
-
- {Auf "display enable"=0 (d.h.: aktiv) warten, so dass Seitenumschaltung}
- {fuer HB/LB auf selber Seite geschieht:}
-
- @WaitNotHSyncLoop:
- in al,dx
- and al,1
- jnz @WaitNotHSyncLoop
- @WaitHSyncLoop:
- in al,dx
- and al,1
- jz @WaitHSyncLoop
-
- MOV DX,CRTAddress {CRT-Controller}
- MOV AL,$0D {LB-Startadress-Register}
- OUT DX,AL
- INC DX
- { Realisiere "AX:=Offset_Adr[Page]": }
- MOV SI,PAGE {Page-Wert *2 (da Worteintraege!)}
- MOV BX,SI {Page-Wert in BX merken!}
- SHL SI,1 {dazu Startadresse des Feldes addieren}
- ADD SI,OFFSET Offset_Adr-StartIndex*2 {evtl. Verschiebung korrigieren}
- LODSW {und Wert holen}
- OUT DX,AL {LB der neuen Startadresse setzen}
- DEC DX
- MOV AL,$0C
- OUT DX,AL
- INC DX
- MOV AL,AH {HB der neuen Startadresse setzen}
- OUT DX,AL
- STI
-
- NEG BX {neuer PAGE-Wert := 1-alter PAGE-Wert, d.h.: }
- ADD BX,1 {IF PAGE=0 THEN PAGE:=1 ELSE (PAGE=1) PAGE:=0 }
- MOV PAGE,BX
-
- SHL BX,1 {neuer PAGEADR-Wert := Segment_Adr[PAGE] }
- ADD BX,OFFSET Segment_Adr-StartIndex*2
- MOV AX,[BX]
- MOV PAGEADR,AX
-
- {Jetzt ueberpruefen, ob gesetzte Zyklus(mindest)zeit abgelaufen ist:}
- @L10:
- MOV AL,TimeFlag {Bit 7 = 0/1 fuer Zeit ist abgelaufen/laeuft noch }
- AND AL,$80
- JE @L10
-
- {Zeitueberwachung fuer naechsten Zyklus starten:}
- MOV AL,IsAT {ist das ein AT/386? ($0/$80=ja/nein)}
- OR AL,AL {Zeitmechanismus geht nur auf AT/386 }
- JNE @L11 {anderenfalls keine Zeitueberwachung!}
- MOV TimeFlag,AL {AL=0 zugleich als Init-Wert benutzen}
- MOV DX,WORD PTR CycleTime {Mindestzykluszeit (in Mikrosekunden)}
- MOV CX,WORD PTR CycleTime+2 {eintragen: CX=HIGH-Word, DX=LOW-Word}
- MOV BX,OFFSET TimeFlag {ES:BX=Zeiger auf TimeFlag, Bit 7=0/1}
- MOV AX,DS {fuer: Zeit laeuft noch/ist um }
- MOV ES,AX
- MOV AX,8300h {Zeitueberwachung starten}
- INT 15h
- @L11:
- END
- END;
-
-
- FUNCTION LoadSprite(name:String; number:WORD):WORD;
- { in: name = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
- { number = Nummer, die das erste Sprite aus diesem File bekommen soll }
- {out: Anzahl der aus dem File gelesenen Sprites (0 = Fehler trat auf) }
- {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein ein-}
- { zelnes Sprite oder eine ganze Spritebibliothek handelt und laedt }
- { alle Spritedaten auf den Heap, und zwar derart, dass die Adresse }
- { immer auf eine Segmentgrenze faellt. Diese Anfangsadressen werden }
- { dann in der Tabelle SPRITEAD[number] abgelegt; sind mehrere Sprites }
- { in der Datei so werden sie mit fortlaufender Nummer eingetragen, }
- { also number+i }
- LABEL quit_loop;
- VAR p1,p2:Pointer;
- len:LONGINT;
- f:File;
- count,Kopf:WORD;
- Header:SpriteHeader;
- BEGIN
- count:=0; {Zahl der bisher eingelesenen Sprites}
- Kopf:=SizeOf(SpriteHeader);
- assign(f,name);
- {$I-} reset(f,1); {$I+}
- if (ioresult<>0)
- THEN BEGIN {Datei existiert nicht oder nicht unter diesem Pfad}
- Error:=Err_FileIO;
- loadSprite:=0; exit
- END;
- len:=filesize(f); {Dateilaenge ermitteln}
- if (maxavail<len+16)
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
- if (number=0) or (number>LoadMAX)
- THEN BEGIN
- Error:=Err_InvalidSpritenumber;
- goto quit_loop;
- END;
- WHILE NOT EOF(f) DO
- BEGIN
- {Zunaechst den Spriteheader einlesen: }
- {$I-} {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
- blockread(f,Header,Kopf);
- {$I+}
-
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoSprite;
- goto quit_loop;
- END;
- IF (Header.SpriteLength>MaxAvail+15) {noch genug Platz da?}
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- {Jetzt eigentliche Spritedaten einlesen: }
- getmem(p1,Header.SpriteLength+15); {genug Platz reservieren}
- IF (LONGINT(p1) mod 16)=0
- THEN p2:=p1 {p2 auf Segmentgrenze bringen}
- ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
-
- MOVE(Header,p2^,Kopf); {Spriteheader auf Heap bringen}
- LONGINT(p1):=LONGINT(p2)+Kopf; {zeigt genau hinter den Header}
-
- {$I-} {jetzt den "Rest" des Sprites laden}
- blockread(f,p1^,Header.SpriteLength-Kopf);
- {$I+}
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
-
- {der Spritenummer zuordnen:}
- spritead[number+count]:=(longint(p2) shr 16)
- +(longint(p2) and 65535) shr 4;
- INC(count);
- END;
-
- quit_loop: ;
- close(f);
- loadSprite:=count
- END;
-
- FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
- { in: name = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
- { number = 0..255 = Tilenummer fuer das erste Sprite der Datei }
- {out: Anzahl der aus dem File gelesenen Tiles (0 = Fehler trat auf) }
- {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein ein-}
- { zelnes Sprite oder eine ganze Spritebibliothek handelt und laedt }
- { alle Sprites, zerlegt diese in Tiles und legt sie in der 4.Grafik- }
- { seite ab, beginnend mit der uebergebenen Nummer number }
- { Da eine Kachel 16x16 Punkte gross ist, muessen die Sprites ein Viel-}
- { faches von 16 Punkten in x- und y-Richtung sein }
- { Enthaelt die Datei mehrere Tiles, so werden sie zeilenweise geladen,}
- { jede Zeile dabei in der Reihenfolge von links nach rechts }
- LABEL quit_loop;
- TYPE split=RECORD loword,hiword:WORD END;
- VAR p1:Pointer;
- len,ad,p:LONGINT;
- f:File;
- count,Kopf,ZielOfs,step,yoffset:WORD;
- pSeg,pOfs:ARRAY[0..3] OF WORD;
- Breite_in_Tiles,Hoehe_in_Tiles,x,y,i,zeilen:BYTE;
- Header:SpriteHeader;
- BEGIN
- count:=0; {Zahl der bisher eingelesenen Sprites}
- Kopf:=SizeOf(SpriteHeader);
- assign(f,name);
- {$I-} reset(f,1); {$I+}
- if (ioresult<>0)
- THEN BEGIN {Datei existiert nicht oder nicht unter diesem Pfad}
- Error:=Err_FileIO;
- LoadTile:=0; exit
- END;
- len:=filesize(f); {Dateilaenge ermitteln}
- if (maxavail<len+16)
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
- WHILE NOT EOF(f) DO
- BEGIN
- {Zunaechst den Spriteheader einlesen: }
- {$I-} {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
- blockread(f,Header,Kopf);
- {$I+}
-
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
- IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
- THEN BEGIN
- Error:=Err_NoTile; {oder Err_NoSprite!}
- goto quit_loop
- END;
- IF (Header.Breite_in_4er_Gruppen MOD 4<>0) OR
- (Header.Hoehe_in_Zeilen MOD 16<>0) {Groesse Vielfaches von 16?}
- THEN BEGIN
- Error:=Err_NoTile;
- goto quit_loop
- END
- ELSE BEGIN {ja, Anzahl Tiles in diesem Spritefile ermitteln}
- Breite_in_Tiles:=Header.Breite_in_4er_Gruppen SHR 2;
- Hoehe_in_Tiles :=Header.Hoehe_in_Zeilen SHR 4;
- step:=Breite_in_Tiles*4; {Schrittweite beim laden}
- END;
- IF (Header.SpriteLength>MaxAvail) {noch genug Platz da?}
- THEN BEGIN
- Error:=Err_NotEnoughMemory;
- goto quit_loop;
- END;
-
- {Jetzt eigentliche Spritedaten einlesen: }
- getmem(p1,Header.SpriteLength); {genug Platz reservieren}
-
- {$I-} {jetzt den "Rest" des Sprites laden}
- blockread(f,p1^,Header.SpriteLength-Kopf);
- {$I+}
- IF (ioresult<>0)
- THEN BEGIN
- Error:=Err_FileIO;
- goto quit_loop;
- END;
-
- ad:=(LONGINT(split(p1).HiWord) SHL 4) + split(p1).LoWord - Kopf;
- FOR i:=0 TO 3 DO
- BEGIN
- p:=ad+Header.Zeiger_auf_Plane[i]; pSeg[i]:=p SHR 4; pOfs[i]:=p AND $F;
- END;
-
- FOR y:=0 TO Pred(Hoehe_in_Tiles) DO
- BEGIN
- yoffset:=y*Breite_in_Tiles*16*(16 DIV 4);
- FOR x:=0 TO Pred(Breite_in_Tiles) DO
- BEGIN
- IF count+number>255
- THEN BEGIN
- Error:=Err_InvalidTileNumber;
- goto quit_loop
- END;
- ZielOfs:=(number+count) SHL 6;
- FOR i:=0 TO 3 DO
- BEGIN
- PORTW[$3C4]:=(TranslateTab[i] SHL 8) + 2;
- FOR zeilen:=0 TO 15 DO
- BEGIN
- move(mem[pSeg[i]:pOfs[i] + yoffset + zeilen*step + x*(16 DIV 4)],
- mem[SCROLLADR:ZielOfs + zeilen*(16 DIV 4)],
- 16 DIV 4);
- END;
- END;
-
- INC(count);
- END;
- END;
- Dispose(p1);
- END;
-
- quit_loop: ;
- close(f);
- LoadTile:=count
- END;
-
- PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
- { in: (x1,y1) = linke obere Ecke des Bereiches (virtuelle Koord.)}
- { (x2,y2) = dto., rechte untere Ecke}
- {out: (BackX1,BackY1), (BackX2,BackY2) = auf 16er Raster gerundete Koord. }
- { XTiles, YTiles = Breite und Hoehe des gewaehlten Bereiches in Kacheln}
- {rem: Die li. obere Ecke wird nach links oben gezogen, die re. untere nach }
- { rechts unten!}
- { Die Anwendung dieser Routine ist natuerlich nur fuer den Hintergrund-}
- { modus SCROLLING sinnvoll}
- BEGIN
- BackX1:=x1 AND $FFF0; BackX2:=x2 OR $F;
- BackY1:=y1 AND $FFF0; BackY2:=y2 OR $F;
- xtiles:=succ(BackX2-BackX1) shr 4;
- ytiles:=succ(BackY2-BackY1) shr 4;
- IF (xtiles OR ytiles)<=0
- THEN Error:=Err_InvalidCoordinates
- ELSE IF xtiles*ytiles>MaxTiles
- THEN Error:=Err_BackgroundToBig;
- END;
-
- PROCEDURE SetBackgroundMode(mode:BYTE);
- { in: mode = gewuenschter Hintergrundmodus STATIC oder SCROLLING}
- {out: Backgroundmode = gesetzter Modus STATIC/SCROLLING}
- BEGIN
- IF (mode<>STATIC) AND (mode<>SCROLLING)
- THEN Error:=Err_InvalidMode
- ELSE Backgroundmode:=mode
- END;
-
- PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
- { in: x,y = virtuelle Koordinate, an die die Kachel plaziert werden soll}
- { TileNr= Nummer der zu plazierenden Kachel}
- {out: - }
- {rem: Der Punkt (x,y) wird zunaechst auf 16er Raster gebracht! }
- { Die Anwendung dieser Routine ist nur fuer den Hintergrund-}
- { modus SCROLLING sinnvoll}
- VAR index:WORD;
- BEGIN
- ASM
- MOV AX,x {berechne relativen X-Abstand vom linken Rand des}
- SUB AX,BackX1 {definierten Bereiches in "x" mittels der Formel:}
- SAR AX,1 { x:=((x AND $FFF0)-BackX1) DIV 16 (nicht SHR 4)!}
- SAR AX,1 {"AND $FFF0" kann dabei entfallen, da in BackX1 }
- SAR AX,1 {die letzte Hex-Ziffer $0 ist! }
- SAR AX,1
- MOV x,AX
-
- MOV AX,y {dto. fuer Abstand der y-Koordinate vom oberen }
- SUB AX,BackY1 {Rand: y:=((y AND $FFF0)-BackY1) DIV 16 }
- SAR AX,1
- SAR AX,1
- SAR AX,1
- SAR AX,1
- MOV y,AX
- END;
-
- IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
- THEN Error:=Err_InvalidCoordinates
- ELSE BEGIN {jede Kachelzeile ist XTiles breit, jede Kachel 16x16 Punkte}
- index:=y*XTiles+x; {eigentlich: (x MOD XTiles)}
- BackTile[Succ(index)]:=TileNr; {"Succ", um BackTile[0] freizuhalten}
- END;
- END;
-
- PROCEDURE SetOffscreenTile(TileNr:BYTE);
- { in: TileNr= Nummer der zu plazierenden Kachel}
- {out: - }
- {rem: Alle Bildschirmteile, die ausserhalb des durch SetBackground-}
- { ScrollRange definierten Bereiches liegen, erhalten TileNr als}
- { Muster zugewiesen }
- { Die Anwendung dieser Routine ist nur fuer den Hintergrund- }
- { modus SCROLLING sinnvoll}
- BEGIN
- BackTile[0]:=TileNr
- END;
-
- PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
- { in: Sp = SpriteLADEnummer, dessen Modusbyte veraendert werden soll}
- {out: M = Methode, mit der Sp ab sofort dargestellt werden soll: }
- { Display_NORMAL, Display_FAST, Display_SHADOW oder }
- { Display_SHADOWEXACT }
- {rem: Existiert das Sprite noch nicht oder ist der Modus nicht er- }
- { laubt, so geschieht nicht! }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF ad=0 THEN Error:=Err_InvalidSpriteNumber {Sprite muss schon geladen sein}
- ELSE IF (M<Display_NORMAL) OR (M>Display_SHADOWEXACT)
- THEN Error:=Err_InvalidMode {nur diese 4 Modi sind zulaessig}
- ELSE MEM[ad:Modus]:=M
- END;
-
- FUNCTION GetModeByte(Sp:WORD):BYTE;
- { in: Sp = SpriteLADEnummer, dessen Modusbyte abgefragt werden soll}
- {out: Methode, die fuer Sp momentan gesetzt ist: Display_NORMAL, }
- { Display_FAST, Display_SHADOW, Display_SHADOWEXACT bzw. }
- { Display_UNKNOWN, wenn das Sprite noch nicht geladen wurde! }
- VAR ad:WORD;
- BEGIN
- ad:=SPRITEAD[Sp];
- IF (ad=0)
- THEN GetModeByte:=Display_UNKNOWN {Sprite noch nicht geladen}
- ELSE GetModeByte:=MEM[SPRITEAD[Sp]:Modus]
- END;
-
- PROCEDURE FillPage(pa,color:Byte);
- { in: pa = die Seite, die gefuellt werden soll (0..3)}
- { color = Fuellfarbe fuer die Seite}
- {out: Grafikseite "pa" wurde mit der Farbe "Color" gefuellt }
- {rem: Sinnvoll sind nur die Seiten 0,1 und BACKGNDPAGE, jedoch }
- { ist SCROLLPAGE ebenfalls erlaubt}
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE) AND (pa<>SCROLLPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE BEGIN
- portw[$3C4]:=$0F02; {im Map-Mask Register alle 4 Ebenen selektieren}
- fillchar(MEM[Segment_Adr[pa]:0],PAGESIZE,Color)
- END;
- END;
-
- PROCEDURE FillBackground(color:BYTE);
- { in: color = Fuellfarbe fuer die Hintergrundseite BACKGNDPAGE }
- {out: Die Grafikseite BACKGNDPAGE wurde mit der Farbe "Color" gefuellt}
- {rem: Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll }
- BEGIN
- FillPage(BACKGNDPAGE,color)
- END;
-
- PROCEDURE GetBackgroundFromPage(pa:Byte);
- {in : pa = 0 oder 1 }
- {out: - }
- {rem: Der Hintergrundspeicher BACKGNDPAGE wird mit dem Inhalt der an- }
- { gegebenen Grafikseite gefuellt.}
- { Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll }
- VAR p:POINTER;
- BEGIN
- IF (pa<>0) AND (pa<>1)
- THEN Error:=Err_InvalidPageNumber
- ELSE BEGIN
- portw[$3c4]:=$0f02; {im MapMask Register alle 4 Ebenen selektieren}
- port[$3ce]:=5; {Schreibmodus 1 }
- port[$3cf]:=port[$3cf] OR 1; {oder direkt :=$41}
- p:=Ptr(Segment_Adr[pa],$0000);
- MOVE(p^,MEM[BACKGNDADR:0],PAGESIZE);
- portw[$3cf]:=port[$3cf] and $FC; {Schreibmodus 0 (oder direkt:=$40)}
- END;
- END;
-
- PROCEDURE WritePage(name:STRING; pa:BYTE);
- { in: name = Filename fuer das abzuspeichernde Bild}
- { pa = abzuspeichernde Seite (0..2) }
- { PAGESIZE = Groesse einer Bitplane }
- { PICHeader= einzutragende Kennung fuer Bilderdateien}
- {out: - }
- {rem: Die Grafik auf Seite "pa" wurde in der Datei "name" als Bitmap abgelegt}
- { Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes gross: 320x200 Punkte zu je }
- { 1 Byte plus Length(PICHeader) als Kennung}
- VAR f:FILE;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- {$I-}
- Assign(f,name); fehler:=IOResult<>0;
- Rewrite(f,1); fehler:=fehler OR (IOResult<>0);
- BlockWrite(f,PICHeader[1],Length(PICHeader));
- fehler:=fehler OR (IOResult<>0);
- {$I+}
- IF fehler
- THEN BEGIN
- {$I-} Close(f); {$I+}
- Error:=Err_FileIO; exit
- END;
- port[$3ce]:=5; {alten Lese-/Schreibmodus merken}
- oldMode:=port[$3cf];
- port[$3cf]:=$40; {Lesemodus 0 setzen}
- FOR i:=0 TO 3 DO
- BEGIN
- portw[$3CE]:=4+(i shl 8); {Lese-Plane anwaehlen}
- {$I-}
- BlockWrite(f,mem[Segment_Adr[pa]:0],PAGESIZE);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- END;
- {$I-}
- Close(f);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- port[$3ce]:=5; {alten Lese-/Schreibmodus setzen}
- port[$3cf]:=oldMode;
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE LoadPage(name:STRING; pa:BYTE);
- { in: name = Filename fuer das zu ladende Bild}
- { pa = Zielseite, in die das Bild geladen werden soll (0..2) }
- { PAGESIZE = Groesse einer Bitplane }
- { PICHeader= Kennung fuer Bilderdateien}
- {out: - }
- {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Seite "pa" geladen}
- VAR f:FILE;
- i,oldMode:BYTE;
- fehler:BOOLEAN;
- s:STRING[3];
- splane:WORD;
- p1,p2:POINTER;
- TYPE tempArray=ARRAY[1..PAGESIZE] OF BYTE;
- VAR temp:^tempArray;
- BEGIN
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN BEGIN
- Error:=Err_InvalidPageNumber; exit
- END;
- {$I-}
- Assign(f,name); fehler:=IOResult<>0;
- Reset(f,1); fehler:=fehler OR (IOResult<>0);
- s[0]:=PICHeader[0];
- BlockRead(f,s[1],Length(PICHeader)); fehler:=fehler OR (IOResult<>0);
- {$I+}
- IF fehler
- THEN BEGIN
- {$I-} Close(f); {$I+}
- Error:=Err_FileIO; exit
- END
- ELSE IF (FileSize(f)<>4*PAGESIZE+Length(PICHeader)) OR (s<>PICHeader)
- THEN BEGIN
- {$I-} Close(f); {$I+}
- Error:=Err_NoPicture; exit
- END;
- ASM cli END;
- port[$3ce]:=5; {alten Lese-/Schreibmodus merken}
- oldMode:=port[$3cf];
- New(temp);
- ASM sti END;
- FOR i:=0 TO 3 DO
- BEGIN
- {$I-}
- BlockRead(f,temp^[1],PAGESIZE);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- splane:=2+(TranslateTab[i] shl 8); {welche Schreib-Plane}
- p1:=@temp^[1];
- p2:=ptr(Segment_Adr[pa],0);
- ASM
- cli
- mov dx,$3CE {Schreibmodus 0 waehlen}
- mov ax,$4005
- out dx,ax
-
- mov ax,splane {Schreibplane anwaehlen}
- mov dx,$3C4
- out dx,ax
-
- les di,p2
- lds si,p1
- mov cx,PAGESIZE SHR 1
- rep movsw
-
- mov ax,SEG @DATA
- mov ds,ax
- sti
- END;
-
- END;
- Dispose(temp);
- {$I-}
- Close(f);
- {$I+}
- fehler:=fehler OR (IOResult<>0);
- portw[$3ce]:=oldMode SHL 8 + 5; {alten Lese-/Schreibmodus setzen}
- IF fehler THEN Error:=Err_FileIO
- END;
-
- PROCEDURE WriteBackgroundPage(name:STRING);
- { in: name = Filename fuer das abzuspeichernde Hintergrundbild}
- { BACKGNDPAGE= abzuspeichernde Seite (=2) }
- { PAGESIZE = Groesse einer Bitplane }
- { PICHeader = einzutragende Kennung fuer Bilderdateien}
- {out: - }
- {rem: Die Grafik der Hintergrundseite wurde in der Datei "name" abgelegt}
- { Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes gross: 320x200 Punkte }
- { zu je 1 Byte plus Length(PICHeader) als Kennung}
- { Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll }
- BEGIN
- WritePage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE LoadBackgroundPage(name:STRING);
- { in: name = Filename fuer das zu ladende Hintergrundbild}
- { BACKGNDPAGE= Zielseite, in die das Bild geladen werden soll (=2) }
- { PAGESIZE = Groesse einer Bitplane }
- { PICHeader= Kennung fuer Bilderdateien}
- {out: - }
- {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Hintergrundseite}
- { BACKGNDPAGE geladen}
- { Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll}
- BEGIN
- LoadPage(name,BACKGNDPAGE)
- END;
-
- PROCEDURE FadeIn(pa,ti,style:WORD);
- { in: pa = Seite, die auf die aktuelle Seite eingeblendet werden soll}
- { ti = Zeit in Millisekunden, in der dies geschehen soll}
- { style = Algorithmus der dafuer benutzt werden soll}
- { 1-PAGE = aktuell sichtbare Seite}
- {out: Error = Err_InvalidFade, falls nicht zulaessiger Alg. gewaehlt wurde}
- {rem: Grafikmodus muss natuerlich bereits initialisiert worden sein}
- { Sinnvoll ist eigentlich nur pa=BACKGNDPAGE}
-
- PROCEDURE WipeIn(pa,time:WORD);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST hoehe =40; {Teiler von Succ(YMAX)}
- breite=40; {Teiler von Succ(XMAX)}
- br_x =Succ(XMAX) DIV breite; {Bloecke in X-Richtung}
- br_y =Succ(YMAX) DIV hoehe; {Bloecke in Y-Richtung}
- n=hoehe*br_x; {Anzahl Aufrufe der Verzoegerungsschleife}
- VAR i,x,y,ploty,plotx:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- p:POINTER;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- FOR i:=0 TO pred(hoehe) DO
- FOR x:=0 TO pred(br_x) DO
- BEGIN
- FOR y:=0 TO pred(br_y) DO
- BEGIN
- IF ODD(x)
- THEN ploty:=y*hoehe+i +StartVirtualY
- ELSE ploty:=y*hoehe+(hoehe-1-i)+StartVirtualY;
- plotx:=x*breite +StartVirtualX;
- p:=GetImage(plotx,ploty,plotx+pred(breite),ploty,pa);
- PutImage(plotx,ploty,p,1-PAGE);
- FreeImageMem(p);
- END; {of FOR y}
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR x}
- END;
-
- PROCEDURE Chaos(pa,time:WORD;m:BYTE);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
- { m = Art, wie das geschehen soll (1..14)}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST n=Succ(XMAX)*Succ(YMAX); {Anzahl Bildschirmpunkte}
- {gute Parameter sind z.B. Summen von Zweierpotenzen +1}
- para:ARRAY[1..14] OF WORD=
- (13477,65,337,129,257,513,769,1025,481,4097,5121,177,16385,16897);
- VAR i,k,x,y:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- rand:WORD;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- rand:=0;
- IF (m<1) OR (m>14) THEN m:=1;
- k:=para[m];
- temp:=0.0182*time/n;
- FOR i:=0 TO 65535 DO
- BEGIN
- ASM {berechne: "x:=rand MOD 320" und "y:=rand DIV 320"}
- XOR DX,DX
- MOV AX,rand
- MOV BX,XMAX+1
- DIV BX
- MOV y,AX
- MOV x,DX
- END;
- IF y<=YMAX
- THEN PutPixel(StartVirtualX+x,StartVirtualY+y,
- PageGetPixel(StartVirtualX+x,StartVirtualY+y,pa));
- ASM {berechne: rand:=rand*k+1}
- MOV AX,rand
- MUL k
- INC AX
- MOV rand,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- END; {of FOR i}
- END;
-
- PROCEDURE SweepVertical(pa,time:WORD; down:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
- { down = TRUE/FALSE fuer: von oben nach unten/umgekehrt }
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST n=Succ(YMAX); {Anzahl Aufrufe der Verzoegerungsschleife}
- VAR y,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF down
- THEN FOR y:=0+StartVirtualY TO YMAX+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR y:=YMAX+StartVirtualY DOWNTO 0+StartVirtualY DO
- BEGIN
- Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
- PutImage(StartVirtualX,y,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE SweepHorizontal(pa,time:WORD; left_to_right:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
- { left_to_right=TRUE/FALSE fuer: von links nach rechts/umgekehrt}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST n=Succ(XMAX); {Anzahl Aufrufe der Verzoegerungsschleife}
- VAR x,counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- oldColor,step:BYTE;
- p:POINTER;
- BEGIN
- oldColor:=Color;
- Color:=white;
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF left_to_right
- THEN FOR x:=0+StartVirtualX TO XMAX+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END
- ELSE FOR x:=XMAX+StartVirtualX DOWNTO 0+StartVirtualX DO
- BEGIN
- Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
- PutImage(x,StartVirtualY,p,1-PAGE);
- FreeImageMem(p);
- END;
- Color:=oldColor
- END;
-
- PROCEDURE ScrollVertical(pa,time:WORD; up:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
- { up = TRUE/FALSE fuer: von unten nach oben/umgekehrt }
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- LABEL oneLine1,oneLine2;
- CONST n=Succ(YMAX); {Anzahl Aufrufe der Verzoegerungsschleife}
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF up
- THEN BEGIN {nach oben scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,YMAX*LINESIZE+(LINESIZE-1) {DX:BX = ^Quelldaten}
-
- MOV AX,YMAX {AX = Zeilenzaehler}
-
- oneLine2:
- STD {rueckwaerts moven!}
- MOV SI,ES {zuerst alten Inhalt nach oben rollen:}
- MOV DS,SI {DS=ES=sichtbare Grafikseite}
- MOV SI,(YMAX-1)*LINESIZE+(LINESIZE-1) {von vorletzter Grafikzeile}
- MOV DI,YMAX*LINESIZE+(LINESIZE-1) {nach letzter Grafikzeile}
- MOV CX,YMAX*LINESIZE {199 Zeilen}
- REP MOVSB
-
- MOV DS,DX {jetzt neue Zeile sichtbar machen:}
- MOV SI,BX {DS:SI=^zu movende Zeile}
- MOV CX,LINESIZE {1 Zeile}
- REP MOVSB
-
- SUB BX,LINESIZE {Quellzeiger weitersetzen}
-
- {--- Einschub fuer Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- CLD {sicher ist sicher!}
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- Einschub Ende}
-
- DEC AX {alle Zeilen durch?}
- JNS oneLine2 {nein, naechste Zeile}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {nach unten scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE {DX:BX = ^Quelldaten}
-
- MOV AX,YMAX {AX = Zeilenzaehler}
-
- oneLine1:
- MOV SI,ES {zuerst alten Inhalt nach oben rollen:}
- MOV DS,SI {DS=ES=sichtbare Grafikseite}
- MOV SI,1*LINESIZE {von Grafikzeile 1}
- MOV DI,0*LINESIZE {nach Grafikzeile 0}
- MOV CX,YMAX*LINESIZE {199 Zeilen}
- REP MOVSB
-
- MOV DS,DX {jetzt neue Zeile sichtbar machen:}
- MOV SI,BX {DS:SI=^zu movende Zeile}
- MOV CX,LINESIZE {1 Zeile}
- REP MOVSB
-
- ADD BX,LINESIZE {Quellzeiger weitersetzen}
-
- {--- Einschub fuer Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH BX
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP BX
- POP AX
- {--- Einschub Ende}
-
- DEC AX {alle Zeilen durch?}
- JNS oneLine1 {nein, naechste Zeile}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END;
-
- PROCEDURE ScrollHorizontal(pa,time:WORD; left:BOOLEAN);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
- { left = TRUE/FALSE fuer: von links nach rechts/umgekehrt}
- { 1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- LABEL oneColumn1,oneColumn2;
- CONST n=Pred(LINESIZE); {Anzahl Aufrufe der Verzoegerungsschleife}
- VAR counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- IF left
- THEN BEGIN {nach links scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
-
- MOV AX,LINESIZE-1 {AX = Spaltenzaehler}
-
- oneColumn2: {alten Schirminhalt nach rechts schieben:}
- MOV SI,ES
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,PAGESIZE-2
- MOV DI,PAGESIZE-1
- MOV CX,PAGESIZE-1
- STD
- REP MOVSB
- CLD
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP Daten}
- MOV CX,YMAX+1 {CX = Zeilenzaehler}
-
- MOV SI,AX
- XOR DI,DI
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^Quelldaten}
-
- @oneRow: {erste Spalte erneuern:}
- MOVSB
- ADD SI,BX {auf naechste Zeile positionieren:}
- ADD DI,BX {geht, weil BX+1=LINESIZE}
- LOOP @oneRow
-
- {--- Einschub fuer Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- Einschub Ende}
-
- DEC AX {alle Spalten durch?}
- JNS oneColumn2 {nein, naechste Spalte}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END
- ELSE BEGIN {nach rechts scrollen}
- ASM
- MOV DX,3C4h
- MOV AX,0F02h {alle 4 Planes gleichzeitig ansprechen}
- OUT DX,AX
- MOV DX,3CEh
- MOV AX,4105h {Writemode 1 setzen}
- OUT DX,AX
-
- MOV SI,1
- SUB SI,PAGE
- AND SI,1
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW
- MOV ES,AX {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
-
- MOV SI,pa
- AND SI,3
- SHL SI,1
- ADD SI,OFFSET Segment_Adr-StartIndex*2
- LODSW {AX:=Segment_Adr[pa] = ^Quelladresse}
-
- PUSH DS
- MOV DX,AX
- MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
-
- MOV AX,0 {AX = Spaltenzaehler}
-
- oneColumn1: {alten Schirminhalt nach links schieben:}
- MOV SI,ES
- MOV DS,SI {DS = ES = sichtbare Grafikseite}
- MOV SI,1
- XOR DI,DI
- MOV CX,PAGESIZE-1
- REP MOVSB
-
- MOV CX,SEG @DATA
- MOV DS,CX {DS = ^TP Daten}
- MOV CX,YMAX+1 {CX = Zeilenzaehler}
-
- MOV SI,AX
- MOV DI,LINESIZE-1
- MOV BX,LINESIZE-1
- MOV DS,DX {DS = ^Quelldaten}
-
- @oneRow: {letzte Spalte erneuern:}
- MOVSB
- ADD SI,BX {auf naechste Zeile positionieren:}
- ADD DI,BX {geht, weil BX+1=LINESIZE}
- LOOP @oneRow
-
- {--- Einschub fuer Zeitbedingung:}
- PUSH AX {alle noch relevanten Register retten}
- PUSH DX
- PUSH ES
- MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
- MOV DS,AX
- END;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- ASM;
- POP ES
- POP DX
- POP AX
- {--- Einschub Ende}
-
- INC AX {alle Spalten durch?}
- CMP AX,LINESIZE
- JB oneColumn1 {nein, naechste Spalte}
-
- MOV DX,3CEh {Writemode 0 wiederherstellen}
- MOV AX,4005h
- OUT DX,AX
- POP DS
- END;
- END;
- END;
-
- PROCEDURE CircleIn(pa,time:WORD);
- { in: pa = Seite, deren Inhalt sichtbar gemacht werden soll}
- { time = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
- {out: - }
- {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
- CONST centerX=XMAX DIV 2; {Bildschirmmitte}
- centerY=YMAX DIV 2;
- k=189; {Anzahl Kreise:= sqrt(centerX²+centerY²), aufgerundet}
- adjust=0.707106781; {Kompensation in Diagonalrichtung = 1/sqrt(2) }
- n=TRUNC(k/adjust); {Anzahl Aufrufe der Verzoegerungsschleife}
- VAR radqu,x,y,x0,y0,u1,u2,u3,u4,v1,v2,v3,v4:WORD;
- counter:WORD;
- ClockTicks:LONGINT ABSOLUTE $40:$6C;
- t:LONGINT;
- radius,temp:REAL;
- BEGIN
- t:=ClockTicks;
- counter:=0;
- temp:=0.0182*time/n;
- x0:=centerX + StartVirtualX;
- y0:=centerY + StartVirtualY;
- {FOR true_radius:=1 TO k STEP 1/adjust ist in Pascal leider nicht moeglich!}
- radius:=0.0;
- REPEAT
- radqu:=TRUNC(sqr(radius));
- FOR x:=0 TO TRUNC(radius/sqrt(2)) DO {Oktanden berechnen}
- BEGIN
- y:=TRUNC(sqrt(radqu-sqr(x))); {Satz des Pythagoras}
- u1:=x0-x; v1:=y0-y; {Achsen- und Punktsymmetrie ausnutzen}
- u2:=x0+x; v2:=y0+y;
- u3:=x0-y; v3:=y0-x;
- u4:=x0+y; v4:=y0+x;
- PutPixel(u1,v1,PageGetPixel(u1,v1,pa));
- PutPixel(u1,v2,PageGetPixel(u1,v2,pa));
- PutPixel(u2,v1,PageGetPixel(u2,v1,pa));
- PutPixel(u2,v2,PageGetPixel(u2,v2,pa));
- PutPixel(u3,v3,PageGetPixel(u3,v3,pa));
- PutPixel(u3,v4,PageGetPixel(u3,v4,pa));
- PutPixel(u4,v3,PageGetPixel(u4,v3,pa));
- PutPixel(u4,v4,PageGetPixel(u4,v4,pa));
- END;
- radius:=radius+adjust;
- INC(counter);
- WHILE ClockTicks<t+counter*temp DO BEGIN END;
- UNTIL radius>=k;
- END;
-
- BEGIN {of FadeIn}
- IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
- THEN Error:=Err_InvalidPageNumber
- ELSE CASE style OF
- Fade_Squares :WipeIn(pa,ti);
- Fade_Moiree1..Fade_Moiree14:Chaos(pa,ti,style+1-Fade_Moiree1);
- Fade_SweepInFromTop: SweepVertical(pa,ti,TRUE);
- Fade_SweepInFromBottom: SweepVertical(pa,ti,FALSE);
- Fade_SweepInFromLeft: SweepHorizontal(pa,ti,TRUE);
- Fade_SweepInFromRight: SweepHorizontal(pa,ti,FALSE);
- Fade_ScrollInFromTop: ScrollVertical(pa,ti,TRUE);
- Fade_ScrollInFromBottom:ScrollVertical(pa,ti,FALSE);
- Fade_ScrollInFromLeft: ScrollHorizontal(pa,ti,TRUE);
- Fade_ScrollInFromRight: ScrollHorizontal(pa,ti,FALSE);
- Fade_Circles : CircleIn(pa,ti);
- else Error:=Err_InvalidFade
- END;
- END;
-
-
- PROCEDURE InitRoutines;
- { in: - }
- {out: SpriteN[],SPRITEAD[] wurden auf "gaenzlich leer" initialisiert }
- { NextSprite[] wurde so gesetzt, dass jedes Sprite sein eigener Nach-}
- { folger ist}
- { PAGE, PAGEADR wurden auf die Grafikseite 0 eingestellt}
- { BACKGNDADR wurde auf die Hintergrundseite gesetzt }
- { SCROLLADR wurde auf die scrollbare Hintergrundseite gesetzt}
- { BACKGROUNDMODE wurde auf STATIC gesetzt}
- { als Defaulttile fuer den scrollbaren Hintergrund wurde #0 gesetzt }
- { StartVirtualX,StartVirtualY = 0 (d.h.: virtuelle = absolute Koord.)}
- { oldMode = alter Grafikmodus}
- { Error wurde gesetzt, falls keine VGA-Karte im System enthalten ist }
- { CycleTime = 0, d.h.: keine Mindestzeit fuer einen Animationszyklus }
- { Color = 15, d.h.: weiss }
- { ActualColors = Defaultfarbpalette des Modus $13 }
- { CRTAddress = Portadresse des CRT-Adressregisters}
- { StatusReg = Portadresse des Statusregisters }
- {rem: Diese Prozedur sollte einmal - ganz zu Beginn - zur Initialisierung}
- { des Animationspaketes aufgerufen werden }
- VAR i:WORD;
-
- FUNCTION IsVGA:BOOLEAN;
- BEGIN
- WITH Regs DO
- BEGIN
- AX:=$1A00;
- Intr($10,Regs);
- IsVGA:=(AL=$1A) AND {VGA Identify-Adapter-Function unterstuetzt?}
- ( (BL=7) OR (BL=8) ) {VGAMono oder VGAColor - Adapter}
- END;
- END;
-
- BEGIN
- IF IsVGA THEN Error:=Err_None
- ELSE Error:=Err_NoVGA;
-
- SetCycleTime(0);
-
- fillchar(SpriteN,sizeof(SpriteN),0);
- fillchar(SPRITEAD,sizeof(SPRITEAD),0);
-
- FOR i:=0 TO LoadMAX DO NextSprite[i]:=i;
-
- BACKGNDADR:=Segment_Adr[BACKGNDPAGE]; {Segmentadresse der Hintergrundseite}
-
- PAGE:=0; {Seite, auf der gezeichnet werden soll}
- PAGEADR:=Segment_Adr[PAGE];
- SCROLLADR:=Segment_Adr[SCROLLPAGE];
- SetBackgroundMode(STATIC);
- SetOffscreenTile(0);
-
- StartVirtualX:=0; StartVirtualY:=0; {virtuelle = absolute Koordinaten}
- Color:=white; {aktuelle Zeichenfarbe sei Weiss }
- regs.ah:=$f; intr($10,regs); oldMode:=regs.al;
-
- ActualColors:=DefaultColors;
- {SetShadowTab(Schatten) kann entfallen, da Defaultwerte schon gesetzt!}
-
- ASM {ermitteln, ob Farb- oder Monochromdarstellung}
- MOV DX,3CCh {Output-Register befragen:}
- IN AL,DX
- TEST AL,1 {ist es ein Farbbildschirm?}
- MOV DX,3D4h
- JNZ @L1 {ja }
- MOV DX,3B4h {nein}
- @L1: {DX=3B4h/3D4h = CRTAddress-Register fuer monochrom/Farbe}
- MOV CRTAddress,DX
- ADD DX,6 {DX=3BAh/3DAh = Status-Register fuer monochrom/Farbe}
- MOV StatusReg,DX
- END; {of ASM}
- END;
-
- PROCEDURE CloseRoutines;
- { in: oldMode = alter Grafikmodus, auf den zurueckgeschaltet werden soll}
- {out: - }
- BEGIN
- regs.al:=oldMode; regs.ah:=0; intr($10,regs);
- END;
-
- FUNCTION GetErrorMessage:STRING;
- { in: Error = Nummer des aufgetretenen Fehlers}
- {out: den Fehler in Worten}
- BEGIN
- CASE Error OF
- Err_None:GetErrorMessage:='No Error';
- Err_NotEnoughMemory:GetErrorMessage:='Not enough memory available on heap';
- Err_FileIO:GetErrorMessage:='I/O-error with file';
- Err_InvalidSpriteNumber:GetErrorMessage:='Invalid sprite number used';
- Err_NoSprite:GetErrorMessage:='No (or corrupted) sprite file';
- Err_InvalidPageNumber:GetErrorMessage:='Invalid page number used';
- Err_NoVGA:GetErrorMessage:='No VGA-card found';
- Err_NoPicture:GetErrorMessage:='No (or corrupted) picture file';
- Err_InvalidPercentage:GetErrorMessage:='Percentage value must be 0..100';
- Err_NoTile:GetErrorMessage:='No (or corrupted) tile/sprite file';
- Err_InvalidTileNumber:GetErrorMessage:='Invalid tile number used';
- Err_InvalidCoordinates:GetErrorMessage:='Invalid coordinates used';
- Err_BackgroundToBig:GetErrorMessage:='Background to big for tile-buffer';
- Err_InvalidMode:GetErrorMessage:='Only STATIC or SCROLLING allowed here';
- Err_InvalidSpriteLoadNumber:GetErrorMessage:='Invalid spriteload number used';
- Err_NoPalette:GetErrorMessage:='No (or corrupted) palette file';
- Err_PaletteWontFit:GetErrorMessage:='Attempt to write beyond palette end';
- Err_InvalidFade:GetErrorMessage:='Invalid fade style used';
- ELSE GetErrorMessage:='Unknown error';
- END;
- END;
-
-
- BEGIN
-
- InitRoutines;
-
- END.
-