From: sparky4 Date: Wed, 2 Jul 2014 17:16:50 +0000 (-0500) Subject: modified: 16/DOS_GFX.EXE X-Git-Url: http://4ch.mooo.com/gitweb/?a=commitdiff_plain;h=d93cdaff4168104cb64af6658c22344dcecf74f1;p=16.git modified: 16/DOS_GFX.EXE modified: 16/DOS_GFX.OBJ modified: 16/dos_gfx.cpp new file: 16/lib/modex105/ASM.BAT new file: 16/lib/modex105/DEMOS/BASIC7/CHARDEMO.BAS new file: 16/lib/modex105/DEMOS/BASIC7/MAKE-LIB.BAT new file: 16/lib/modex105/DEMOS/BASIC7/MODEX.BI new file: 16/lib/modex105/DEMOS/BASIC7/MODEX.LIB new file: 16/lib/modex105/DEMOS/BASIC7/MODEX.OBJ new file: 16/lib/modex105/DEMOS/BASIC7/MODEX.QLB new file: 16/lib/modex105/DEMOS/BASIC7/TEST6.BAS new file: 16/lib/modex105/DEMOS/BASIC7/UASM-BC7.BAT new file: 16/lib/modex105/DEMOS/BASIC7/UTILS.ASM new file: 16/lib/modex105/DEMOS/BASIC7/UTILS.BI new file: 16/lib/modex105/DEMOS/BASIC7/UTILS.OBJ new file: 16/lib/modex105/DEMOS/C/C_UTILS.ASM new file: 16/lib/modex105/DEMOS/C/C_UTILS.H new file: 16/lib/modex105/DEMOS/C/C_UTILS.OBJ new file: 16/lib/modex105/DEMOS/C/MODEX.ASM new file: 16/lib/modex105/DEMOS/C/MODEX.BI new file: 16/lib/modex105/DEMOS/C/MODEX.H new file: 16/lib/modex105/DEMOS/C/MODEX.OBJ new file: 16/lib/modex105/DEMOS/C/UTLS-ASM.BAT new file: 16/lib/modex105/DEMOS/C/X-DEMO.C new file: 16/lib/modex105/DEMOS/C/X-DEMO.EXE new file: 16/lib/modex105/DEMOS/C/X-DEMO.OBJ new file: 16/lib/modex105/DEMOS/C/X-DEMO.PRJ new file: 16/lib/modex105/DEMOS/C/x.exe new file: 16/lib/modex105/DEMOS/CHARDEMO.EXE new file: 16/lib/modex105/DEMOS/PASCAL/TEST5.PAS new file: 16/lib/modex105/DEMOS/QB45/MAKE-LIB.BAT new file: 16/lib/modex105/DEMOS/QB45/MODEX.BI new file: 16/lib/modex105/DEMOS/QB45/MODEX.LIB new file: 16/lib/modex105/DEMOS/QB45/MODEX.OBJ new file: 16/lib/modex105/DEMOS/QB45/MODEX.QLB new file: 16/lib/modex105/DEMOS/QB45/TEST6A.BAS new file: 16/lib/modex105/DEMOS/QB45/TEST6A.EXE new file: 16/lib/modex105/DEMOS/QB45/UASM-QB4.BAT new file: 16/lib/modex105/DEMOS/QB45/UTILS.ASM new file: 16/lib/modex105/DEMOS/QB45/UTILS.BI new file: 16/lib/modex105/DEMOS/QB45/UTILS.OBJ new file: 16/lib/modex105/DEMOS/ROM_8X8.FNT new file: 16/lib/modex105/DEMOS/SPACEAGE.FNT new file: 16/lib/modex105/DEMOS/SYSTEM.FNT new file: 16/lib/modex105/DEMOS/TEST6.EXE new file: 16/lib/modex105/FONTEDIT/CHARSETS.CS new file: 16/lib/modex105/FONTEDIT/CSEDIT.DOC new file: 16/lib/modex105/FONTEDIT/CSEDIT.EXE new file: 16/lib/modex105/FONTEDIT/INVERSE.FNT new file: 16/lib/modex105/FONTEDIT/MOUSEIMG.CS new file: 16/lib/modex105/FONTEDIT/PALETTE.CS new file: 16/lib/modex105/FONTEDIT/ROM_8X8.FNT new file: 16/lib/modex105/FONTEDIT/SPACEAGE.FNT new file: 16/lib/modex105/FONTEDIT/SYSTEM.FNT new file: 16/lib/modex105/MODE-X.TXT new file: 16/lib/modex105/MODEX.ASM new file: 16/lib/modex105/MODEX.BI new file: 16/lib/modex105/MODEX.COM new file: 16/lib/modex105/MODEX.H new file: 16/lib/modex105/MODEX.LST new file: 16/lib/modex105/MODEX.OBJ new file: 16/lib/modex105/MODEX.SBR new file: 16/lib/modex105/PACKING.LST new file: 16/lib/modex105/PALEDIT/CHARSETS.CS new file: 16/lib/modex105/PALEDIT/GAMECOLR.PAL new file: 16/lib/modex105/PALEDIT/MOUSEIMG.CS new file: 16/lib/modex105/PALEDIT/PALEDIT.DOC new file: 16/lib/modex105/PALEDIT/PALEDIT.EXE new file: 16/lib/modex105/PALEDIT/PRIME.PAL new file: 16/lib/modex105/PALEDIT/RGB.PAL new file: 16/lib/modex105/README.DOC new file: 16/lib/modex105/modex105.zip new file: 16/vgap.pcx --- diff --git a/16/DOS_GFX.EXE b/16/DOS_GFX.EXE index 064b25db..33f8bba9 100644 Binary files a/16/DOS_GFX.EXE and b/16/DOS_GFX.EXE differ diff --git a/16/DOS_GFX.OBJ b/16/DOS_GFX.OBJ index b5949851..b159b50c 100644 Binary files a/16/DOS_GFX.OBJ and b/16/DOS_GFX.OBJ differ diff --git a/16/dos_gfx.cpp b/16/dos_gfx.cpp index abe38f8e..f26fd4f7 100644 --- a/16/dos_gfx.cpp +++ b/16/dos_gfx.cpp @@ -56,20 +56,18 @@ void setvideo(/*byte mode, */short vq){ //mxSetClipRegion(0, VH+1, VW, (TILEWH*BUFFMX)); } } - -void pdump(){ - int mult=QUADWH; - int palq=mult*16; - int palcol=0; - for(int paly=0; paly(VW-SW-1)) || (xpos<1))delay(500); //mxWaitRetrace(); -//mxBitBlt(32, (SH+32), SW, SH, xpos, ypos); +//mxBitBlt(32, (SH+32), SW, SH, xpos, ypos); mxBitBlt(TILEWH*2, (SH+64+32), SW, SH, TILEWH*2, TILEWH*2); //xpos=ypos=TILEWH*2; mxPan(32,32); @@ -379,7 +377,7 @@ mxPan(32,32); if( (xpos>(VW-SW-1)) || (xpos<1)){xdir=-xdir;} if( (ypos>(BH-SH-1)) || (ypos<1)){ydir=-ydir;} // { Hit a boundry, change // direction! } -//mxBitBlt(32, (SH+64+32), SW, SH, xpos, ypos); +//mxBitBlt(32, (SH+64+32), SW, SH, xpos, ypos); //mxBitBlt(TILEWH*2, (SH+64+32), SW, SH, TILEWH*2, TILEWH*2); } ch=getch(); diff --git a/16/lib/modex105/ASM.BAT b/16/lib/modex105/ASM.BAT new file mode 100644 index 00000000..2e5785f9 --- /dev/null +++ b/16/lib/modex105/ASM.BAT @@ -0,0 +1 @@ +MASM modex,modex,modex,nul \ No newline at end of file diff --git a/16/lib/modex105/DEMOS/BASIC7/CHARDEMO.BAS b/16/lib/modex105/DEMOS/BASIC7/CHARDEMO.BAS new file mode 100644 index 00000000..627e3278 --- /dev/null +++ b/16/lib/modex105/DEMOS/BASIC7/CHARDEMO.BAS @@ -0,0 +1,164 @@ +DEFINT A-Z +DECLARE SUB PRINT.STRING (Text$, Xpos%, Ypos%, Colour%) +DECLARE FUNCTION MakePal$ (Red%, Green%, Blue%) +DECLARE SUB LOAD.FONT (FontFile$, FontNum%) +DECLARE SUB ERROR.OUT (Text$) + + REM $INCLUDE: 'MODEX.BI' + + REM $INCLUDE: 'UTILS.BI' + +TYPE FONT + SetData AS STRING * 1024 +END TYPE + + +TYPE VGAPalette + PalData AS STRING * 768 +END TYPE + + + ' Alternate form of LOAD_DAC_REGISTERS so we can pass an offset into + ' a String instead of the Address of the String + +DECLARE SUB LOAD.DACS ALIAS "LOAD_DAC_REGISTERS" (BYVAL Addr&, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) + + + ' + 'MODE X DEMO of Multiple Character Sets and Block Color Cycling + ' + 'By Matt Pritchard + ' + +COMMON SHARED CharSet() AS FONT + +DIM Pal AS VGAPalette + + REM $DYNAMIC + +DIM SHARED CharSet(0 TO 3) AS FONT + + + LOAD.FONT "SYSTEM.FNT", 0 + LOAD.FONT "ROM_8x8.FNT", 1 + LOAD.FONT "SPACEAGE.FNT", 2 + + + IF SET.MODEX(Mode320x240) = False THEN + ERROR.OUT "ERROR SETTING MODE X" + END IF + + + A$ = "": B$ = "" + FOR X = 0 TO 31: A$ = A$ + MakePal$(31 - X, X, 0): NEXT X + FOR X = 0 TO 31: A$ = A$ + MakePal$(0, 31 - X, X): NEXT X + FOR X = 0 TO 31: A$ = A$ + MakePal$(X, 0, 31 - X): NEXT X + + FOR X = 0 TO 31: B$ = B$ + MakePal$(31 - X, X, X): NEXT X + FOR X = 0 TO 31: B$ = B$ + MakePal$(X, 31 - X, X): NEXT X + FOR X = 0 TO 31: B$ = B$ + MakePal$(X, X, 31 - X): NEXT X + + Black$ = STRING$(192, 0) + White$ = STRING$(128 * 3, 48) + + Pal1$ = Black$ + A$ + A$ + B$ + B$ + A$ + + LOAD.DACS SSEGADD(Black$), 64, 127, 1 + LOAD.DACS SSEGADD(Black$), 20, 63, 0 + + LOAD.DACS SSEGADD(White$), 128, 255, 0 + + '*** Background *** + + FOR X = 0 TO 319 + FOR Y = 0 TO 239 + IF ((X + Y) AND 1) = 1 THEN SET.POINT X, Y, 64 + X \ 5 ELSE SET.POINT X, Y, 20 + Y \ 6 + NEXT Y + NEXT X + + '*** Draw Font Displays *** + + PRINT.STRING "FONT: SYSTEM.FNT", 11, 7, 15 + PRINT.STRING "FONT: ROM_8x8.FNT", 11, 17, 15 + PRINT.STRING "FONT: SPACEAGE.FNT", 11, 27, 15 + PRINT.STRING "PRESS ANY KEY TO CONTINUE", 8, 29, 14 + + + FOR F = 0 TO 2 + SET.DISPLAY.FONT CharSet(F), 1 + Yp = F * 80 + 10 + FOR Y = 0 TO 96 STEP 32 + FOR X = 0 TO 31 + TGPRINTC 128 + Y + X, X * 10 + 1, Yp, 128 + Y + NEXT X + Yp = Yp + 10 + NEXT Y + NEXT F + + DO + LOOP UNTIL SCAN.KEYBOARD + + Offset = 0 + Restart = 192 + MaxOfs = 192 + 96 * 6 + + Delay = 100 + + Offset2 = 0 + Offset2Dir = 3 + Offset2Min = 192 + Offset2Max = Offset2Min + 192 * 6 + + DO + LOAD.DACS SSEGADD(Pal1$) + Offset, 64, 127, 1 + Offset = Offset + 3 + IF Offset >= MaxOfs THEN Offset = Restart + IF Delay THEN + Delay = Delay - 1 + ELSE + LOAD.DACS SSEGADD(Pal1$) + Offset2, 20, 60, 0 + IF Offset2 = Offset2Max THEN Offset2Dir = -3 + IF Offset2 = Offset2Min THEN Offset2Dir = 3 + Offset2 = Offset2 + Offset2Dir + END IF + + LOOP UNTIL SCAN.KEYBOARD + + ERROR.OUT "DEMO OVER" + +REM $STATIC +SUB ERROR.OUT (Text$) + + SET.VIDEO.MODE 3 + + DOS.PRINT Text$ + + END + +END SUB + +SUB LOAD.FONT (FontFile$, FontNum) STATIC + + IF LEN(DIR$(FontFile$)) = 0 THEN ERROR.OUT "FILE NOT FOUND: " + FontFile$ + + OPEN FontFile$ FOR BINARY AS #1 + + SEEK #1, 1 + GET #1, , CharSet(FontNum) + + CLOSE #1 + +END SUB + +FUNCTION MakePal$ (Red, Green, Blue) STATIC + + MakePal$ = CHR$(Red) + CHR$(Green) + CHR$(Blue) + +END FUNCTION + +SUB PRINT.STRING (Text$, Xpos, Ypos, Colour) + + TPRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos * 8, Ypos * 8, Colour + +END SUB + diff --git a/16/lib/modex105/DEMOS/BASIC7/MAKE-LIB.BAT b/16/lib/modex105/DEMOS/BASIC7/MAKE-LIB.BAT new file mode 100644 index 00000000..fc0b3b5c --- /dev/null +++ b/16/lib/modex105/DEMOS/BASIC7/MAKE-LIB.BAT @@ -0,0 +1,5 @@ +ECHO ... Building MODEX.QLB for BASIC PDS 7.1 +LIB MODEX -+MODEX,, +LIB MODEX -+UTILS,, +DEL MODEX.BAK +LINK /Q MODEX+UTILS, MODEX.QLB, NUL, C:\BC7\LIB\QBXQLB.LIB; diff --git a/16/lib/modex105/DEMOS/BASIC7/MODEX.BI b/16/lib/modex105/DEMOS/BASIC7/MODEX.BI new file mode 100644 index 00000000..6b1d7afe --- /dev/null +++ b/16/lib/modex105/DEMOS/BASIC7/MODEX.BI @@ -0,0 +1,63 @@ + + ' ===== SCREEN RESOLUTIONS ===== + +CONST Mode320x200 = 0, Mode320x400 = 1 +CONST Mode360x200 = 2, Mode360x400 = 3 +CONST Mode320x240 = 4, Mode320x480 = 5 +CONST Mode360x240 = 6, Mode360x480 = 7 + + ' ===== MODE X SETUP ROUTINES ===== + +DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%) +DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%) + + ' ===== BASIC GRAPHICS PRIMITIVES ===== + +DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%) +DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%) +DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%) +DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) +DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) + + ' ===== DAC COLOR REGISTER ROUTINES ===== + +DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%) +DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%) +DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) +DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%) + + + ' ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE" +DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE" +DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%) +DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" () +DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" () +DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY" + + ' ===== TEXT DISPLAY ROUTINES ===== + +DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%) + + ' ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) +DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) + + ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%) +DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%) + + + + + + diff --git a/16/lib/modex105/DEMOS/BASIC7/MODEX.LIB b/16/lib/modex105/DEMOS/BASIC7/MODEX.LIB new file mode 100644 index 00000000..0a0364a3 Binary files /dev/null and b/16/lib/modex105/DEMOS/BASIC7/MODEX.LIB differ diff --git a/16/lib/modex105/DEMOS/BASIC7/MODEX.OBJ b/16/lib/modex105/DEMOS/BASIC7/MODEX.OBJ new file mode 100644 index 00000000..80b311d6 Binary files /dev/null and b/16/lib/modex105/DEMOS/BASIC7/MODEX.OBJ differ diff --git a/16/lib/modex105/DEMOS/BASIC7/MODEX.QLB b/16/lib/modex105/DEMOS/BASIC7/MODEX.QLB new file mode 100644 index 00000000..70d22db3 Binary files /dev/null and b/16/lib/modex105/DEMOS/BASIC7/MODEX.QLB differ diff --git a/16/lib/modex105/DEMOS/BASIC7/TEST6.BAS b/16/lib/modex105/DEMOS/BASIC7/TEST6.BAS new file mode 100644 index 00000000..220a67ba --- /dev/null +++ b/16/lib/modex105/DEMOS/BASIC7/TEST6.BAS @@ -0,0 +1,562 @@ +'File: TEST6.BAS +'Descp.: A Mode "X" demonstration +'Author: Matt Pritchard +'Date: 14 April, 1993 +' +DECLARE SUB DEMO.RES (Mode%, Xmax%, Ymax%) +DECLARE SUB ERROR.OUT (Message$) +DECLARE FUNCTION GET.KEY% () +DECLARE SUB LOAD.SHAPES () +DECLARE SUB PAGE.DEMO () +DECLARE SUB PRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%, ColorB%) +DECLARE SUB TPRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%) +DEFINT A-Z + + +TYPE ShapeType + ImgData AS STRING * 512 + xWidth AS INTEGER + yWidth AS INTEGER +END TYPE + +TYPE Sprite + Xpos AS INTEGER + Ypos AS INTEGER + XDir AS INTEGER + YDir AS INTEGER + Shape AS INTEGER +END TYPE + + +CONST MaxShapes = 32 + + REM $INCLUDE: 'UTILS.BI' + REM $INCLUDE: 'MODEX.BI' + +DIM SHARED Img(32) AS ShapeType +COMMON SHARED Img() AS ShapeType + + + CALL INIT.RANDOM + + CALL LOAD.SHAPES + + CALL DEMO.RES(Mode320x200, 320, 200) + CALL DEMO.RES(Mode320x400, 320, 400) + + CALL DEMO.RES(Mode360x200, 360, 200) + CALL DEMO.RES(Mode360x400, 360, 400) + + CALL DEMO.RES(Mode320x240, 320, 240) + CALL DEMO.RES(Mode320x480, 320, 480) + + CALL DEMO.RES(Mode360x240, 360, 240) + CALL DEMO.RES(Mode360x480, 360, 480) + + CALL PAGE.DEMO + + SET.VIDEO.MODE 3 + DOS.PRINT "THIS MODE X DEMO IS FINISHED" + END + +SUB DEMO.RES (Mode, Xmax, Ymax) + + IF SET.MODEX%(Mode) = 0 THEN + ERROR.OUT "Unable to SET_MODEX" + STR$(Mode) + END IF + + XCenter = Xmax \ 2 + + X1 = 10 + Y1 = 10 + X2 = Xmax - 1 + Y2 = Ymax - 1 + + FOR Z = 0 TO 3 + Colr = 31 - Z * 2 + DRAW.LINE X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr + DRAW.LINE X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr + DRAW.LINE X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr + DRAW.LINE X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr + NEXT Z + + XChars = Xmax \ 10 + YChars = Ymax \ 10 + + FOR X = 0 TO XChars - 1 + TGPRINTC 48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X \ 8) MOD 7) + DRAW.LINE X * 10 + 9, 0, X * 10 + 9, 3, 15 + NEXT X + + FOR Y = 0 TO YChars - 1 + TGPRINTC 48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y \ 10) MOD 7) + DRAW.LINE 0, Y * 10 + 9, 3, Y * 10 + 9, 15 + NEXT Y + + ' Draw Lines + + FOR X = 0 TO 63 + N = 15 + X * .75 + SET.DAC.REGISTER 64 + X, N, N, N + SET.DAC.REGISTER 128 + X, 0, N, N + + DRAW.LINE 103 - X, 60, 40 + X, 123, 64 + X + DRAW.LINE 40, 60 + X, 103, 123 - X, 128 + X + + NEXT X + TPRINT.TEXT "LINE TEST", 37, 130, c.BLUE + + Y = 60: Gap = 0 + FOR X = 0 TO 9 + FILL.BLOCK 120, Y, 120 + X, Y + Gap, 64 + X + FILL.BLOCK 140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X + FILL.BLOCK 170 - (15 - X), Y, 170, Y + Gap, 128 + X + Y = Y + Gap + 2 + Gap = Gap + 1 + NEXT X + TPRINT.TEXT "FILL TEST", 110, 46, c.GREEN + + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + SET.POINT X, Y, X + Y + X + Y + NEXT Y + NEXT X + + TPRINT.TEXT "PIXEL TEST", 182, 130, c.RED + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + IF READ.POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN + ERROR.OUT "READ.PIXEL Failure" + END IF + NEXT Y + NEXT X + + + + Msg$ = " This is a MODE X demo " + PRINT.TEXT Msg$, XCenter - (LEN(Msg$) * 4), 20, c.bRED, c.BLUE + Msg$ = "Screen Resolution is by " + Xp = XCenter - (LEN(Msg$) * 4) + PRINT.TEXT Msg$, Xp, 30, c.bGREEN, c.BLACK + + PRINT.TEXT LTRIM$(STR$(Xmax)), Xp + 8 * 21, 30, c.bPURPLE, c.BLACK + PRINT.TEXT LTRIM$(STR$(Ymax)), Xp + 8 * 28, 30, c.bWHITE, c.BLACK + + FOR X = 0 TO 15 + SET.DAC.REGISTER 230 + X, 63 - X * 4, 0, 15 + X * 3 + DRAW.LINE 30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X + NEXT X + TPRINT.TEXT "Press to Continue", XCenter - (26 * 4), Ymax - 18, c.YELLOW + + X = GET.KEY% + IF X = KyESC THEN ERROR.OUT "ABORT" + +END SUB + +SUB ERROR.OUT (Message$) + + SET.VIDEO.MODE 3 + DOS.PRINT Message$ + END + +END SUB + +FUNCTION GET.KEY% + + DO + X = SCAN.KEYBOARD + LOOP UNTIL X + + GET.KEY% = X + +END FUNCTION + +SUB LOAD.SHAPES + +DIM Grid(1 TO 32, 1 TO 32) + + FOR Shape = 0 TO MaxShapes - 1 + + FOR Y = 1 TO 32 + FOR X = 1 TO 32 + Grid(X, Y) = 0 + NEXT X + NEXT Y + + Style = RANDOM.INT(6) + Colour = 1 + RANDOM.INT(15) + + SELECT CASE Style + + CASE 0: ' Solid Box + + DO + xWidth = 3 + RANDOM.INT(30) + yWidth = 3 + RANDOM.INT(30) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + CASE 1: ' Hollow Box + + DO + xWidth = 5 + RANDOM.INT(28) + yWidth = 5 + RANDOM.INT(28) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + HollowX = 1 + RANDOM.INT(xWidth \ 2 - 1) + HollowY = 1 + RANDOM.INT(yWidth \ 2 - 1) + + FOR Y = HollowY + 1 TO yWidth - HollowY + FOR X = HollowX + 1 TO xWidth - HollowX + Grid(X, Y) = nil + NEXT X + NEXT Y + + CASE 2: ' Solid Diamond + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + NEXT X + NEXT Y + + + CASE 3: ' Hollow Diamond + + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + sWidth = RANDOM.INT(Centre) + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + IF X + (Centre - Y) >= sWidth THEN + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + END IF + NEXT X + NEXT Y + + CASE 4: ' Ball + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + CASE 5: ' Ball + + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + sWidth = RANDOM.INT(xWidth) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre AND D >= sWidth THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + END SELECT + + Img(Shape).xWidth = xWidth + Img(Shape).yWidth = yWidth + + A$ = STRING$(xWidth * yWidth, nil) + + c = 1 + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + MID$(A$, c, 1) = CHR$(Grid(X, Y)) + c = c + 1 + NEXT X + NEXT Y + + Img(Shape).ImgData = A$ + + + NEXT Shape + +END SUB + +SUB PAGE.DEMO + +CONST MaxSprites = 64 + +DIM Obj(MaxSprites) AS Sprite +DIM LastX(MaxSprites, 1), LastY(MaxSprites, 1) +DIM LastObjects(1) + + ScreenX = 360: ScreenY = 240 + + IF SET.VGA.MODEX%(Mode320x200, ScreenX, ScreenY, 3) = 0 THEN + ERROR.OUT "Unable to SET_VGA_MODEX" + STR$(Mode) + END IF + + SET.ACTIVE.PAGE 0 + + CLEAR.VGA.SCREEN c.BLACK + + PRINT.TEXT "This is a Test of the Following Functions:", 10, 9, c.bWHITE, c.BLACK + + DRAW.LINE 10, 18, 350, 18, c.YELLOW + PRINT.TEXT "SET_ACTIVE_PAGE", 10, 20, c.bBLUE, c.BLACK + PRINT.TEXT "SET_DISPLAY_PAGE", 10, 30, c.GREEN, c.BLACK + PRINT.TEXT "SET_DAC_REGISTER", 10, 40, c.RED, c.BLACK + PRINT.TEXT "CLEAR_VGA_SCREEN", 10, 50, c.CYAN, c.BLACK + + PRINT.TEXT "TDRAW_BITMAP", 10, 60, c.PURPLE, c.BLACK + PRINT.TEXT "COPY_PAGE", 10, 70, c.GREEN, c.BLACK + PRINT.TEXT "COPY_BITMAP", 10, 80, c.CYAN, c.BLACK + + PRINT.TEXT "GPRINTC", 10, 90, c.BLUE, c.BLACK + PRINT.TEXT "TGPRINTC", 10, 100, c.GREEN, c.BLACK + PRINT.TEXT "SET_WINDOW", 10, 110, c.RED, c.BLACK + + PRINT.TEXT "VIRTUAL SCREEN SIZES", 190, 20, c.bBLUE, c.BLACK + PRINT.TEXT " SMOOTH SCROLLING", 190, 30, c.GREEN, c.BLACK + PRINT.TEXT " SPRITE ANIMATION", 190, 40, c.CYAN, c.BLACK + PRINT.TEXT " PAGE FLIPPING", 190, 50, c.RED, c.BLACK + PRINT.TEXT " COLOR CYCLING", 190, 60, c.PURPLE, c.BLACK + + + FOR X = 0 TO 60 + SET.DAC.REGISTER 50 + X, 3 + X, 0, 60 - X + SET.DAC.REGISTER 150 + X, 3 + X, 0, 60 - X + NEXT X + + c = 0: DC = 1 + FOR X = 0 TO ScreenX \ 2 + DRAW.LINE ScreenX \ 2 - 1, ScreenY \ 4, X, ScreenY - 1, c + 50 + DRAW.LINE ScreenX \ 2, ScreenY \ 4, ScreenX - X - 1, ScreenY - 1, c + 50 + c = c + DC + IF c = 0 OR c = 60 THEN DC = -DC + NEXT X + + TPRINT.TEXT "Press to Continue", 72, 190, c.bWHITE + TPRINT.TEXT "< > = Faster < > = Slower", 72, 204, c.bGREEN + TPRINT.TEXT "< > = Fewer Shapes < > = More Shapes", 32, 218, c.bCYAN + + TGPRINTC 43, 80, 204, c.YELLOW + TGPRINTC 45, 200, 204, c.YELLOW + + TGPRINTC 25, 40, 218, c.YELLOW + TGPRINTC 24, 200, 218, c.YELLOW + + COPY.PAGE 0, 1 + COPY.PAGE 0, 2 + + FOR X = 1 TO MaxSprites + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + + Obj(X).Shape = X MOD MaxShapes + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + Obj(X).Xpos = 1 + RANDOM.INT(ScreenX - SpriteX - 2) + Obj(X).Ypos = 1 + RANDOM.INT(ScreenY - SpriteY - 2) + + LastX(X, 0) = Obj(X).Xpos + LastX(X, 1) = Obj(X).Xpos + LastY(X, 0) = Obj(X).Ypos + LastY(X, 1) = Obj(X).Ypos + NEXT X + + CurrentPage = 0 + + 'View Shift... + + ViewX = 0 + ViewY = 0 + ViewMax = 3 + ViewCnt = 0 + ViewXD = 1 + ViewYD = 1 + + SetColor = 3: SDir = 1 + PrevColor = 0: PDir = 1 + + VisObjects = MaxSprites \ 2 + LastObjects(0) = 0 + LastObjects(1) = 0 + +DRAW.LOOP: + + + SET.ACTIVE.PAGE CurrentPage + + ' Erase Old Images + + FOR X = 1 TO LastObjects(CurrentPage) + + X1 = LastX(X, CurrentPage) AND &HFFFC + Y1 = LastY(X, CurrentPage) + X2 = ((LastX(X, CurrentPage) + Img(Obj(X).Shape).xWidth)) OR 3 + Y2 = Y1 + Img(Obj(X).Shape).yWidth - 1 + + COPY.BITMAP 2, X1, Y1, X2, Y2, CurrentPage, X1, Y1 + + NEXT X + + ' Draw new images + + FOR X = 1 TO VisObjects + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + ' Move Sprite + +REDOX: + NewX = Obj(X).Xpos + Obj(X).XDir + IF NewX < 0 OR NewX + SpriteX > ScreenX THEN + Obj(X).XDir = -Obj(X).XDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOX + END IF + END IF + Obj(X).Xpos = Obj(X).Xpos + Obj(X).XDir + +REDOY: + NewY = Obj(X).Ypos + Obj(X).YDir + IF NewY < 0 OR NewY + SpriteY > ScreenY THEN + Obj(X).YDir = -Obj(X).YDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOY + END IF + END IF + Obj(X).Ypos = Obj(X).Ypos + Obj(X).YDir + + 'Draw Sprite + + TDRAW.BITMAP Img(Obj(X).Shape), Obj(X).Xpos, Obj(X).Ypos, SpriteX, SpriteY + + LastX(X, CurrentPage) = Obj(X).Xpos + LastY(X, CurrentPage) = Obj(X).Ypos + + NEXT X + + LastObjects(CurrentPage) = VisObjects + + ' Pan Screen Back & Forth + + ViewCnt = ViewCnt + 1 + IF ViewCnt >= ViewMax THEN + ViewX = ViewX + ViewXD + IF ViewX = 0 OR ViewX = 39 THEN ViewXD = -ViewXD + IF ViewXD < 0 THEN + ViewY = ViewY + ViewYD + IF ViewY = 0 OR ViewY = 39 THEN ViewYD = -ViewYD + END IF + + SET.WINDOW CurrentPage, ViewX, ViewY + + ViewCnt = 0 + ELSE + SET.DISPLAY.PAGE CurrentPage + END IF + + ' Cycle Colors + + SET.DAC.REGISTER 50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 50 + SetColor, SetColor, 10, 63 - SetColor + + SET.DAC.REGISTER 150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 150 + SetColor, 63, 63, SetColor + + SetColor = SetColor + SDir + IF SetColor = 60 OR SetColor = 0 THEN SDir = -SDir + + PrevColor = PrevColor + PDir + IF PrevColor = 60 OR PrevColor = 0 THEN PDir = -PDir + + CurrentPage = 1 - CurrentPage + + Code = SCAN.KEYBOARD + + IF Code = False THEN GOTO DRAW.LOOP + + IF Code = KyPlus THEN + IF ViewMax < 12 THEN ViewMax = ViewMax + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyMinus THEN + IF ViewMax > 1 THEN ViewMax = ViewMax - 1 + IF ViewCnt >= ViewMax THEN ViewCnt = 0 + GOTO DRAW.LOOP + END IF + + IF Code = KyUp THEN + IF VisObjects < MaxSprites THEN VisObjects = VisObjects + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyDown THEN + IF VisObjects > 1 THEN VisObjects = VisObjects - 1 + GOTO DRAW.LOOP + END IF + + +END SUB + +SUB PRINT.TEXT (Text$, Xpos, Ypos, ColorF, ColorB) + + IF LEN(Text$) = 0 THEN EXIT SUB + + PRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF, ColorB + + +END SUB + +SUB TPRINT.TEXT (Text$, Xpos, Ypos, ColorF) + + IF LEN(Text$) = 0 THEN EXIT SUB + + TPRINT.STR SSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF + +END SUB + diff --git a/16/lib/modex105/DEMOS/BASIC7/UASM-BC7.BAT b/16/lib/modex105/DEMOS/BASIC7/UASM-BC7.BAT new file mode 100644 index 00000000..5ad67fb5 --- /dev/null +++ b/16/lib/modex105/DEMOS/BASIC7/UASM-BC7.BAT @@ -0,0 +1 @@ +MASM /DFARSTRINGS utils, utils, utils, nul; \ No newline at end of file diff --git a/16/lib/modex105/DEMOS/BASIC7/UTILS.ASM b/16/lib/modex105/DEMOS/BASIC7/UTILS.ASM new file mode 100644 index 00000000..811b8f8e --- /dev/null +++ b/16/lib/modex105/DEMOS/BASIC7/UTILS.ASM @@ -0,0 +1,406 @@ +;======================================================= +;=== UTILS.ASM - Asm Utilities for QuickBasic/BC7 === +;======================================================= + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ==== MACROS ==== + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + push R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + pop R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear a Register to 0 + +CLR MACRO Register + xor Register, Register ; Set Register = 0 +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + dec Register ; Counter-- + jnz Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + dec Register ; Counter-- + jz Destination ; Jump if 0 +ENDM + + + ; ==== General Constants ==== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + +IFDEF FARSTRINGS + + EXTRN stringaddress:far + EXTRN stringlength:far + +ENDIF + + + .Data + + EVEN + +RND_Seed DW 7397, 29447, 802 +RND_Mult DW 179, 183, 182 +RND_ModV DW 32771, 32779, 32783 + +CR_LF DB 13, 10 ; the CRLF data + + .Code + +;================= +;DOS_PRINT (Text$) +;================= +; +; Prints Text Directly to DOS console w/ CR/LF +; + + PUBLIC DOS_PRINT + +DP_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DP_Text DW ? ; Address of Text$ Descriptor +DP_Stack ENDS + + +DOS_PRINT PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @No_Print ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@No_Print: + mov AX, SEG DGROUP ; Restore DGroup + mov DS, AX + + mov DX, o CR_LF ; Get Addr of CR/LF pair + mov CX, 2 ; 2 Characters to Write + mov BX, 1 ; 1= DOS Handle for Display + + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINT ENDP + + +;================== +;DOS_PRINTS (Text$) +;================== +; +; Print Text$ Directly to DOS console +; without a trailing CR/LF +; + + PUBLIC DOS_PRINTS + +DOS_PRINTS PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @DPS_Exit ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@DPS_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINTS ENDP + + +;====================== +;SET_VIDEO_MODE (Mode%) +;====================== +; +; Sets the Video Mode through the BIOS +; + + PUBLIC SET_VIDEO_MODE + +SVM_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Mode DB ?,? ; Desired Video Mode +SVM_Stack ENDS + + +SET_VIDEO_MODE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR AH ; Function 0 + mov AL, [BP].SVM_Mode ; Get Mode # + + int 10H ; Change Video Modes + +@SVM_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +SET_VIDEO_MODE ENDP + + +;============== +;SCAN_KEYBOARD% +;============== +; +; Function to scan keyboard for a pressed key +; + + PUBLIC SCAN_KEYBOARD + +SCAN_KEYBOARD PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + + mov AH, 01H ; Function #1 + int 16H ; Call Keyboard Driver + jz @SK_NO_KEY ; Exit if Zero flag set + + mov AH, 00H ; Remove Key from Buffer + int 16H ; Get Keycode in AX + + or AL, AL ; Low Byte Set (Ascii?) + jz @SK_Exit ; if not, it's a F-Key + + CLR AH ; Clear ScanCode if Ascii + jmp s @SK_Exit ; Return Key in AX + +@SK_NO_KEY: + CLR AX ; Return Nil (no Keypress) + +@SK_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret ; Exit & Clean Up Stack + +SCAN_KEYBOARD ENDP + + +;==================== +;RANDOM_INT (MaxInt%) +;==================== +; +; Returns a pseudo-random number in the range of (0.. MaxInt-1) +; + + + PUBLIC RANDOM_INT + +RI_Stack STRUC + DW ? ; BP + DD ? ; Caller + RI_MaxVal DW ? ; Maximum Value to Return + 1 +RI_Stack ENDS + + +RANDOM_INT PROC FAR + + push BP ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR BX ; BX is the data index + CLR CX ; CX is the accumulator + +REPT 3 + mov AX, RND_Seed[BX] ; load the initial seed + mul RND_Mult[BX] ; multiply it + div RND_ModV[BX] ; and obtain the Mod value + mov RND_Seed[BX], DX ; save that for the next time + + add CX, DX ; add it into the accumulator + inc BX + inc BX ; point to the next set of values +ENDM + + mov AX, CX ; AX = Random # + CLR DX ; DX = 0 + div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder + + mov AX, DX + + pop BP ; Restore BP + ret 2 ; back to BASIC with AX holding the result + +RANDOM_INT ENDP + + +;=========== +;INIT_RANDOM +;=========== +; +; Scrambles the psuedo-random number sequence +; (XOR's the seed value with the timer) +; + + PUBLIC INIT_RANDOM + +INIT_RANDOM PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + + xor RND_Seed, AX ; Scramble 1st Seed + + ret ; Exit & Clean Up Stack + +INIT_RANDOM ENDP + + +;==================== +;INT_SQR (X%, Round%) +;==================== +; +; Returns the Integer Square Root of (X) +; Round allows the return value to be rounded to the +; nearest integer value by passing 0x80. Passing 0 +; return the Integer Portion only. The rounding amound is +; a number from 0 to 1 multiplied by 256, thus +; 0.5 * 0x100 = 0x80! +; + +ISQ_Stack STRUC + DW ?,? ; BP, DI + DD ? ; Caller + ISQ_Round DW ? ; Amount to Round Result * 256 + ISQ_X DW ? ; "X" +ISQ_Stack ENDS + + PUBLIC INT_SQR + +INT_SQR PROC FAR + + PUSHx BP, DI ; Save BP + mov BP, SP ; Set up Stack Frame + + xor AX, AX ; {xor eax,eax} + xor DX, DX ; {xor edx,edx} + mov DI, [BP].ISQ_X ; {mov edi,x} + + mov CX, 16 ; {mov cx, 32} + +@ISQ_L: + + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl AX, 1 ; {shl eax,1} + mov BX, AX ; {mov ebx,eax} + shl BX, 1 ; {shl ebx,1} + inc BX ; {inc ebx} + cmp DX, BX ; {cmp edx,ebx} + jl @ISQ_S + + sub DX, BX ; {sub edx,ebx} + inc AX ; {inc eax} + +@ISQ_S: + loop @ISQ_L + + add ax, [BP].ISQ_Round ; {add eax,$00008000} + ; {*round* result in hi word: ie. +0.5} + shr ax, 8 ; {shr eax,16} {to ax (result)} + + POPx DI, BP ; Restore Registers + ret 4 ; Exit + +INT_SQR ENDP + + +;============ +;TIMER_COUNT& +;============ +; +; Returns the current timer value as an integer/long integer +; + + + PUBLIC TIMER_COUNT + +TIMER_COUNT PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX ; use ES to get at data + mov AX, ES:[046Ch] ; Get Timer Lo Word + mov DX, ES:[046Eh] ; Get Timer Hi Word + ret ; Exit & Return value in DX:AX + +TIMER_COUNT ENDP + + + END diff --git a/16/lib/modex105/DEMOS/BASIC7/UTILS.BI b/16/lib/modex105/DEMOS/BASIC7/UTILS.BI new file mode 100644 index 00000000..aeafeef4 --- /dev/null +++ b/16/lib/modex105/DEMOS/BASIC7/UTILS.BI @@ -0,0 +1,51 @@ + + ' Misc Constants + +CONST True = -1, False = 0, nil = 0 + + ' Keyboard Codes: Extended + +CONST KyF1 = &H3B00, KyF2 = &H3C00, KyF3 = &H3D00, KyF4 = &H3E00, KyF5 = &H3F00 +CONST KyF6 = &H4000, KyF7 = &H4100, KyF8 = &H4200, KyF9 = &H4300, KyF10 = &H4400 + +CONST KyUp = &H4800, KyLeft = &H4B00, KyRight = &H4D00, KyDown = &H5000 +CONST KySLeft = &HCB00, KySRight = &HCD00, KySUp = &HC800, KySDown = &HD000 + +CONST KyHome = &H4700, KyPgUp = &H4900, KyEnd = &H4F00, KyPgDn = &H5100 +CONST KySHome = &HC700, KySPgUp = &HC900, KySEnd = &HCF00, KySPgDn = &HD100 + +CONST KyIns = &H5200, KyDel = &H5300, KyRvsTab = &H8F00 +CONST KySIns = &HC200, KySDel = &HC300 + +CONST KyAltA = &H1E00, KyAltB = &H3000, KyAltC = &H2E00, KyAltD = &H2000 +CONST KyAltE = &H1200, KyAltF = &H2100, KyAltG = &H2200, KyAltH = &H2300 +CONST KyAltI = &H1700, KyAltJ = &H2400, KyAltK = &H2500, KyAltL = &H2600 +CONST KyAltM = &H3200, KyAltN = &H3100, KyAltO = &H1800, KyAltP = &H1900 +CONST KyAltQ = &H1000, KyAltR = &H1300, KyAltS = &H1F00, KyAltT = &H1400 +CONST KyAltU = &H1600, KyAltV = &H2F00, KyAltW = &H1100, KyAltX = &H2D00 +CONST KyAltY = &H1500, KyAltZ = &H2C00 + + ' Keyboard Codes: Ascii + +CONST KyBS = 8, KyTab = 9, KyCR = 13, KyESC = &H1B, KyClr = &H7F +CONST KyPlus = 45, KyMinus = 43 + + ' Color Constants + +CONST c.BLACK = 0, c.BLUE = 1, c.GREEN = 2, c.CYAN = 3 +CONST c.RED = 4, c.PURPLE = 5, c.BROWN = 6, c.WHITE = 7 +CONST c.GREY = 8, c.bBLUE = 9, c.bGREEN = 10, c.bCYAN = 11 +CONST c.bRED = 12, c.bPURPLE = 13, c.YELLOW = 14, c.bWHITE = 15 +CONST c.BRIGHT = 8 + + ' From UTILS.ASM + +DECLARE SUB DOS.PRINT ALIAS "DOS_PRINT" (Text$) +DECLARE SUB DOS.PRINTS ALIAS "DOS_PRINTS" (Text$) +DECLARE SUB SET.VIDEO.MODE ALIAS "SET_VIDEO_MODE" (BYVAL Mode%) +DECLARE FUNCTION SCAN.KEYBOARD% ALIAS "SCAN_KEYBOARD" +DECLARE FUNCTION RANDOM.INT ALIAS "RANDOM_INT" (BYVAL MaxInt%) +DECLARE SUB INIT.RANDOM ALIAS "INIT_RANDOM" +DECLARE FUNCTION TIMER.COUNT& ALIAS "TIMER_COUNT" +DECLARE FUNCTION INT.SQR ALIAS "INT_SQR" (BYVAL X%, BYVAL Round%) + diff --git a/16/lib/modex105/DEMOS/BASIC7/UTILS.OBJ b/16/lib/modex105/DEMOS/BASIC7/UTILS.OBJ new file mode 100644 index 00000000..b251b64b Binary files /dev/null and b/16/lib/modex105/DEMOS/BASIC7/UTILS.OBJ differ diff --git a/16/lib/modex105/DEMOS/C/C_UTILS.ASM b/16/lib/modex105/DEMOS/C/C_UTILS.ASM new file mode 100644 index 00000000..8302561a --- /dev/null +++ b/16/lib/modex105/DEMOS/C/C_UTILS.ASM @@ -0,0 +1,405 @@ +;======================================================= +;=== C_UTILS.ASM - Asm Utilities for C/C++ === +;======================================================= + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ==== MACROS ==== + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + push R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + pop R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear a Register to 0 + +CLR MACRO Register + xor Register, Register ; Set Register = 0 +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + dec Register ; Counter-- + jnz Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + dec Register ; Counter-- + jz Destination ; Jump if 0 +ENDM + + + ; ==== General Constants ==== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + + .Data + + EVEN + +RND_Seed DW 7397, 29447, 802 +RND_Mult DW 179, 183, 182 +RND_ModV DW 32771, 32779, 32783 + +CR_LF DB 13, 10 ; the CRLF data + + .Code + +;=========================================== +;void far pascal dos_print (far char *Text) +;=========================================== +; +; - Print Text Directly to DOS console w/ CR/LF +; + + PUBLIC DOS_PRINT + +DP_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DP_Text DD ? ; Far Address of Text to print +DP_Stack ENDS + + +DOS_PRINT PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor + + ; Compute Length of string + + CLR CX ; Length = 0 + mov SI, DX ; DS:SI = String data + +@@DP_Scan_it: + + cmp b [SI], 0 ; Null Byte found? + je @@DP_Got_Len ; exit loop if so + + inc CX ; Len++ + inc SI ; Point to next char + jmp s @@DP_Scan_it ; check again... + +@@DP_Got_len: + + jcxz @No_Print ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@No_Print: + mov AX, SEG DGROUP ; Restore DGroup + mov DS, AX + + mov DX, o CR_LF ; Get Addr of CR/LF pair + mov CX, 2 ; 2 Characters to Write + mov BX, 1 ; 1= DOS Handle for Display + + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 4 ; Exit & Clean Up Stack + +DOS_PRINT ENDP + + +;=========================================== +;void far pascal dos_prints (char far *Text) +;=========================================== +; +; Print Text Directly to DOS console +; without a trailing CR/LF +; + + PUBLIC DOS_PRINTS + +DOS_PRINTS PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + lds DX, [BP].DP_Text ; Get Addr of Text$ descriptor + + ; Compute Length of string + + CLR CX ; Length = 0 + mov SI, DX ; DS:SI = String data + +@@DPS_Scan_it: + + cmp b [SI], 0 ; Null Byte found? + je @@DPS_Got_Len ; exit loop if so + + inc CX ; Len++ + inc SI ; Point to next char + jmp s @@DPS_Scan_it ; check again... + +@@DPS_Got_len: + + jcxz @DPS_Exit ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@DPS_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINTS ENDP + + +;========================================= +;void far pascal set_video_mode (int Mode) +;========================================= +; +; Sets the Video Mode through the BIOS +; + + PUBLIC SET_VIDEO_MODE + +SVM_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Mode DB ?,? ; Desired Video Mode +SVM_Stack ENDS + + +SET_VIDEO_MODE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR AH ; Function 0 + mov AL, [BP].SVM_Mode ; Get Mode # + + int 10H ; Change Video Modes + +@SVM_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +SET_VIDEO_MODE ENDP + + +;=================================== +;int far pascal scan_keyboard (void) +;=================================== +; +; Function to scan keyboard for a pressed key +; + + PUBLIC SCAN_KEYBOARD + +SCAN_KEYBOARD PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + + mov AH, 01H ; Function #1 + INT 16H ; Call Keyboard Driver + JZ @SK_NO_KEY ; Exit if Zero flag set + + mov AH, 00H ; Remove Key from Buffer + INT 16H ; Get Keycode in AX + + OR AL, AL ; Low Byte Set (Ascii?) + JZ @SK_Exit ; if not, it's a F-Key + + CLR AH ; Clear ScanCode if Ascii + JMP s @SK_Exit ; Return Key in AX + +@SK_NO_KEY: + CLR AX ; Return Nil (no Keypress) + +@SK_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret ; Exit & Clean Up Stack + +SCAN_KEYBOARD ENDP + + +;======================================== +;int far pascal random_int (int MaxValue) +;======================================== +; +; Returns a pseudo-random number in the range of (0.. MaxInt-1) +; + + + PUBLIC RANDOM_INT + +RI_Stack STRUC + DW ? ; BP + DD ? ; Caller + RI_MaxVal DW ? ; Maximum Value to Return + 1 +RI_Stack ENDS + + +RANDOM_INT PROC FAR + + push BP ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR BX ; BX is the data index + CLR CX ; CX is the accumulator + +REPT 3 + mov AX, RND_Seed[BX] ; load the initial seed + mul RND_Mult[BX] ; multiply it + div RND_ModV[BX] ; and obtain the Mod value + mov RND_Seed[BX], DX ; save that for the next time + + add CX, DX ; add it into the accumulator + inc BX + inc BX ; point to the next set of values +ENDM + + mov AX, CX ; AX = Random # + CLR DX ; DX = 0 + div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder + + mov AX, DX + + pop BP ; Restore BP + ret 2 ; back to BASIC with AX holding the result + +RANDOM_INT ENDP + + +;================================== +;void far pascal init_random (void) +;================================== +; +; Scrambles the psuedo-random number sequence +; (XOR's the seed value with the timer) +; + + PUBLIC INIT_RANDOM + +INIT_RANDOM PROC FAR + + CLR AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + + xor RND_Seed, AX ; Scramble 1st Seed + + ret ; Exit & Clean Up Stack + +INIT_RANDOM ENDP + +;========================================= +;int far pascal int_sqr (int X, int Round) +;========================================= +; +; Returns the Integer Square Root of (X) +; Round allows the return value to be rounded to the +; nearest integer value by passing 0x80. Passing 0 +; return the Integer Portion only. The rounding amound is +; a number from 0 to 1 multiplied by 256, thus +; 0.5 * 0x100 = 0x80! +; + +ISQ_Stack STRUC + DW ?,? ; BP, DI + DD ? ; Caller + ISQ_Round DW ? ; Amount to Round Result * 256 + ISQ_X DW ? ; "X" +ISQ_Stack ENDS + + PUBLIC INT_SQR + +INT_SQR PROC FAR + + PUSHx BP, DI ; Save BP + mov BP, SP ; Set up Stack Frame + + xor AX, AX ; {xor eax,eax} + xor DX, DX ; {xor edx,edx} + mov DI, [BP].ISQ_X ; {mov edi,x} + + mov CX, 16 ; {mov cx, 32} + +@ISQ_L: + + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl AX, 1 ; {shl eax,1} + mov BX, AX ; {mov ebx,eax} + shl BX, 1 ; {shl ebx,1} + inc BX ; {inc ebx} + cmp DX, BX ; {cmp edx,ebx} + jl @ISQ_S + + sub DX, BX ; {sub edx,ebx} + inc AX ; {inc eax} + +@ISQ_S: + loop @ISQ_L + + add ax, [BP].ISQ_Round ; {add eax,$00008000} + ; {*round* result in hi word: ie. +0.5} + shr ax, 8 ; {shr eax,16} {to ax (result)} + + POPx DI, BP ; Restore Registers + ret 4 ; Exit + +INT_SQR ENDP + +;================================= +;int far pascal timer_count (void) +;================================= +; +; Returns the current timer value as an integer/long integer +; + + PUBLIC TIMER_COUNT + +TIMER_COUNT PROC FAR + + CLR AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + mov DX, ES:[046Eh] ; Get Timer Hi Word + ret ; Exit & Clean Up Stack + +TIMER_COUNT ENDP + + + END diff --git a/16/lib/modex105/DEMOS/C/C_UTILS.H b/16/lib/modex105/DEMOS/C/C_UTILS.H new file mode 100644 index 00000000..ed0e188f --- /dev/null +++ b/16/lib/modex105/DEMOS/C/C_UTILS.H @@ -0,0 +1,117 @@ + +#ifndef __C_UTILS_H +#define __C_UTILS_H + + + /* Misc Constants */ + +#define True -1 +#define False 0 +#define nil 0 + + /* Color Constants */ + +#define c_BLACK 0 +#define c_BLUE 1 +#define c_GREEN 2 +#define c_CYAN 3 +#define c_RED 4 +#define c_PURPLE 5 +#define c_BROWN 6 +#define c_WHITE 7 +#define c_GREY 8 +#define c_bBLUE 9 +#define c_bGREEN 10 +#define c_bCYAN 11 +#define c_bRED 12 +#define c_bPURPLE 13 +#define c_YELLOW 14 +#define c_bWHITE 15 +#define c_BRIGHT 16 + + +#define Ky_F1 0x3B00 +#define Ky_F2 0x3C00 +#define Ky_F3 0x3D00 +#define Ky_F4 0x3E00 +#define Ky_F5 0x3F00 +#define Ky_F6 0x4000 +#define Ky_F7 0x4100 +#define Ky_F8 0x4200 +#define Ky_F9 0x4300 +#define Ky_F10 0x4400 + +#define Ky_Up 0x4800 +#define Ky_Left 0x4B00 +#define Ky_Right 0x4D00 +#define Ky_Down 0x5000 +#define Ky_SUp 0xC800 +#define Ky_SLeft 0xCB00 +#define Ky_SRight 0xCD00 +#define Ky_SDown 0xD000 + +#define Ky_Home 0x4700 +#define Ky_End 0x4F00 +#define Ky_PgUp 0x4900 +#define Ky_PgDn 0x5100 +#define Ky_SHome 0xC700 +#define Ky_SEnd 0xCF00 +#define Ky_SPgUp 0xC900 +#define Ky_SPgDn 0xD100 + +#define Ky_Ins 0x5200 +#define Ky_Del 0x5300 +#define Ky_SIns 0xC200 +#define Ky_SDel 0xC300 + +#define Ky_Tab 0x0009 +#define Ky_RvsTab 0x8F00 +#define Ky_STab 0x8F00 + +#define Ky_BS 0x0008 +#define Ky_CR 0x000D +#define Ky_ESC 0x001B +#define Ky_Clr 0x007F + +#define Ky_Plus 0x002D +#define Ky_Minus 0x002B + +#define Ky_AltA 0x1E00 +#define Ky_AltB 0x3000 +#define Ky_AltC 0x2E00 +#define Ky_AltD 0x2000 +#define Ky_AltE 0x1200 +#define Ky_AltF 0x2100 +#define Ky_AltG 0x2200 +#define Ky_AltH 0x2300 +#define Ky_AltI 0x1700 +#define Ky_AltJ 0x2400 +#define Ky_AltK 0x2500 +#define Ky_AltL 0x2600 +#define Ky_AltM 0x3200 +#define Ky_AltN 0x3100 +#define Ky_AltO 0x1800 +#define Ky_AltP 0x1900 +#define Ky_AltQ 0x1000 +#define Ky_AltR 0x1300 +#define Ky_AltS 0x1F00 +#define Ky_AltT 0x1400 +#define Ky_AltU 0x1600 +#define Ky_AltV 0x2F00 +#define Ky_AltW 0x1100 +#define Ky_AltX 0x2D00 +#define Ky_AltY 0x1500 +#define Ky_AltZ 0x2C00 + + /* .ASM Functions From C_UTILS.ASM */ + +void far pascal dos_print (char far *Text); +void far pascal dos_prints (char far *Text); +void far pascal set_video_mode (int Mode); +int far pascal scan_keyboard (void); +int far pascal random_int (int MaxValue); +void far pascal init_random (void); +int far pascal int_sqr (int X, int Round); +int far pascal timer_count (void); + +#endif \ No newline at end of file diff --git a/16/lib/modex105/DEMOS/C/C_UTILS.OBJ b/16/lib/modex105/DEMOS/C/C_UTILS.OBJ new file mode 100644 index 00000000..075a2da1 Binary files /dev/null and b/16/lib/modex105/DEMOS/C/C_UTILS.OBJ differ diff --git a/16/lib/modex105/DEMOS/C/MODEX.ASM b/16/lib/modex105/DEMOS/C/MODEX.ASM new file mode 100644 index 00000000..2985fd80 --- /dev/null +++ b/16/lib/modex105/DEMOS/C/MODEX.ASM @@ -0,0 +1,3295 @@ +;======================================================== +; MODEX.ASM - A Complete Mode X Library +; +; Version 1.04 Release, 3 May 1993, By Matt Pritchard +; With considerable input from Michael Abrash +; +; The following information is donated to the public domain in +; the hopes that save other programmers much frustration. +; +; If you do use this code in a product, it would be nice if +; you include a line like "Mode X routines by Matt Pritchard" +; in the credits. +; +; ========================================================= +; +; All of this code is designed to be assembled with MASM 5.10a +; but TASM 3.0 could be used as well. +; +; The routines contained are designed for use in a MEDIUM model +; program. All Routines are FAR, and is assumed that a DGROUP +; data segment exists and that DS will point to it on entry. +; +; For all routines, the AX, BX, CX, DX, ES and FLAGS registers +; will not be preserved, while the DS, BP, SI and DI registers +; will be preserved. +; +; Unless specifically noted, All Parameters are assumed to be +; "PASSED BY VALUE". That is, the actual value is placed on +; the stack. When a reference is passed it is assumed to be +; a near pointer to a variable in the DGROUP segment. +; +; Routines that return a single 16-Bit integer value will +; return that value in the AX register. +; +; This code will *NOT* run on an 8086/8088 because 80286+ +; specific instructions are used. If you have an 8088/86 +; and VGA, you can buy an 80386-40 motherboard for about +; $160 and move into the 90's. +; +; This code is reasonably optimized: Most drawing loops have +; been unrolled once and memory references are minimized by +; keeping stuff in registers when possible. +; +; Error Trapping varies by Routine. No Clipping is performed +; so the caller should verify that all coordinates are valid. +; +; Several Macros are used to simplify common 2 or 3 instruction +; sequences. Several Single letter Text Constants also +; simplify common assembler expressions like "WORD PTR". +; +; ------------------ Mode X Variations ------------------ +; +; Mode # Screen Size Max Pages Aspect Ratio (X:Y) +; +; 0 320 x 200 4 Pages 1.2:1 +; 1 320 x 400 2 Pages 2.4:1 +; 2 360 x 200 3 Pages 1.35:1 +; 3 360 x 400 1 Page 2.7:1 +; 4 320 x 240 3 Pages 1:1 +; 5 320 x 480 1 Page 2:1 +; 6 360 x 240 3 Pages 1.125:1 +; 7 360 x 480 1 Page 2.25:1 +; +; -------------------- The Legal Stuff ------------------ +; +; No warranty, either written or implied, is made as to +; the accuracy and usability of this code product. Use +; at your own risk. Batteries not included. Pepperoni +; and extra cheese available for an additional charge. +; +; ----------------------- The Author -------------------- +; +; Matt Pritchard is a paid programmer who'd rather be +; writing games. He can be reached at: P.O. Box 140264, +; Irving, TX 75014 USA. Michael Abrash is a living +; god, who now works for Bill Gates (Microsoft). +; +; -------------------- Revision History ----------------- +; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI +; SET_MODEX now saves SI +; 5-3-93: v1.04 - added LOAD_DAC_REGISTERS and +; READ_DAC_REGISTERS. Expanded CLR Macro +; to handle multiple registers +; + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ===== MACROS ===== + + ; Macro to OUT a 16 bit value to an I/O port + +OUT_16 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AX not setup + MOV AX, Value ; then Get Data Value + ENDIF + OUT DX, AX ; Set I/O Register(s) +ENDM + + ; Macro to OUT a 8 bit value to an I/O Port + +OUT_8 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AL not Setup + MOV AL, Value ; then Get Data Value + ENDIF + OUT DX, AL ; Set I/O Register +ENDM + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + PUSH R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + POP R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear Registers to 0 + +CLR MACRO Register, R2, R3, R4, R5, R6 + IFNB + XOR Register, Register ; Set Register = 0 + CLR R2, R3, R4, R5, R6 + ENDIF +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + DEC Register ; Counter-- + JNZ Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + DEC Register ; Counter-- + JZ Destination ; Jump if 0 +ENDM + + + ; ===== General Constants ===== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + ; ===== VGA Register Values ===== + + VGA_Segment EQU 0A000h ; Vga Memory Segment + + ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller + GC_Index EQU 03CEh ; VGA Graphics Controller + SC_Index EQU 03C4h ; VGA Sequencer Controller + SC_Data EQU 03C5h ; VGA Sequencer Data Port + CRTC_Index EQU 03D4h ; VGA CRT Controller + CRTC_Data EQU 03D5h ; VGA CRT Controller Data + MISC_OUTPUT EQU 03C2h ; VGA Misc Register + INPUT_1 EQU 03DAh ; Input Status #1 Register + + DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register + DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register + PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W + + PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg + MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg + READ_MAP EQU 004h ; GC Index: Read Map Register + START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi + START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo + + MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1 + MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1 + ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes + + CHAIN4_OFF EQU 00604h ; Chain 4 mode Off + ASYNC_RESET EQU 00100h ; (A)synchronous Reset + SEQU_RESTART EQU 00300h ; Sequencer Restart + + LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches + LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU + + VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit + PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane # + ALL_PLANES EQU 0Fh ; All Bit Planes Selected + CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data + + GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set + ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer + ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer + + ; Constants Specific for these routines + + NUM_MODES EQU 8 ; # of Mode X Variations + + ; Specific Mode Data Table format... + +Mode_Data_Table STRUC + M_MiscR DB ? ; Value of MISC_OUTPUT register + M_Pages DB ? ; Maximum Possible # of pages + M_XSize DW ? ; X Size Displayed on screen + M_YSize DW ? ; Y Size Displayed on screen + M_XMax DW ? ; Maximum Possible X Size + M_YMax DW ? ; Maximum Possible Y Size + M_CRTC DW ? ; Table of CRTC register values +Mode_Data_Table ENDS + + ; ===== DGROUP STORAGE NEEDED (42 BYTES) ===== + + .DATA? + +SCREEN_WIDTH DW 0 ; Width of a line in Bytes +SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels + +LAST_PAGE DW 0 ; # of Display Pages +PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page + +PAGE_SIZE DW 0 ; Size of Page in Addr Bytes + +DISPLAY_PAGE DW 0 ; Page # currently displayed +ACTIVE_PAGE DW 0 ; Page # currently active + +CURRENT_PAGE DW 0 ; Offset of current Page +CURRENT_SEGMENT DW 0 ; Segment of VGA memory + +CURRENT_XOFFSET DW 0 ; Current Display X Offset +CURRENT_YOFFSET DW 0 ; Current Display Y Offset + +CURRENT_MOFFSET DW 0 ; Current Start Offset + +MAX_XOFFSET DW 0 ; Current Display X Offset +MAX_YOFFSET DW 0 ; Current Display Y Offset + +CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127 +CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255 + + .CODE + + ; ===== DATA TABLES ===== + + ; Data Tables, Put in Code Segment for Easy Access + ; (Like when all the other Segment Registers are in + ; use!!) and reduced DGROUP requirements... + + ; Bit Mask Tables for Left/Right/Character Masks + +Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H + +Right_Clip_Mask DB 01H, 03H, 07H, 0FH + + ; Bit Patterns for converting character fonts + +Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH + DB 01H,09H,05H,0DH,03H,0BH,07H,0FH + + ; CRTC Register Values for Various Configurations + +MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes + DW 04009H ; Cell Height (1 Scan Line) + DW 00014H ; Dword Mode off + DW 0E317H ; turn on Byte Mode + DW nil ; End of CRTC Data for 400/480 Line Mode + +MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes + DW 04109H ; Cell Height (2 Scan Lines) + DW 00014H ; Dword Mode off + DW 0E317H ; turn on Byte Mode + DW nil ; End of CRTC Data for 200/240 Line Mode + +MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels + DW 05F00H ; Horz total + DW 04F01H ; Horz Displayed + DW 05002H ; Start Horz Blanking + DW 08203H ; End Horz Blanking + DW 05404H ; Start H Sync + DW 08005H ; End H Sync + DW nil ; End of CRTC Data for 320 Horz pixels + +MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels + DW 06B00H ; Horz total + DW 05901H ; Horz Displayed + DW 05A02H ; Start Horz Blanking + DW 08E03H ; End Horz Blanking + DW 05E04H ; Start H Sync + DW 08A05H ; End H Sync + DW nil ; End of CRTC Data for 360 Horz pixels + +MODE_200_Tall: +MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes + DW 0BF06H ; Vertical Total + DW 01F07H ; Overflow + DW 09C10H ; V Sync Start + DW 08E11H ; V Sync End/Prot Cr0 Cr7 + DW 08F12H ; Vertical Displayed + DW 09615H ; V Blank Start + DW 0B916H ; V Blank End + DW nil ; End of CRTC Data for 200/400 Lines + +MODE_240_Tall: +MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes + DW 00D06H ; Vertical Total + DW 03E07H ; Overflow + DW 0EA10H ; V Sync Start + DW 08C11H ; V Sync End/Prot Cr0 Cr7 + DW 0DF12H ; Vertical Displayed + DW 0E715H ; V Blank Start + DW 00616H ; V Blank End + DW nil ; End of CRTC Data for 240/480 Lines + + ; Table of Display Mode Tables + +MODE_TABLE: + DW o MODE_320x200, o MODE_320x400 + DW o MODE_360x200, o MODE_360x400 + DW o MODE_320x240, o MODE_320x480 + DW o MODE_360x240, o MODE_360x480 + + ; Table of Display Mode Components + +MODE_320x200: ; Data for 320 by 200 Pixels + + DB 063h ; 400 scan Lines & 25 Mhz Clock + DB 4 ; Maximum of 4 Pages + DW 320, 200 ; Displayed Pixels (X,Y) + DW 1302, 816 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_200_Tall + DW o MODE_Double_Line, nil + +MODE_320x400: ; Data for 320 by 400 Pixels + + DB 063h ; 400 scan Lines & 25 Mhz Clock + DB 2 ; Maximum of 2 Pages + DW 320, 400 ; Displayed Pixels X,Y + DW 648, 816 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_400_Tall + DW o MODE_Single_Line, nil + +MODE_360x240: ; Data for 360 by 240 Pixels + + DB 0E7h ; 480 scan Lines & 28 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 360, 240 ; Displayed Pixels X,Y + DW 1092, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, o MODE_240_Tall + DW o MODE_Double_Line , nil + +MODE_360x480: ; Data for 360 by 480 Pixels + + DB 0E7h ; 480 scan Lines & 28 Mhz Clock + DB 1 ; Only 1 Page Possible + DW 360, 480 ; Displayed Pixels X,Y + DW 544, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, o MODE_480_Tall + DW o MODE_Single_Line , nil + +MODE_320x240: ; Data for 320 by 240 Pixels + + DB 0E3h ; 480 scan Lines & 25 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 320, 240 ; Displayed Pixels X,Y + DW 1088, 818 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_240_Tall + DW o MODE_Double_Line, nil + +MODE_320x480: ; Data for 320 by 480 Pixels + + DB 0E3h ; 480 scan Lines & 25 Mhz Clock + DB 1 ; Only 1 Page Possible + DW 320, 480 ; Displayed Pixels X,Y + DW 540, 818 ; Max Possible X and Y Sizes + + DW o MODE_320_WIDE, o MODE_480_Tall + DW o MODE_Single_Line, nil + +MODE_360x200: ; Data for 360 by 200 Pixels + + DB 067h ; 400 scan Lines & 28 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 360, 200 ; Displayed Pixels (X,Y) + DW 1302, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, MODE_200_Tall + DW o MODE_Double_Line, nil + +MODE_360x400: ; Data for 360 by 400 Pixels + + DB 067h ; 400 scan Lines & 28 Mhz Clock + DB 1 ; Maximum of 1 Pages + DW 360, 400 ; Displayed Pixels X,Y + DW 648, 816 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, MODE_400_Tall + DW o MODE_Single_Line, nil + + + ; ===== MODE X SETUP ROUTINES ===== + +;====================================================== +;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%) +;====================================================== +; +; Sets Up the specified version of Mode X. Allows for +; the setup of multiple video pages, and a virtual +; screen which can be larger than the displayed screen +; (which can then be scrolled a pixel at a time) +; +; ENTRY: ModeType = Desired Screen Resolution (0-7) +; +; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio +; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio +; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio +; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio +; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio +; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio +; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio +; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio +; +; MaxXpos = The Desired Virtual Screen Width +; MaxYpos = The Desired Virtual Screen Height +; Pages = The Desired # of Video Pages +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +SVM_STACK STRUC + SVM_Table DW ? ; Offset of Mode Info Table + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Pages DW ? ; # of Screen Pages desired + SVM_Ysize DW ? ; Vertical Screen Size Desired + SVM_Xsize DW ? ; Horizontal Screen Size Desired + SVM_Mode DW ? ; Display Resolution Desired +SVM_STACK ENDS + + PUBLIC SET_VGA_MODEX + +SET_VGA_MODEX PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 2 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + ; Check Legality of Mode Request.... + + MOV BX, [BP].SVM_Mode ; Get Requested Mode # + CMP BX, NUM_MODES ; Is it 0..7? + JAE @SVM_BadModeSetup ; If Not, Error out + + SHL BX, 1 ; Scale BX + MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + MOV [BP].SVM_Table, SI ; Save ptr for later use + + ; Check # of Requested Display Pages + + MOV CX, [BP].SVM_Pages ; Get # of Requested Pages + CLR CH ; Set Hi Word = 0! + CMP CL, CS:[SI].M_Pages ; Check # Pages for mode + JA @SVM_BadModeSetup ; Report Error if too Many Pages + JCXZ @SVM_BadModeSetup ; Report Error if 0 Pages + + ; Check Validity of X Size + + AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0 + + MOV AX, [BP].SVM_XSize ; Get Logical Screen Width + CMP AX, CS:[SI].M_XSize ; Check against Displayed X + JB @SVM_BadModeSetup ; Report Error if too small + CMP AX, CS:[SI].M_XMax ; Check against Max X + JA @SVM_BadModeSetup ; Report Error if too big + + ; Check Validity of Y Size + + MOV BX, [BP].SVM_YSize ; Get Logical Screen Height + CMP BX, CS:[SI].M_YSize ; Check against Displayed Y + JB @SVM_BadModeSetup ; Report Error if too small + CMP BX, CS:[SI].M_YMax ; Check against Max Y + JA @SVM_BadModeSetup ; Report Error if too big + + ; Enough memory to Fit it all? + + SHR AX, 2 ; # of Bytes:Line = XSize/4 + MUL CX ; AX = Bytes/Line * Pages + MUL BX ; DX:AX = Total VGA mem needed + JNO @SVM_Continue ; Exit if Total Size > 256K + + DEC DX ; Was it Exactly 256K??? + OR DX, AX ; (DX = 1, AX = 0000) + JZ @SVM_Continue ; if so, it's valid... + +@SVM_BadModeSetup: + + CLR AX ; Return Value = False + JMP @SVM_Exit ; Normal Exit + +@SVM_Continue: + + MOV AX, 13H ; Start with Mode 13H + INT 10H ; Let BIOS Set Mode + + OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode + OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset + OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size + OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ... + + OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register + INC DX ; Point to Data + IN AL, DX ; Get Value, Bit 7 = Protect + AND AL, 7FH ; Mask out Write Protect + OUT DX, AL ; And send it back + + MOV DX, CRTC_INDEX ; Vga Crtc Registers + ADD SI, M_CRTC ; SI -> CRTC Parameter Data + + ; Load Tables of CRTC Parameters from List of Tables + +@SVM_Setup_Table: + + MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl + ADD SI, 2 ; Point to next Ptr Entry + OR DI, DI ; A nil Ptr means that we have + JZ @SVM_Set_Data ; finished CRTC programming + +@SVM_Setup_CRTC: + MOV AX, CS:[DI] ; Get CRTC Data from Table + ADD DI, 2 ; Advance Pointer + OR AX, AX ; At End of Data Table? + JZ @SVM_Setup_Table ; If so, Exit & get next Table + + OUT DX, AX ; Reprogram VGA CRTC reg + JMP s @SVM_Setup_CRTC ; Process Next Table Entry + + ; Initialize Page & Scroll info, DI = 0 + +@SVM_Set_Data: + MOV DISPLAY_PAGE, DI ; Display Page = 0 + MOV ACTIVE_PAGE, DI ; Active Page = 0 + MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0 + MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0 + MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0 + MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0 + + MOV AX, VGA_SEGMENT ; Segment for VGA memory + MOV CURRENT_SEGMENT, AX ; Save for Future LES's + + ; Set Logical Screen Width, X Scroll and Our Data + + MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info + MOV AX, [BP].SVM_Xsize ; Get Display Width + + MOV CX, AX ; CX = Logical Width + SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value + MOV MAX_XOFFSET, CX ; Set Maximum X Scroll + + SHR AX, 2 ; Bytes = Pixels / 4 + MOV SCREEN_WIDTH, AX ; Save Width in Pixels + + SHR AX, 1 ; Offset Value = Bytes / 2 + MOV AH, 13h ; CRTC Offset Register Index + XCHG AL, AH ; Switch format for OUT + OUT DX, AX ; Set VGA CRTC Offset Reg + + ; Setup Data table, Y Scroll, Misc for Other Routines + + MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height + + MOV CX, AX ; CX = Logical Height + SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value + MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll + + MOV SCREEN_HEIGHT, AX ; Save Height in Pixels + MUL SCREEN_WIDTH ; AX = Page Size in Bytes, + MOV PAGE_SIZE, AX ; Save Page Size + + MOV CX, [BP].SVM_Pages ; Get # of Pages + MOV LAST_PAGE, CX ; Save # of Pages + + CLR BX ; Page # = 0 + MOV DX, BX ; Page 0 Offset = 0 + +@SVM_Set_Pages: + + MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset + ADD BX, 2 ; Page#++ + ADD DX, AX ; Compute Addr of Next Page + LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set + + ; Clear VGA Memory + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + LES DI, d CURRENT_PAGE ; -> Start of VGA memory + + CLR AX ; AX = 0 + CLD ; Block Xfer Forwards + MOV CX, 8000H ; 32K * 4 * 2 = 256K + REP STOSW ; Clear dat memory! + + ; Setup Font Pointers + + MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127 + MOV AX, GET_CHAR_PTR ; Service to Get Pointer + INT 10h ; Call VGA BIOS + + MOV CHARSET_LOW, BP ; Save Char Set Offset + MOV CHARSET_LOW+2, ES ; Save Char Set Segment + + MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255 + MOV AX, GET_CHAR_PTR ; Service to Get Pointer + INT 10h ; Call VGA BIOS + + MOV CHARSET_HI, BP ; Save Char Set Offset + MOV CHARSET_HI+2, ES ; Save Char Set Segment + + MOV AX, True ; Return Success Code + +@SVM_EXIT: + ADD SP, 2 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 8 ; Exit & Clean Up Stack + +SET_VGA_MODEX ENDP + + +;================== +;SET_MODEX% (Mode%) +;================== +; +; Quickie Mode Set - Sets Up Mode X to Default Configuration +; +; ENTRY: ModeType = Desired Screen Resolution (0-7) +; (See SET_VGA_MODEX for list) +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +SM_STACK STRUC + DW ?,? ; BP, SI + DD ? ; Caller + SM_Mode DW ? ; Desired Screen Resolution +SM_STACK ENDS + + PUBLIC SET_MODEX + +SET_MODEX PROC FAR + + PUSHx BP, SI ; Preserve Important registers + MOV BP, SP ; Set up Stack Frame + + CLR AX ; Assume Failure + MOV BX, [BP].SM_Mode ; Get Desired Mode # + CMP BX, NUM_MODES ; Is it a Valid Mode #? + JAE @SMX_Exit ; If Not, don't Bother + + PUSH BX ; Push Mode Parameter + + SHL BX, 1 ; Scale BX to word Index + MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + + PUSH CS:[SI].M_XSize ; Push Default X Size + PUSH CS:[SI].M_Ysize ; Push Default Y size + MOV AL, CS:[SI].M_Pages ; Get Default # of Pages + CLR AH ; Hi Byte = 0 + PUSH AX ; Push # Pages + + CALL f SET_VGA_MODEX ; Set up Mode X! + +@SMX_Exit: + POPx SI, BP ; Restore Registers + RET 2 ; Exit & Clean Up Stack + +SET_MODEX ENDP + + + ; ===== BASIC GRAPHICS PRIMITIVES ===== + +;============================ +;CLEAR_VGA_SCREEN (ColorNum%) +;============================ +; +; Clears the active display page +; +; ENTRY: ColorNum = Color Value to fill the page with +; +; EXIT: No meaningful values returned +; + +CVS_STACK STRUC + DW ?,? ; DI, BP + DD ? ; Caller + CVS_COLOR DB ?,? ; Color to Set Screen to +CVS_STACK ENDS + + PUBLIC CLEAR_VGA_SCREEN + +CLEAR_VGA_SCREEN PROC FAR + + PUSHx BP, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AL, [BP].CVS_COLOR ; Get Color + MOV AH, AL ; Copy for Word Write + CLD ; Block fill Forwards + + MOV CX, PAGE_SIZE ; Get Size of Page + SHR CX, 1 ; Divide by 2 for Words + REP STOSW ; Block Fill VGA memory + + POPx DI, BP ; Restore Saved Registers + RET 2 ; Exit & Clean Up Stack + +CLEAR_VGA_SCREEN ENDP + + +;=================================== +;SET_POINT (Xpos%, Ypos%, ColorNum%) +;=================================== +; +; Plots a single Pixel on the active display page +; +; ENTRY: Xpos = X position to plot pixel at +; Ypos = Y position to plot pixel at +; ColorNum = Color to plot pixel with +; +; EXIT: No meaningful values returned +; + +SP_STACK STRUC + DW ?,? ; BP, DI + DD ? ; Caller + SETP_Color DB ?,? ; Color of Point to Plot + SETP_Ypos DW ? ; Y pos of Point to Plot + SETP_Xpos DW ? ; X pos of Point to Plot +SP_STACK ENDS + + PUBLIC SET_POINT + +SET_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel + MUL SCREEN_WIDTH ; Get Offset to Start of Line + + MOV BX, [BP].SETP_Xpos ; Get Xpos + MOV CX, BX ; Copy to extract Plane # from + SHR BX, 2 ; X offset (Bytes) = Xpos/4 + ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register + AND CL, PLANE_BITS ; Get Plane Bits + SHL AH, CL ; Get Plane Select Value + OUT_16 SC_Index, AX ; Select Plane + + MOV AL,[BP].SETP_Color ; Get Pixel Color + MOV ES:[DI+BX], AL ; Draw Pixel + + POPx DI, BP ; Restore Saved Registers + RET 6 ; Exit and Clean up Stack + +SET_POINT ENDP + + +;========================== +;READ_POINT% (Xpos%, Ypos%) +;========================== +; +; Read the color of a pixel from the Active Display Page +; +; ENTRY: Xpos = X position of pixel to read +; Ypos = Y position of pixel to read +; +; EXIT: AX = Color of Pixel at (Xpos, Ypos) +; + +RP_STACK STRUC + DW ?,? ; BP, DI + DD ? ; Caller + RP_Ypos DW ? ; Y pos of Point to Read + RP_Xpos DW ? ; X pos of Point to Read +RP_STACK ENDS + + PUBLIC READ_POINT + +READ_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].RP_Ypos ; Get Line # of Pixel + MUL SCREEN_WIDTH ; Get Offset to Start of Line + + MOV BX, [BP].RP_Xpos ; Get Xpos + MOV CX, BX + SHR BX, 2 ; X offset (Bytes) = Xpos/4 + ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + MOV AL, READ_MAP ; GC Read Mask Register + MOV AH, CL ; Get Xpos + AND AH, PLANE_BITS ; & mask out Plane # + OUT_16 GC_INDEX, AX ; Select Plane to read in + + CLR AH ; Clear Return Value Hi byte + MOV AL, ES:[DI+BX] ; Get Color of Pixel + + POPx DI, BP ; Restore Saved Registers + RET 4 ; Exit and Clean up Stack + +READ_POINT ENDP + + +;====================================================== +;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) +;====================================================== +; +; Fills a rectangular block on the active display Page +; +; ENTRY: Xpos1 = Left X position of area to fill +; Ypos1 = Top Y position of area to fill +; Xpos2 = Right X position of area to fill +; Ypos2 = Bottom Y position of area to fill +; ColorNum = Color to fill area with +; +; EXIT: No meaningful values returned +; + +FB_STACK STRUC + DW ?x4 ; DS, DI, SI, BP + DD ? ; Caller + FB_Color DB ?,? ; Fill Color + FB_Ypos2 DW ? ; Y pos of Lower Right Pixel + FB_Xpos2 DW ? ; X pos of Lower Right Pixel + FB_Ypos1 DW ? ; Y pos of Upper Left Pixel + FB_Xpos1 DW ? ; X pos of Upper Left Pixel +FB_STACK ENDS + + PUBLIC FILL_BLOCK + +FILL_BLOCK PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + + ; Validate Pixel Coordinates + ; If necessary, Swap so X1 <= X2, Y1 <= Y2 + + MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2? + MOV BX, [BP].FB_Ypos2 ; BX = Y2 + CMP AX, BX + JLE @FB_NOSWAP1 + + MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1 + XCHG AX, BX ; on stack for future use + +@FB_NOSWAP1: + SUB BX, AX ; Get Y width + INC BX ; Add 1 to avoid 0 value + MOV [BP].FB_Ypos2, BX ; Save in Ypos2 + + MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line + ADD DI, AX ; DI = Start of Line Y1 + + MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2 + MOV BX, [BP].FB_Xpos2 ; + CMP AX, BX + JLE @FB_NOSWAP2 ; Skip Ahead if Ok + + MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2 + XCHG AX, BX ; on stack for future use + + ; All our Input Values are in order, Now determine + ; How many full "bands" 4 pixels wide (aligned) there + ; are, and if there are partial bands (<4 pixels) on + ; the left and right edges. + +@FB_NOSWAP2: + MOV DX, AX ; DX = X1 (Pixel Position) + SHR DX, 2 ; DX/4 = Bytes into Line + ADD DI, DX ; DI = Addr of Upper-Left Corner + + MOV CX, BX ; CX = X2 (Pixel Position) + SHR CX, 2 ; CX/4 = Bytes into Line + + CMP DX, CX ; Start and end in same band? + JNE @FB_NORMAL ; if not, check for l & r edges + JMP @FB_ONE_BAND_ONLY ; if so, then special processing + +@FB_NORMAL: + SUB CX, DX ; CX = # bands -1 + MOV SI, AX ; SI = PLANE#(X1) + AND SI, PLANE_BITS ; if Left edge is aligned then + JZ @FB_L_PLANE_FLUSH ; no special processing.. + + ; Draw "Left Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask + + MOV SI, DI ; SI = Copy of Start Addr (UL) + + MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_LEFT_LOOP: + MOV ES:[SI], AL ; Fill in Left Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn + + MOV ES:[SI], AL ; Fill in Left Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn + +@FB_LEFT_CONT: + + INC DI ; Point to Middle (or Right) Block + DEC CX ; Reset CX instead of JMP @FB_RIGHT + +@FB_L_PLANE_FLUSH: + INC CX ; Add in Left band to middle block + + ; DI = Addr of 1st middle Pixel (band) to fill + ; CX = # of Bands to fill -1 + +@FB_RIGHT: + MOV SI, [BP].FB_Xpos2 ; Get Xpos2 + AND SI, PLANE_BITS ; Get Plane values + CMP SI, 0003 ; Plane = 3? + JE @FB_R_EDGE_FLUSH ; Hey, add to middle + + ; Draw "Right Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask + + MOV SI, DI ; Get Addr of Left Edge + ADD SI, CX ; Add Width-1 (Bands) + DEC SI ; To point to top of Right Edge + + MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_RIGHT_LOOP: + MOV ES:[SI], AL ; Fill in Right Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn + + MOV ES:[SI], AL ; Fill in Right Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn + +@FB_RIGHT_CONT: + + DEC CX ; Minus 1 for Middle bands + JZ @FB_EXIT ; Uh.. no Middle bands... + +@FB_R_EDGE_FLUSH: + + ; DI = Addr of Upper Left block to fill + ; CX = # of Bands to fill in (width) + + OUT_8 SC_Data, ALL_PLANES ; Write to All Planes + + MOV DX, SCREEN_WIDTH ; DX = DI Increment + SUB DX, CX ; = Screen_Width-# Planes Filled + + MOV BX, CX ; BX = Quick Refill for CX + MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill + MOV AL, [BP].FB_Color ; Get Fill Color + +@FB_MIDDLE_LOOP: + REP STOSB ; Fill in entire line + + MOV CX, BX ; Recharge CX (Line Width) + ADD DI, DX ; Point to start of Next Line + LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn + + JMP s @FB_EXIT ; Outa here + +@FB_ONE_BAND_ONLY: + MOV SI, AX ; Get Left Clip Mask, Save X1 + AND SI, PLANE_BITS ; Mask out Row # + MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask + MOV SI, BX ; Get Right Clip Mask, Save X2 + AND SI, PLANE_BITS ; Mask out Row # + AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + + MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_ONE_LOOP: + MOV ES:[DI], AL ; Fill in Pixels + ADD DI, BX ; Point to Next Line (Below) + LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn + + MOV ES:[DI], AL ; Fill in Pixels + ADD DI, BX ; Point to Next Line (Below) + LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn + +@FB_EXIT: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +FILL_BLOCK ENDP + + +;===================================================== +;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) +;===================================================== +; +; Draws a Line on the active display page +; +; ENTRY: Xpos1 = X position of first point on line +; Ypos1 = Y position of first point on line +; Xpos2 = X position of last point on line +; Ypos2 = Y position of last point on line +; ColorNum = Color to draw line with +; +; EXIT: No meaningful values returned +; + +DL_STACK STRUC + DW ?x3 ; DI, SI, BP + DD ? ; Caller + DL_ColorF DB ?,? ; Line Draw Color + DL_Ypos2 DW ? ; Y pos of last point + DL_Xpos2 DW ? ; X pos of last point + DL_Ypos1 DW ? ; Y pos of first point + DL_Xpos1 DW ? ; X pos of first point +DL_STACK ENDS + + PUBLIC DRAW_LINE + +DRAW_LINE PROC FAR + + PUSHx BP, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + MOV CH, [BP].DL_ColorF ; Save Line Color in CH + + ; Check Line Type + + MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2? + MOV DI, [BP].DL_Xpos2 ; DX = X2 + CMP SI, DI ; Is X1 < X2 + JE @DL_VLINE ; If X1=X2, Draw Vertical Line + JL @DL_NOSWAP1 ; If X1 < X2, don't swap + + XCHG SI, DI ; X2 IS > X1, SO SWAP THEM + +@DL_NOSWAP1: + + ; SI = X1, DI = X2 + + MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2? + CMP AX, [BP].DL_Ypos2 ; Y1 = Y2? + JE @DL_HORZ ; If so, Draw a Horizontal Line + + JMP @DL_BREZHAM ; Diagonal line... go do it... + + ; This Code draws a Horizontal Line in Mode X where: + ; SI = X1, DI = X2, and AX = Y1/Y2 + +@DL_HORZ: + + MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width + MOV DX, AX ; CX = Line offset into Page + + MOV AX, SI ; Get Left edge, Save X1 + AND SI, PLANE_BITS ; Mask out Row # + MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask + MOV CX, DI ; Get Right edge, Save X2 + AND DI, PLANE_BITS ; Mask out Row # + MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte + + SHR AX, 2 ; Get X1 Byte # (=X1/4) + SHR CX, 2 ; Get X2 Byte # (=X2/4) + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + ADD DI, DX ; Point to Start of Line + ADD DI, AX ; Point to Pixel X1 + + SUB CX, AX ; CX = # Of Bands (-1) to set + JNZ @DL_LONGLN ; jump if longer than one segment + + AND BL, BH ; otherwise, merge clip masks + +@DL_LONGLN: + + OUT_8 SC_Data, BL ; Set the Left Clip Mask + + MOV AL, [BP].DL_ColorF ; Get Line Color + MOV BL, AL ; BL = Copy of Line Color + STOSB ; Set Left (1-4) Pixels + + JCXZ @DL_EXIT ; Done if only one Line Segment + + DEC CX ; CX = # of Middle Segments + JZ @DL_XRSEG ; If no middle segments.... + + ; Draw Middle Segments + + OUT_8 DX, ALL_PLANES ; Write to ALL Planes + + MOV AL, BL ; Get Color from BL + REP STOSB ; Draw Middle (4 Pixel) Segments + +@DL_XRSEG: + OUT_8 DX, BH ; Select Planes for Right Clip Mask + MOV AL, BL ; Get Color Value + STOSB ; Draw Right (1-4) Pixels + + JMP s @DL_EXIT ; We Are Done... + + + ; This Code Draws A Vertical Line. On entry: + ; CH = Line Color, SI & DI = X1 + +@DL_VLINE: + + MOV AX, [BP].DL_Ypos1 ; AX = Y1 + MOV SI, [BP].DL_Ypos2 ; SI = Y2 + CMP AX, SI ; Is Y1 < Y2? + JLE @DL_NOSWAP2 ; if so, Don't Swap them + + XCHG AX, SI ; Ok, NOW Y1 < Y2 + +@DL_NOSWAP2: + + SUB SI, AX ; SI = Line Height (Y2-Y1+1) + INC SI + + ; AX = Y1, DI = X1, Get offset into Page into AX + + MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width + MOV DX, DI ; Copy Xpos into DX + SHR DI, 2 ; DI = Xpos/4 + ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1 + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + ADD DI, AX ; Point to Pixel X1, Y1 + + ;Select Plane + + MOV CL, DL ; CL = Save X1 + AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #) + MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1 + SHL AH, CL ; Change to Correct Plane # + OUT_16 SC_Index, AX ; Select Plane + + MOV AL, CH ; Get Saved Color + MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By + +@DL_VLoop: + MOV ES:[DI], AL ; Draw Single Pixel + ADD DI, BX ; Point to Next Line + LOOPjz SI, @DL_EXIT ; Lines--, Exit if done + + MOV ES:[DI], AL ; Draw Single Pixel + ADD DI, BX ; Point to Next Line + LOOPx SI, @DL_VLoop ; Lines--, Loop until Done + +@DL_EXIT: + + JMP @DL_EXIT2 ; Done! + + ; This code Draws a diagonal line in Mode X + +@DL_BREZHAM: + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].DL_Ypos1 ; get Y1 value + MOV BX, [BP].DL_Ypos2 ; get Y2 value + MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos + + CMP BX, AX ; Y2-Y1 is? + JNC @DL_DeltaYOK ; if Y2>=Y1 then goto... + + XCHG BX, AX ; Swap em... + MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos + +@DL_DeltaYOK: + MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1 + + ADD DI, AX ; DI -> Start of Line Y1 on Page + MOV AX, CX ; AX = Xpos (X1) + SHR AX, 2 ; /4 = Byte Offset into Line + ADD DI, AX ; DI = Starting pos (X1,Y1) + + MOV AL, 11h ; Staring Mask + AND CL, PLANE_BITS ; Get Plane # + SHL AL, CL ; and shift into place + MOV AH, [BP].DL_ColorF ; Color in Hi Bytes + + PUSH AX ; Save Mask,Color... + + MOV AH, AL ; Plane # in AH + MOV AL, MAP_MASK ; Select Plane Register + OUT_16 SC_Index, AX ; Select initial plane + + MOV AX, [BP].DL_Xpos1 ; get X1 value + MOV BX, [BP].DL_Ypos1 ; get Y1 value + MOV CX, [BP].DL_Xpos2 ; get X2 value + MOV DX, [BP].DL_Ypos2 ; get Y2 value + + MOV BP, SCREEN_WIDTH ; Use BP for Line width to + ; to avoid extra memory access + + SUB DX, BX ; figure Delta_Y + JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1 + + ADD BX, DX ; put Y2 into Y1 + NEG DX ; abs(Delta_Y) + XCHG AX, CX ; and exchange X1 and X2 + +@DL_DeltaYOK2: + MOV BX, 08000H ; seed for fraction accumulator + + SUB CX, AX ; figure Delta_X + JC @DL_DrawLeft ; if negative, go left + + JMP @DL_DrawRight ; Draw Line that slopes right + +@DL_DrawLeft: + + NEG CX ; abs(Delta_X) + + CMP CX, DX ; is Delta_X < Delta_Y? + JB @DL_SteepLeft ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the left in Mode X + +@DL_ShallowLeft: + CLR AX ; zero low word of Delta_Y * 10000h + SUB AX, DX ; DX:AX <- DX * 0FFFFh + SBB DX, 0 ; include carry + DIV CX ; divide by Delta_X + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down... + +@DL_SLLLoop: + MOV ES:[DI], AH ; set first pixel, plane data set up + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLLL2nc ; move down on carry + + ADD DI, BP ; Move Down one line... + +@DL_SLLL2nc: + DEC DI ; Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + + ADD SI, BX ; add numerator to accumulator, + JNC @DL_SLLL3nc ; move down on carry + + ADD DI, BP ; Move Down one line... + +@DL_SLLL3nc: ; Now move left a pixel... + DEC DI ; Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + JMP s @DL_SLLLoop ; loop until done + +@DL_SLLExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a steep line to the left in Mode X + +@DL_SteepLeft: + CLR AX ; zero low word of Delta_Y * 10000h + XCHG DX, CX ; Delta_Y switched with Delta_X + DIV CX ; divide by Delta_Y + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe left + +@DL_STLLoop: + + MOV ES:[DI], AH ; set first pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_STLnc2 ; No carry, just move down! + + DEC DI ; Move Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@DL_STLnc2: + ADD DI, BP ; advance to next line. + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_STLnc3 ; No carry, just move down! + + DEC DI ; Move Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@DL_STLnc3: + ADD DI, BP ; advance to next line. + JMP s @DL_STLLoop ; Loop until done + +@DL_STLExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a line that goes to the Right... + +@DL_DrawRight: + CMP CX, DX ; is Delta_X < Delta_Y? + JB @DL_SteepRight ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the Right in Mode X + +@DL_ShallowRight: + CLR AX ; zero low word of Delta_Y * 10000h + SUB AX, DX ; DX:AX <- DX * 0FFFFh + SBB DX, 0 ; include carry + DIV CX ; divide by Delta_X + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down... + +@DL_SLRLoop: + MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLR2nc ; don't move down if carry not set + + ADD DI, BP ; Move Down one line... + +@DL_SLR2nc: ; Now move right a pixel... + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLR3nc ; don't move down if carry not set + + ADD DI, BP ; Move Down one line... + +@DL_SLR3nc: + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + JMP s @DL_SLRLoop ; loop till done + +@DL_SLRExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a Steep line to the Right in Mode X + +@DL_SteepRight: + CLR AX ; zero low word of Delta_Y * 10000h + XCHG DX, CX ; Delta_Y switched with Delta_X + DIV CX ; divide by Delta_Y + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right + +@STRLoop: + MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + + ADD SI, BX ; add numerator to accumulator + JNC @STRnc2 ; if no carry then just go down... + + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@STRnc2: + ADD DI, BP ; advance to next line. + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + + ADD SI, BX ; add numerator to accumulator + JNC @STRnc3 ; if no carry then just go down... + + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@STRnc3: + ADD DI, BP ; advance to next line. + JMP s @STRLoop ; loop till done + +@DL_EXIT2: + POPx DI, SI, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +DRAW_LINE ENDP + + + ; ===== DAC COLOR REGISTER ROUTINES ===== + +;================================================= +;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%) +;================================================= +; +; Sets a single (RGB) Vga Palette Register +; +; ENTRY: Register = The DAC # to modify (0-255) +; Red = The new Red Intensity (0-63) +; Green = The new Green Intensity (0-63) +; Blue = The new Blue Intensity (0-63) +; +; EXIT: No meaningful values returned +; + +SDR_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDR_Blue DB ?,? ; Blue Data Value + SDR_Green DB ?,? ; Green Data Value + SDR_Red DB ?,? ; Red Data Value + SDR_Register DB ?,? ; Palette Register # +SDR_STACK ENDS + + PUBLIC SET_DAC_REGISTER + +SET_DAC_REGISTER PROC FAR + + PUSH BP ; Save BP + MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to modify + + OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register + + MOV DX, PEL_DATA_REG ; Dac Data Register + OUT_8 DX, [BP].SDR_Red ; Set Red Intensity + OUT_8 DX, [BP].SDR_Green ; Set Green Intensity + OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity + + POP BP ; Restore Registers + RET 8 ; Exit & Clean Up Stack + +SET_DAC_REGISTER ENDP + +;==================================================== +;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%) +;==================================================== +; +; Reads the RGB Values of a single Vga Palette Register +; +; ENTRY: Register = The DAC # to read (0-255) +; Red = Offset to Red Variable in DS +; Green = Offset to Green Variable in DS +; Blue = Offset to Blue Variable in DS +; +; EXIT: The values of the integer variables Red, +; Green, and Blue are set to the values +; taken from the specified DAC register. +; + +GDR_STACK STRUC + DW ? ; BP + DD ? ; Caller + GDR_Blue DW ? ; Addr of Blue Data Value in DS + GDR_Green DW ? ; Addr of Green Data Value in DS + GDR_Red DW ? ; Addr of Red Data Value in DS + GDR_Register DB ?,? ; Palette Register # +GDR_STACK ENDS + + PUBLIC GET_DAC_REGISTER + +GET_DAC_REGISTER PROC FAR + + PUSH BP ; Save BP + MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to read in + + OUT_8 DAC_READ_ADDR, [BP].GDR_Register + + MOV DX, PEL_DATA_REG ; Dac Data Register + CLR AX ; Clear AX + + IN AL, DX ; Read Red Value + MOV BX, [BP].GDR_Red ; Get Address of Red% + MOV [BX], AX ; *Red% = AX + + IN AL, DX ; Read Green Value + MOV BX, [BP].GDR_Green ; Get Address of Green% + MOV [BX], AX ; *Green% = AX + + IN AL, DX ; Read Blue Value + MOV BX, [BP].GDR_Blue ; Get Address of Blue% + MOV [BX], AX ; *Blue% = AX + + POP BP ; Restore Registers + RET 8 ; Exit & Clean Up Stack + +GET_DAC_REGISTER ENDP + + +;=========================================================== +;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%) +;=========================================================== +; +; Sets a Block of Vga Palette Registers +; +; ENTRY: PalData = Far Pointer to Block of palette data +; StartReg = First Register # in range to set (0-255) +; EndReg = Last Register # in Range to set (0-255) +; Sync = Wait for Vertical Retrace Flag (Boolean) +; +; EXIT: No meaningful values returned +; +; NOTES: PalData is a linear array of 3 byte Palette values +; in the order: Red (0-63), Green (0-63), Blue (0-63) +; + +LDR_STACK STRUC + DW ?x3 ; BP, DS, SI + DD ? ; Caller + LDR_Sync DW ? ; Vertical Sync Flag + LDR_EndReg DB ?,? ; Last Register # + LDR_StartReg DB ?,? ; First Register # + LDR_PalData DD ? ; Far Ptr to Palette Data +LDR_STACK ENDS + + PUBLIC LOAD_DAC_REGISTERS + +LOAD_DAC_REGISTERS PROC FAR + + PUSHx BP, DS, SI ; Save Registers + mov BP, SP ; Set up Stack Frame + + mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag + or AX, AX ; is Sync Flag = 0? + jz @LDR_Load ; if so, skip call + + call f SYNC_DISPLAY ; wait for vsync + + ; Determine register #'s, size to copy, etc + +@LDR_Load: + + lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data + mov DX, DAC_WRITE_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + mov AL, [BP].LDR_StartReg ; Get Start Register + mov BL, [BP].LDR_EndReg ; Get End Register + + sub BX, AX ; BX = # of DAC registers -1 + inc BX ; BX = # of DAC registers + mov CX, BX ; CX = # of DAC registers + add CX, BX ; CX = " " * 2 + add CX, BX ; CX = " " * 3 + cld ; Block OUTs forward + out DX, AL ; set up correct register # + + ; Load a block of DAC Registers + + mov DX, PEL_DATA_REG ; Dac Data Register + + rep outsb ; block set DAC registers + + POPx SI, DS, BP ; Restore Registers + ret 10 ; Exit & Clean Up Stack + +LOAD_DAC_REGISTERS ENDP + + +;==================================================== +;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%) +;==================================================== +; +; Reads a Block of Vga Palette Registers +; +; ENTRY: PalData = Far Pointer to block to store palette data +; StartReg = First Register # in range to read (0-255) +; EndReg = Last Register # in Range to read (0-255) +; +; EXIT: No meaningful values returned +; +; NOTES: PalData is a linear array of 3 byte Palette values +; in the order: Red (0-63), Green (0-63), Blue (0-63) +; + +RDR_STACK STRUC + DW ?x3 ; BP, ES, DI + DD ? ; Caller + RDR_EndReg DB ?,? ; Last Register # + RDR_StartReg DB ?,? ; First Register # + RDR_PalData DD ? ; Far Ptr to Palette Data +RDR_STACK ENDS + + PUBLIC READ_DAC_REGISTERS + +READ_DAC_REGISTERS PROC FAR + + PUSHx BP, ES, DI ; Save Registers + mov BP, SP ; Set up Stack Frame + + ; Determine register #'s, size to copy, etc + + les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer + mov DX, DAC_READ_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + mov AL, [BP].RDR_StartReg ; Get Start Register + mov BL, [BP].RDR_EndReg ; Get End Register + + sub BX, AX ; BX = # of DAC registers -1 + inc BX ; BX = # of DAC registers + mov CX, BX ; CX = # of DAC registers + add CX, BX ; CX = " " * 2 + add CX, BX ; CX = " " * 3 + cld ; Block INs forward + + ; Read a block of DAC Registers + + out DX, AL ; set up correct register # + mov DX, PEL_DATA_REG ; Dac Data Register + + rep insb ; block read DAC registers + + POPx DI, ES, BP ; Restore Registers + ret 8 ; Exit & Clean Up Stack + +READ_DAC_REGISTERS ENDP + + + ; ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +;========================= +;SET_ACTIVE_PAGE (PageNo%) +;========================= +; +; Sets the active display Page to be used for future drawing +; +; ENTRY: PageNo = Display Page to make active +; (values: 0 to Number of Pages - 1) +; +; EXIT: No meaningful values returned +; + +SAP_STACK STRUC + DW ? ; BP + DD ? ; Caller + SAP_Page DW ? ; Page # for Drawing +SAP_STACK ENDS + + PUBLIC SET_ACTIVE_PAGE + +SET_ACTIVE_PAGE PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + MOV BX, [BP].SAP_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SAP_Exit ; IF Not, Do Nothing + + MOV ACTIVE_PAGE, BX ; Set Active Page # + + SHL BX, 1 ; Scale Page # to Word + MOV AX, PAGE_ADDR[BX] ; Get offset to Page + + MOV CURRENT_PAGE, AX ; And set for future LES's + +@SAP_Exit: + POP BP ; Restore Registers + RET 2 ; Exit and Clean up Stack + +SET_ACTIVE_PAGE ENDP + + +;================ +;GET_ACTIVE_PAGE% +;================ +; +; Returns the Video Page # currently used for Drawing +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Video Page used for Drawing +; + + PUBLIC GET_ACTIVE_PAGE + +GET_ACTIVE_PAGE PROC FAR + + MOV AX, ACTIVE_PAGE ; Get Active Page # + RET ; Exit and Clean up Stack + +GET_ACTIVE_PAGE ENDP + + +;=============================== +;SET_DISPLAY_PAGE (DisplayPage%) +;=============================== +; +; Sets the currently visible display page. +; When called this routine syncronizes the display +; to the vertical blank. +; +; ENTRY: PageNo = Display Page to show on the screen +; (values: 0 to Number of Pages - 1) +; +; EXIT: No meaningful values returned +; + +SDP_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDP_Page DW ? ; Page # to Display... +SDP_STACK ENDS + + PUBLIC SET_DISPLAY_PAGE + +SET_DISPLAY_PAGE PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + MOV BX, [BP].SDP_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SDP_Exit ; IF Not, Do Nothing + + MOV DISPLAY_PAGE, BX ; Set Display Page # + + SHL BX, 1 ; Scale Page # to Word + MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page + ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling + + ; Wait if we are currently in a Vertical Retrace + + MOV DX, INPUT_1 ; Input Status #1 Register + +@DP_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @DP_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new page + + MOV DX, CRTC_Index ; We Change the VGA Sequencer + + MOV AL, START_DISP_LO ; Display Start Low Register + MOV AH, CL ; Low 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr Low + + MOV AL, START_DISP_HI ; Display Start High Register + MOV AH, CH ; High 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + MOV DX, INPUT_1 ; Input Status #1 Register + +@DP_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @DP_WAIT1 ; If Not, wait for it + + ; Now Set Display Starting Address + + +@SDP_Exit: + POP BP ; Restore Registers + RET 2 ; Exit and Clean up Stack + +SET_DISPLAY_PAGE ENDP + + +;================= +;GET_DISPLAY_PAGE% +;================= +; +; Returns the Video Page # currently displayed +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Video Page being displayed +; + + PUBLIC GET_DISPLAY_PAGE + +GET_DISPLAY_PAGE PROC FAR + + MOV AX, DISPLAY_PAGE ; Get Display Page # + RET ; Exit & Clean Up Stack + +GET_DISPLAY_PAGE ENDP + + +;======================================= +;SET_WINDOW (DisplayPage%, Xpos%, Ypos%) +;======================================= +; +; Since a Logical Screen can be larger than the Physical +; Screen, Scrolling is possible. This routine sets the +; Upper Left Corner of the Screen to the specified Pixel. +; Also Sets the Display page to simplify combined page +; flipping and scrolling. When called this routine +; syncronizes the display to the vertical blank. +; +; ENTRY: DisplayPage = Display Page to show on the screen +; Xpos = # of pixels to shift screen right +; Ypos = # of lines to shift screen down +; +; EXIT: No meaningful values returned +; + +SW_STACK STRUC + DW ? ; BP + DD ? ; Caller + SW_Ypos DW ? ; Y pos of UL Screen Corner + SW_Xpos DW ? ; X pos of UL Screen Corner + SW_Page DW ? ; (new) Display Page +SW_STACK ENDS + + PUBLIC SET_WINDOW + +SET_WINDOW PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + ; Check if our Scroll Offsets are Valid + + MOV BX, [BP].SW_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SW_Exit ; IF Not, Do Nothing + + MOV AX, [BP].SW_Ypos ; Get Desired Y Offset + CMP AX, MAX_YOFFSET ; Is it Within Limits? + JA @SW_Exit ; if not, exit + + MOV CX, [BP].SW_Xpos ; Get Desired X Offset + CMP CX, MAX_XOFFSET ; Is it Within Limits? + JA @SW_Exit ; if not, exit + + ; Compute proper Display start address to use + + MUL SCREEN_WIDTH ; AX = YOffset * Line Width + SHR CX, 2 ; CX / 4 = Bytes into Line + ADD AX, CX ; AX = Offset of Upper Left Pixel + + MOV CURRENT_MOFFSET, AX ; Save Offset Info + + MOV DISPLAY_PAGE, BX ; Set Current Page # + SHL BX, 1 ; Scale Page # to Word + ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page + MOV BX, AX ; BX = Desired Display Start + + MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait if we are currently in a Vertical Retrace + +@SW_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @SW_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new window + + MOV DX, CRTC_Index ; We Change the VGA Sequencer + MOV AL, START_DISP_LO ; Display Start Low Register + MOV AH, BL ; Low 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr Low + + MOV AL, START_DISP_HI ; Display Start High Register + MOV AH, BH ; High 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + MOV DX, INPUT_1 ; Input Status #1 Register + +@SW_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @SW_WAIT1 ; If Not, wait for it + + ; Now Set the Horizontal Pixel Pan values + + OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register + + MOV AX, [BP].SW_Xpos ; Get Desired X Offset + AND AL, 03 ; Get # of Pixels to Pan (0-3) + SHL AL, 1 ; Shift for 256 Color Mode + OUT DX, AL ; Fine tune the display! + +@SW_Exit: + POP BP ; Restore Saved Registers + RET 6 ; Exit and Clean up Stack + +SET_WINDOW ENDP + + +;============= +;GET_X_OFFSET% +;============= +; +; Returns the X coordinate of the Pixel currently display +; in the upper left corner of the display +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Horizontal Scroll Offset +; + + PUBLIC GET_X_OFFSET + +GET_X_OFFSET PROC FAR + + MOV AX, CURRENT_XOFFSET ; Get current horz offset + RET ; Exit & Clean Up Stack + +GET_X_OFFSET ENDP + + +;============= +;GET_Y_OFFSET% +;============= +; +; Returns the Y coordinate of the Pixel currently display +; in the upper left corner of the display +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Vertical Scroll Offset +; + + PUBLIC GET_Y_OFFSET + +GET_Y_OFFSET PROC FAR + + MOV AX, CURRENT_YOFFSET ; Get current vertical offset + RET ; Exit & Clean Up Stack + +GET_Y_OFFSET ENDP + + +;============ +;SYNC_DISPLAY +;============ +; +; Pauses the computer until the next Vertical Retrace starts +; +; ENTRY: No Parameters are passed +; +; EXIT: No meaningful values returned +; + + PUBLIC SYNC_DISPLAY + +SYNC_DISPLAY PROC FAR + + MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait for any current retrace to end + +@SD_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @SD_WAIT0 ; If Not, wait for it + + ; Wait for the start of the next vertical retrace + +@SD_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @SD_WAIT1 ; If Not, wait for it + + RET ; Exit & Clean Up Stack + +SYNC_DISPLAY ENDP + + + ; ===== TEXT DISPLAY ROUTINES ===== + +;================================================== +;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%) +;================================================== +; +; Draws an ASCII Text Character using the currently selected +; 8x8 font on the active display page. It would be a simple +; exercise to make this routine process variable height fonts. +; +; ENTRY: CharNum = ASCII character # to draw +; Xpos = X position to draw Character at +; Ypos = Y position of to draw Character at +; ColorF = Color to draw text character in +; ColorB = Color to set background to +; +; EXIT: No meaningful values returned +; + +GPC_STACK STRUC + GPC_Width DW ? ; Screen Width-1 + GPC_Lines DB ?,? ; Scan lines to Decode + GPC_T_SETS DW ? ; Saved Charset Segment + GPC_T_SETO DW ? ; Saved Charset Offset + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + GPC_ColorB DB ?,? ; Background Color + GPC_ColorF DB ?,? ; Text Color + GPC_Ypos DW ? ; Y Position to Print at + GPC_Xpos DW ? ; X position to Print at + GPC_Char DB ?,? ; Character to Print +GPC_STACK ENDS + + PUBLIC GPRINTC + +GPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 8 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, SCREEN_WIDTH ; Get Logical Line Width + MOV BX, AX ; BX = Screen Width + DEC BX ; = Screen Width-1 + MOV [BP].GPC_Width, BX ; Save for later use + + MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width + ADD DI, AX ; DI -> Start of Line Ypos + + MOV AX, [BP].GPC_Xpos ; Get Xpos of Character + MOV CX, AX ; Save Copy of Xpos + SHR AX, 2 ; Bytes into Line = Xpos/4 + ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + MOV AL, [BP].GPC_Char ; Get Character # + TEST AL, 080h ; Is Hi Bit Set? + JZ @GPC_LowChar ; Nope, use low char set ptr + + AND AL, 07Fh ; Mask Out Hi Bit + MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + JMP s @GPC_Set_Char ; Go Setup Character Ptr + +@GPC_LowChar: + + MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + +@GPC_Set_Char: + MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack + + MOV AH, 0 ; Valid #'s are 0..127 + SHL AX, 3 ; * 8 Bytes Per Bitmap + ADD BX, AX ; BX = Offset of Selected char + MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack + + AND CX, PLANE_BITS ; Get Plane # + MOV CH, ALL_PLANES ; Get Initial Plane mask + SHL CH, CL ; And shift into position + AND CH, ALL_PLANES ; And mask to lower nibble + + MOV AL, 04 ; 4-Plane # = # of initial + SUB AL, CL ; shifts to align bit mask + MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + INC DX ; DX -> SC_Data + + MOV AL, 08 ; 8 Lines to Process + MOV [BP].GPC_Lines, AL ; Save on Stack + + MOV DS, [BP].GPC_T_SETS ; Point to character set + +@GPC_DECODE_CHAR_BYTE: + + MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String + + MOV BH, [SI] ; Get Bit Map + INC SI ; Point to Next Line + MOV [BP].GPC_T_SETO, SI ; And save new Pointer... + + CLR AX ; Clear AX + + CLR BL ; Clear BL + ROL BX, CL ; BL holds left edge bits + MOV SI, BX ; Use as Table Index + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_LEFT1BITS: + XOR AL, CH ; Invert mask for Background + JZ @GPC_NO_LEFT0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + +@GPC_NO_LEFT0BITS: + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_MIDDLE1BITS: + XOR AL, ALL_PLANES ; Invert mask for Background + JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_MIDDLE0BITS: + XOR CH, ALL_PLANES ; Invert Clip Mask + CMP CL, 4 ; Aligned by 4? + JZ @GPC_NEXT_LINE ; If so, Exit now.. + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_RIGHT1BITS: + + XOR AL, CH ; Invert mask for Background + JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_RIGHT0BITS: + DEC DI ; Adjust for Next Line Advance + +@GPC_NEXT_LINE: + ADD DI, [BP].GPC_Width ; Point to Next Line + XOR CH, CHAR_BITS ; Flip the Clip mask back + + DEC [BP].GPC_Lines ; Count Down Lines + JZ @GPC_EXIT ; Ok... Done! + + JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey! + +@GPC_EXIT: + ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +GPRINTC ENDP + + +;========================================== +;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%) +;========================================== +; +; Transparently draws an ASCII Text Character using the +; currently selected 8x8 font on the active display page. +; +; ENTRY: CharNum = ASCII character # to draw +; Xpos = X position to draw Character at +; Ypos = Y position of to draw Character at +; ColorF = Color to draw text character in +; +; EXIT: No meaningful values returned +; + +TGP_STACK STRUC + TGP_Width DW ? ; Screen Width-1 + TGP_Lines DB ?,? ; Scan lines to Decode + TGP_T_SETS DW ? ; Saved Charset Segment + TGP_T_SETO DW ? ; Saved Charset Offset + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TGP_ColorF DB ?,? ; Text Color + TGP_Ypos DW ? ; Y Position to Print at + TGP_Xpos DW ? ; X position to Print at + TGP_Char DB ?,? ; Character to Print +TGP_STACK ENDS + + PUBLIC TGPRINTC + +TGPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 8 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, SCREEN_WIDTH ; Get Logical Line Width + MOV BX, AX ; BX = Screen Width + DEC BX ; = Screen Width-1 + MOV [BP].TGP_Width, BX ; Save for later use + + MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width + ADD DI, AX ; DI -> Start of Line Ypos + + MOV AX, [BP].TGP_Xpos ; Get Xpos of Character + MOV CX, AX ; Save Copy of Xpos + SHR AX, 2 ; Bytes into Line = Xpos/4 + ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + MOV AL, [BP].TGP_Char ; Get Character # + TEST AL, 080h ; Is Hi Bit Set? + JZ @TGP_LowChar ; Nope, use low char set ptr + + AND AL, 07Fh ; Mask Out Hi Bit + MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + JMP s @TGP_Set_Char ; Go Setup Character Ptr + +@TGP_LowChar: + + MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + +@TGP_Set_Char: + MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack + + MOV AH, 0 ; Valid #'s are 0..127 + SHL AX, 3 ; * 8 Bytes Per Bitmap + ADD BX, AX ; BX = Offset of Selected char + MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack + + AND CX, PLANE_BITS ; Get Plane # + MOV CH, ALL_PLANES ; Get Initial Plane mask + SHL CH, CL ; And shift into position + AND CH, ALL_PLANES ; And mask to lower nibble + + MOV AL, 04 ; 4-Plane # = # of initial + SUB AL, CL ; shifts to align bit mask + MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + INC DX ; DX -> SC_Data + + MOV AL, 08 ; 8 Lines to Process + MOV [BP].TGP_Lines, AL ; Save on Stack + + MOV DS, [BP].TGP_T_SETS ; Point to character set + +@TGP_DECODE_CHAR_BYTE: + + MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String + + MOV BH, [SI] ; Get Bit Map + INC SI ; Point to Next Line + MOV [BP].TGP_T_SETO, SI ; And save new Pointer... + + MOV AH, [BP].TGP_ColorF ; Get Foreground Color + + CLR BL ; Clear BL + ROL BX, CL ; BL holds left edge bits + MOV SI, BX ; Use as Table Index + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + +@TGP_NO_LEFT1BITS: + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@TGP_NO_MIDDLE1BITS: + XOR CH, ALL_PLANES ; Invert Clip Mask + CMP CL, 4 ; Aligned by 4? + JZ @TGP_NEXT_LINE ; If so, Exit now.. + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@TGP_NO_RIGHT1BITS: + + DEC DI ; Adjust for Next Line Advance + +@TGP_NEXT_LINE: + ADD DI, [BP].TGP_Width ; Point to Next Line + XOR CH, CHAR_BITS ; Flip the Clip mask back + + DEC [BP].TGP_Lines ; Count Down Lines + JZ @TGP_EXIT ; Ok... Done! + + JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey! + +@TGP_EXIT: + ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 8 ; Exit and Clean up Stack + +TGPRINTC ENDP + + +;=============================================================== +;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) +;=============================================================== +; +; Routine to quickly Print a null terminated ASCII string on the +; active display page up to a maximum length. +; +; ENTRY: String = Far Pointer to ASCII string to print +; MaxLen = # of characters to print if no null found +; Xpos = X position to draw Text at +; Ypos = Y position of to draw Text at +; ColorF = Color to draw text in +; ColorB = Color to set background to +; +; EXIT: No meaningful values returned +; + +PS_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + PS_ColorB DW ? ; Background Color + PS_ColorF DW ? ; Text Color + PS_Ypos DW ? ; Y Position to Print at + PS_Xpos DW ? ; X position to Print at + PS_Len DW ? ; Maximum Length of string to print + PS_Text DW ?,? ; Far Ptr to Text String +PS_STACK ENDS + + PUBLIC PRINT_STR + +PRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + +@PS_Print_It: + + MOV CX, [BP].PS_Len ; Get Remaining text Length + JCXZ @PS_Exit ; Exit when out of text + + LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text + MOV AL, ES:[DI] ; AL = Text Character + AND AX, 00FFh ; Clear High Word + JZ @PS_Exit ; Exit if null character + + DEC [BP].PS_Len ; Remaining Text length-- + INC [BP].PS_Text ; Point to Next text char + + ; Set up Call to GPRINTC + + PUSH AX ; Set Character Parameter + MOV BX, [BP].PS_Xpos ; Get Xpos + PUSH BX ; Set Xpos Parameter + ADD BX, 8 ; Advance 1 Char to Right + MOV [BP].PS_Xpos, BX ; Save for next time through + + MOV BX, [BP].PS_Ypos ; Get Ypos + PUSH BX ; Set Ypos Parameter + + MOV BX, [BP].PS_ColorF ; Get Text Color + PUSH BX ; Set ColorF Parameter + + MOV BX, [BP].PS_ColorB ; Get Background Color + PUSH BX ; Set ColorB Parameter + + CALL f GPRINTC ; Print Character! + JMP s @PS_Print_It ; Process next character + +@PS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 14 ; Exit and Clean up Stack + +PRINT_STR ENDP + + +;================================================================ +;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) +;================================================================ +; +; Routine to quickly transparently Print a null terminated ASCII +; string on the active display page up to a maximum length. +; +; ENTRY: String = Far Pointer to ASCII string to print +; MaxLen = # of characters to print if no null found +; Xpos = X position to draw Text at +; Ypos = Y position of to draw Text at +; ColorF = Color to draw text in +; +; EXIT: No meaningful values returned +; + +TPS_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TPS_ColorF DW ? ; Text Color + TPS_Ypos DW ? ; Y Position to Print at + TPS_Xpos DW ? ; X position to Print at + TPS_Len DW ? ; Maximum Length of string to print + TPS_Text DW ?,? ; Far Ptr to Text String +TPS_STACK ENDS + + PUBLIC TPRINT_STR + +TPRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + +@TPS_Print_It: + + MOV CX, [BP].TPS_Len ; Get Remaining text Length + JCXZ @TPS_Exit ; Exit when out of text + + LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text + MOV AL, ES:[DI] ; AL = Text Character + AND AX, 00FFh ; Clear High Word + JZ @TPS_Exit ; Exit if null character + + DEC [BP].TPS_Len ; Remaining Text length-- + INC [BP].TPS_Text ; Point to Next text char + + ; Set up Call to TGPRINTC + + PUSH AX ; Set Character Parameter + MOV BX, [BP].TPS_Xpos ; Get Xpos + PUSH BX ; Set Xpos Parameter + ADD BX, 8 ; Advance 1 Char to Right + MOV [BP].TPS_Xpos, BX ; Save for next time through + + MOV BX, [BP].TPS_Ypos ; Get Ypos + PUSH BX ; Set Ypos Parameter + + MOV BX, [BP].TPS_ColorF ; Get Text Color + PUSH BX ; Set ColorF Parameter + + CALL f TGPRINTC ; Print Character! + JMP s @TPS_Print_It ; Process next character + +@TPS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +TPRINT_STR ENDP + + +;=========================================== +;SET_DISPLAY_FONT(SEG FontData, FontNumber%) +;=========================================== +; +; Allows the user to specify their own font data for +; wither the lower or upper 128 characters. +; +; ENTRY: FontData = Far Pointer to Font Bitmaps +; FontNumber = Which half of set this is +; = 0, Lower 128 characters +; = 1, Upper 128 characters +; +; EXIT: No meaningful values returned +; + +SDF_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDF_Which DW ? ; Hi Table/Low Table Flag + SDF_Font DD ? ; Far Ptr to Font Table +SDF_STACK ENDS + + PUBLIC SET_DISPLAY_FONT + +SET_DISPLAY_FONT PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, [BP].SDF_Font ; Get Far Ptr to Font + + MOV SI, o CHARSET_LOW ; Assume Lower 128 chars + TEST [BP].SDF_Which, 1 ; Font #1 selected? + JZ @SDF_Set_Font ; If not, skip ahead + + MOV SI, o CHARSET_HI ; Ah, really it's 128-255 + +@SDF_Set_Font: + MOV [SI], DI ; Set Font Pointer Offset + MOV [SI+2], ES ; Set Font Pointer Segment + + POP BP ; Restore Registers + RET 6 ; We are Done.. Outa here + +SET_DISPLAY_FONT ENDP + + + ; ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +;====================================================== +;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) +;====================================================== +; +; Draws a variable sized Graphics Bitmap such as a +; picture or an Icon on the current Display Page in +; Mode X. The Bitmap is stored in a linear byte array +; corresponding to (0,0) (1,0), (2,0) .. (Width, Height) +; This is the same linear manner as mode 13h graphics. +; +; ENTRY: Image = Far Pointer to Bitmap Data +; Xpos = X position to Place Upper Left pixel at +; Ypos = Y position to Place Upper Left pixel at +; Width = Width of the Bitmap in Pixels +; Height = Height of the Bitmap in Pixels +; +; EXIT: No meaningful values returned +; + +DB_STACK STRUC + DB_LineO DW ? ; Offset to Next Line + DB_PixCount DW ? ; (Minimum) # of Pixels/Line + DB_Start DW ? ; Addr of Upper Left Pixel + DB_PixSkew DW ? ; # of bytes to Adjust EOL + DB_SkewFlag DW ? ; Extra Pix on Plane Flag + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DB_Height DW ? ; Height of Bitmap in Pixels + DB_Width DW ? ; Width of Bitmap in Pixels + DB_Ypos DW ? ; Y position to Draw Bitmap at + DB_Xpos DW ? ; X position to Draw Bitmap at + DB_Image DD ? ; Far Pointer to Graphics Bitmap +DB_STACK ENDS + + PUBLIC DRAW_BITMAP + +DRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 10 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos + MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos + MOV CL, BL ; Save Plane # in CL + SHR BX, 2 ; Xpos/4 = Offset Into Line + + ADD DI, AX ; ES:DI -> Start of Line + ADD DI, BX ; ES:DI -> Upper Left Pixel + MOV [BP].DB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + MOV BX, [BP].DB_Width ; Get Width of Image + MOV DX, BX ; Save Copy in DX + SHR BX, 2 ; /4 = width in bands + MOV AX, SCREEN_WIDTH ; Get Screen Width + SUB AX, BX ; - (Bitmap Width/4) + + MOV [BP].DB_LineO, AX ; Save Line Width offset + MOV [BP].DB_PixCount, BX ; Minimum # pix to copy + + AND DX, PLANE_BITS ; Get "partial band" size (0-3) + MOV [BP].DB_PixSkew, DX ; Also End of Line Skew + MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count + + AND CX, PLANE_BITS ; CL = Starting Plane # + MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + MOV BH, AH ; BH = Saved Plane Mask + MOV BL, 4 ; BL = Planes to Copy + +@DB_COPY_PLANE: + + LDS SI, [BP].DB_Image ; DS:SI-> Source Image + MOV DX, [BP].DB_Height ; # of Lines to Copy + MOV DI, [BP].DB_Start ; ES:DI-> Dest pos + +@DB_COPY_LINE: + MOV CX, [BP].DB_PixCount ; Min # to copy + + TEST CL, 0FCh ; 16+PixWide? + JZ @DB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + +@DB_COPY_LOOP: + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + + SUB CL, 4 ; Pixels to Copy=-4 + TEST CL, 0FCh ; 4+ Pixels Left? + JNZ @DB_COPY_LOOP ; if so, do another block + +@DB_COPY_REMAINDER: + JCXZ @DB_NEXT_LINE ; Any Pixels left on line + +@DB_COPY2: + MOVSB ; Copy Bitmap Pixel + ADD SI,3 ; Skip to Next Byte in same plane + LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done + +@DB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + OR CX, [BP].DB_SkewFlag ; Get Skew Count + JZ @DB_NEXT2 ; if no partial pixels + + MOVSB ; Copy Bitmap Pixel + DEC DI ; Back up to align + DEC SI ; Back up to align + +@DB_NEXT2: + ADD SI, [BP].DB_PixSkew ; Adjust Skew + ADD DI, [BP].DB_LineO ; Set to Next Display Line + LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more + + ; Copy Next Plane.... + + DEC BL ; Planes to Go-- + JZ @DB_Exit ; Hey! We are done + + ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + + CMP AL, 12h ; Carry Set if AL=11h + ADC [BP].DB_Start, 0 ; Screen Addr =+Carry + INC w [BP].DB_Image ; Start @ Next Byte + + SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew + ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1 + + JMP s @DB_COPY_PLANE ; Go Copy the Next Plane + +@DB_Exit: + ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +DRAW_BITMAP ENDP + + +;======================================================= +;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) +;======================================================= +; +; Transparently Draws a variable sized Graphics Bitmap +; such as a picture or an Icon on the current Display Page +; in Mode X. Pixels with a value of 0 are not drawn, +; leaving the previous "background" contents intact. +; +; The Bitmap format is the same as for the DRAW_BITMAP function. +; +; ENTRY: Image = Far Pointer to Bitmap Data +; Xpos = X position to Place Upper Left pixel at +; Ypos = Y position to Place Upper Left pixel at +; Width = Width of the Bitmap in Pixels +; Height = Height of the Bitmap in Pixels +; +; EXIT: No meaningful values returned +; + +TB_STACK STRUC + TB_LineO DW ? ; Offset to Next Line + TB_PixCount DW ? ; (Minimum) # of Pixels/Line + TB_Start DW ? ; Addr of Upper Left Pixel + TB_PixSkew DW ? ; # of bytes to Adjust EOL + TB_SkewFlag DW ? ; Extra Pix on Plane Flag + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TB_Height DW ? ; Height of Bitmap in Pixels + TB_Width DW ? ; Width of Bitmap in Pixels + TB_Ypos DW ? ; Y position to Draw Bitmap at + TB_Xpos DW ? ; X position to Draw Bitmap at + TB_Image DD ? ; Far Pointer to Graphics Bitmap +TB_STACK ENDS + + PUBLIC TDRAW_BITMAP + +TDRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 10 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos + MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos + MOV CL, BL ; Save Plane # in CL + SHR BX, 2 ; Xpos/4 = Offset Into Line + + ADD DI, AX ; ES:DI -> Start of Line + ADD DI, BX ; ES:DI -> Upper Left Pixel + MOV [BP].TB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + MOV BX, [BP].TB_Width ; Get Width of Image + MOV DX, BX ; Save Copy in DX + SHR BX, 2 ; /4 = width in bands + MOV AX, SCREEN_WIDTH ; Get Screen Width + SUB AX, BX ; - (Bitmap Width/4) + + MOV [BP].TB_LineO, AX ; Save Line Width offset + MOV [BP].TB_PixCount, BX ; Minimum # pix to copy + + AND DX, PLANE_BITS ; Get "partial band" size (0-3) + MOV [BP].TB_PixSkew, DX ; Also End of Line Skew + MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count + + AND CX, PLANE_BITS ; CL = Starting Plane # + MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + MOV BH, AH ; BH = Saved Plane Mask + MOV BL, 4 ; BL = Planes to Copy + +@TB_COPY_PLANE: + + LDS SI, [BP].TB_Image ; DS:SI-> Source Image + MOV DX, [BP].TB_Height ; # of Lines to Copy + MOV DI, [BP].TB_Start ; ES:DI-> Dest pos + + ; Here AH is set with the value to be considered + ; "Transparent". It can be changed! + + MOV AH, 0 ; Value to Detect 0 + +@TB_COPY_LINE: + MOV CX, [BP].TB_PixCount ; Min # to copy + + TEST CL, 0FCh ; 16+PixWide? + JZ @TB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + +@TB_COPY_LOOP: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_01 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_SKIP_01: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_02 ; Skip ahead if so + MOV ES:[DI+1], AL ; Copy Pixel to VGA screen + +@TB_SKIP_02: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_03 ; Skip ahead if so + MOV ES:[DI+2], AL ; Copy Pixel to VGA screen + +@TB_SKIP_03: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_04 ; Skip ahead if so + MOV ES:[DI+3], AL ; Copy Pixel to VGA screen + +@TB_SKIP_04: + ADD DI, 4 ; Adjust Pixel Write Location + SUB CL, 4 ; Pixels to Copy=-4 + TEST CL, 0FCh ; 4+ Pixels Left? + JNZ @TB_COPY_LOOP ; if so, do another block + +@TB_COPY_REMAINDER: + JCXZ @TB_NEXT_LINE ; Any Pixels left on line + +@TB_COPY2: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_05 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_SKIP_05: + INC DI ; Advance Dest Addr + LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done + +@TB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + OR CX, [BP].TB_SkewFlag ; Get Skew Count + JZ @TB_NEXT2 ; if no partial pixels + + LODSB ; Get Pixel Value in AL + DEC SI ; Backup to Align + CMP AL, AH ; It is "Transparent"? + JE @TB_NEXT2 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_NEXT2: + ADD SI, [BP].TB_PixSkew ; Adjust Skew + ADD DI, [BP].TB_LineO ; Set to Next Display Line + LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More + + ;Copy Next Plane.... + + DEC BL ; Planes to Go-- + JZ @TB_Exit ; Hey! We are done + + ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + + CMP AL, 12h ; Carry Set if AL=11h + ADC [BP].TB_Start, 0 ; Screen Addr =+Carry + INC w [BP].TB_Image ; Start @ Next Byte + + SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew + ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1 + + JMP @TB_COPY_PLANE ; Go Copy the next Plane + +@TB_Exit: + ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +TDRAW_BITMAP ENDP + + + ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +;================================== +;COPY_PAGE (SourcePage%, DestPage%) +;================================== +; +; Duplicate on display page onto another +; +; ENTRY: SourcePage = Display Page # to Duplicate +; DestPage = Display Page # to hold copy +; +; EXIT: No meaningful values returned +; + +CP_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + CP_DestP DW ? ; Page to hold copied image + CP_SourceP DW ? ; Page to Make copy from +CP_STACK ENDS + + PUBLIC COPY_PAGE + +COPY_PAGE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + CLD ; Block Xfer Forwards + + ; Make sure Page #'s are valid + + MOV AX, [BP].CP_SourceP ; Get Source Page # + CMP AX, LAST_PAGE ; is it > Max Page #? + JAE @CP_Exit ; if so, abort + + MOV BX, [BP].CP_DestP ; Get Destination Page # + CMP BX, LAST_PAGE ; is it > Max Page #? + JAE @CP_Exit ; if so, abort + + CMP AX, BX ; Pages #'s the same? + JE @CP_Exit ; if so, abort + + ; Setup DS:SI and ES:DI to Video Pages + + SHL BX, 1 ; Scale index to Word + MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page + + MOV BX, AX ; Index to Source page + SHL BX, 1 ; Scale index to Word + MOV SI, PAGE_ADDR[BX] ; Offset to Source Page + + MOV CX, PAGE_SIZE ; Get size of Page + MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment + MOV ES, AX ; ES:DI -> Dest Page + MOV DS, AX ; DS:SI -> Source Page + + ; Setup VGA registers for Mem to Mem copy + + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes + + ; Note.. Do *NOT* use MOVSW or MOVSD - they will + ; Screw with the latches which are 8 bits x 4 + + REP MOVSB ; Copy entire Page! + + ; Reset VGA for normal memory access + + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off + +@CP_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 4 ; Exit and Clean up Stack + +COPY_PAGE ENDP + + +;========================================================================== +;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%) +;========================================================================== +; +; Copies a Bitmap Image from one Display Page to Another +; This Routine is Limited to copying Images with the same +; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4) +; Copying an Image to the Same Page is supported, but results +; may be defined when the when the rectangular areas +; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) - +; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap... +; No Paramter checking to done to insure that +; X2 >= X1 and Y2 >= Y1. Be Careful... +; +; ENTRY: SourcePage = Display Page # with Source Image +; X1 = Upper Left Xpos of Source Image +; Y1 = Upper Left Ypos of Source Image +; X2 = Lower Right Xpos of Source Image +; Y2 = Lower Right Ypos of Source Image +; DestPage = Display Page # to copy Image to +; DestX1 = Xpos to Copy UL Corner of Image to +; DestY1 = Ypos to Copy UL Corner of Image to +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +CB_STACK STRUC + CB_Height DW ? ; Height of Image in Lines + CB_Width DW ? ; Width of Image in "bands" + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + CB_DestY1 DW ? ; Destination Ypos + CB_DestX1 DW ? ; Destination Xpos + CB_DestP DW ? ; Page to Copy Bitmap To + CB_Y2 DW ? ; LR Ypos of Image + CB_X2 DW ? ; LR Xpos of Image + CB_Y1 DW ? ; UL Ypos of Image + CB_X1 DW ? ; UL Xpos of Image + CB_SourceP DW ? ; Page containing Source Bitmap +CB_STACK ENDS + + PUBLIC COPY_BITMAP + +COPY_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 4 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + ; Prep Registers (and keep jumps short!) + + MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram + CLD ; Block Xfer Forwards + + ; Make sure Parameters are valid + + MOV BX, [BP].CB_SourceP ; Get Source Page # + CMP BX, LAST_PAGE ; is it > Max Page #? + JAE @CB_Abort ; if so, abort + + MOV CX, [BP].CB_DestP ; Get Destination Page # + CMP CX, LAST_PAGE ; is it > Max Page #? + JAE @CB_Abort ; if so, abort + + MOV AX, [BP].CB_X1 ; Get Source X1 + XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1 + AND AX, PLANE_BITS ; Check Plane Bits + JNZ @CB_Abort ; They should cancel out + + ; Setup for Copy processing + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + + ; Compute Info About Images, Setup ES:SI & ES:DI + + MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines + SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1 + INC AX ; (add 1 since were not 0 based) + MOV [BP].CB_Height, AX ; Save on Stack for later use + + MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels + MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1 + SHR AX, 2 ; Get X2 Band (X2 / 4) + SHR DX, 2 ; Get X1 Band (X1 / 4) + SUB AX, DX ; AX = # of Bands - 1 + INC AX ; AX = # of Bands + MOV [BP].CB_Width, AX ; Save on Stack for later use + + SHL BX, 1 ; Scale Source Page to Word + MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page + MOV AX, [BP].CB_Y1 ; Get Source Y1 Line + MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + ADD SI, AX ; SI = Offset to Line Y1 + MOV AX, [BP].CB_X1 ; Get Source X1 + SHR AX, 2 ; X1 / 4 = Byte offset + ADD SI, AX ; SI = Byte Offset to (X1,Y1) + + MOV BX, CX ; Dest Page Index to BX + SHL BX, 1 ; Scale Source Page to Word + MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page + MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line + MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + ADD DI, AX ; DI = Offset to Line Y1 + MOV AX, [BP].CB_DestX1 ; Get Dest X1 + SHR AX, 2 ; X1 / 4 = Byte offset + ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1) + + MOV CX, [BP].CB_Width ; CX = Width of Image (Bands) + DEC CX ; CX = 1? + JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band + + MOV BX, [BP].CB_X1 ; Get Source X1 + AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?) + JZ @CB_Check_Right ; if so, check right alignment + JNZ @CB_Left_Band ; not aligned? well.. + +@CB_Abort: + CLR AX ; Return False (Failure) + JMP @CB_Exit ; and Finish Up + + ; Copy when Left & Right Clip Masks overlap... + +@CB_Only_One_Band: + MOV BX, [BP].CB_X1 ; Get Left Clip Mask + AND BX, PLANE_BITS ; Mask out Row # + MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask + MOV BX, [BP].CB_X2 ; Get Right Clip Mask + AND BX, PLANE_BITS ; Mask out Row # + AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + +@CB_One_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_One_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_One_Loop ; Loop until Finished + +@CB_One_Done: + JMP @CB_Finish ; Outa Here! + + ; Copy Left Edge of Bitmap + +@CB_Left_Band: + + OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask + + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + +@CB_Left_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Left_Loop ; Loop until Finished + +@CB_Left_Done: + INC DI ; Move Dest Over 1 band + INC SI ; Move Source Over 1 band + DEC [BP].CB_Width ; Band Width-- + + ; Determine if Right Edge of Bitmap needs special copy + +@CB_Check_Right: + MOV BX, [BP].CB_X2 ; Get Source X2 + AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?) + CMP BL, 03h ; Plane = 3? + JE @CB_Copy_Middle ; Copy the Middle then! + + ; Copy Right Edge of Bitmap + +@CB_Right_Band: + + OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask + + DEC [BP].CB_Width ; Band Width-- + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + MOV BX, [BP].CB_Width ; BX = Offset to Right Edge + +@CB_Right_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Right_Loop ; Loop until Finished + +@CB_Right_Done: + + ; Copy the Main Block of the Bitmap + +@CB_Copy_Middle: + + MOV CX, [BP].CB_Width ; Get Width Remaining + JCXZ @CB_Finish ; Exit if Done + + OUT_8 SC_Data, ALL_PLANES ; Copy all Planes + + MOV DX, SCREEN_WIDTH ; Get Width of Screen minus + SUB DX, CX ; Image width (for Adjustment) + MOV AX, [BP].CB_Height ; AX = # of Lines to Copy + MOV BX, CX ; BX = Quick REP reload count + MOV CX, ES ; Move VGA Segment + MOV DS, CX ; Into DS + + ; Actual Copy Loop. REP MOVSB does the work + +@CB_Middle_Copy: + MOV CX, BX ; Recharge Rep Count + REP MOVSB ; Move Bands + LOOPjz AX, @CB_Finish ; Exit Loop if Finished + + ADD SI, DX ; Adjust DS:SI to Next Line + ADD DI, DX ; Adjust ES:DI to Next Line + + MOV CX, BX ; Recharge Rep Count + REP MOVSB ; Move Bands + + ADD SI, DX ; Adjust DS:SI to Next Line + ADD DI, DX ; Adjust ES:DI to Next Line + LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done + +@CB_Finish: + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on + +@CB_Exit: + ADD SP, 04 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 16 ; Exit and Clean up Stack + +COPY_BITMAP ENDP + + END ; End of Code Segment diff --git a/16/lib/modex105/DEMOS/C/MODEX.BI b/16/lib/modex105/DEMOS/C/MODEX.BI new file mode 100644 index 00000000..6b1d7afe --- /dev/null +++ b/16/lib/modex105/DEMOS/C/MODEX.BI @@ -0,0 +1,63 @@ + + ' ===== SCREEN RESOLUTIONS ===== + +CONST Mode320x200 = 0, Mode320x400 = 1 +CONST Mode360x200 = 2, Mode360x400 = 3 +CONST Mode320x240 = 4, Mode320x480 = 5 +CONST Mode360x240 = 6, Mode360x480 = 7 + + ' ===== MODE X SETUP ROUTINES ===== + +DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%) +DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%) + + ' ===== BASIC GRAPHICS PRIMITIVES ===== + +DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%) +DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%) +DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%) +DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) +DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) + + ' ===== DAC COLOR REGISTER ROUTINES ===== + +DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%) +DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%) +DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) +DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%) + + + ' ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE" +DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE" +DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%) +DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" () +DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" () +DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY" + + ' ===== TEXT DISPLAY ROUTINES ===== + +DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%) + + ' ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) +DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) + + ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%) +DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%) + + + + + + diff --git a/16/lib/modex105/DEMOS/C/MODEX.H b/16/lib/modex105/DEMOS/C/MODEX.H new file mode 100644 index 00000000..7de25a63 --- /dev/null +++ b/16/lib/modex105/DEMOS/C/MODEX.H @@ -0,0 +1,76 @@ + +#ifndef __MODEX_H +#define __MODEX_H + + /* ===== SCREEN RESOLUTIONS ===== */ + +#define Mode_320x200 0 +#define Mode_320x400 1 +#define Mode_360x200 2 +#define Mode_360x400 3 +#define Mode_320x240 4 +#define Mode_320x480 5 +#define Mode_360x240 6 +#define Mode_360x480 7 + + /* ===== MODE X SETUP ROUTINES ===== */ + +int far pascal set_vga_modex (int Mode, int MaxXpos, int MaxYpos, int Pages); +int far pascal set_modex (int Mode); + + /* ===== BASIC GRAPHICS PRIMITIVES ===== */ + +void far pascal clear_vga_screen (int Color); +void far pascal set_point (int Xpos, int Ypos, int Color); +int far pascal read_point (int Xpos, int Ypos); +void far pascal fill_block (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); +void far pascal draw_line (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); + + /* ===== DAC COLOR REGISTER ROUTINES ===== */ + +void far pascal set_dac_register (int RegNo, int Red, int Green, int Blue); +void far pascal get_dac_register (int RegNo, int* Red, int* Green, int* Blue); +void far pascal load_dac_registers (char far *PalData, int StartReg, + int EndReg, int VSync); +void far pascal readd_dac_registers (char far *PalData, int StartReg, + int EndReg); + + /* ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== */ + +void far pascal set_active_page (int PageNo); +int far pascal get_active_page (void); +void far pascal set_display_page (int PageNo); +int far pascal get_display_page (void); +void far pascal set_window (int DisplayPage, int XOffset, int YOffset); +int far pascal get_x_offset (void); +int far pascal get_y_offset (void); +void far pascal sync_display (void); + + /* ===== TEXT DISPLAY ROUTINES ===== */ + +void far pascal gprintc (int CharNum, int Xpos, int Ypos, int ColorF, + int ColorB); +void far pascal tgprintc (int CharNum, int Xpos, int Ypos, int ColorF); +void far pascal print_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF, int ColorB); +void far pascal tprint_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF); +void far pascal set_display_font (char far *FontData, int FontNumber); + + /* ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== */ + +void far pascal draw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); +void far pascal tdraw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); + + /* ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== */ + +void far pascal copy_page (int SourcePage, int DestPage); +void far pascal copy_bitmap (int SourcePage, int X1, int Y1, int X2, int Y2, + int DestPage, int DestX1, int DestY1); + + +#endif diff --git a/16/lib/modex105/DEMOS/C/MODEX.OBJ b/16/lib/modex105/DEMOS/C/MODEX.OBJ new file mode 100644 index 00000000..80b311d6 Binary files /dev/null and b/16/lib/modex105/DEMOS/C/MODEX.OBJ differ diff --git a/16/lib/modex105/DEMOS/C/UTLS-ASM.BAT b/16/lib/modex105/DEMOS/C/UTLS-ASM.BAT new file mode 100644 index 00000000..d996978f --- /dev/null +++ b/16/lib/modex105/DEMOS/C/UTLS-ASM.BAT @@ -0,0 +1 @@ +MASM c_utils, c_utils, c_utils, nul; \ No newline at end of file diff --git a/16/lib/modex105/DEMOS/C/X-DEMO.C b/16/lib/modex105/DEMOS/C/X-DEMO.C new file mode 100644 index 00000000..a5ac59b1 --- /dev/null +++ b/16/lib/modex105/DEMOS/C/X-DEMO.C @@ -0,0 +1,780 @@ +/* X-DEMO.C - a Mode "X" Demo */ +/* By Matt Pritchard, 14 Apr, 1993 */ + +#include +#include + +#include "modex.h" +#include "c_utils.h" + +#define MAX_SHAPES 32 +#define MAX_SPRITES 64 + + /* routines in this file */ + +void demo_res (int, int, int); +int get_key (void); +void error_out (char*); +void load_shapes (void); +int int_sqrt (int, int); +void page_demo (void); + + /* Structures for Sprites */ + +struct Shape +{ + unsigned char Image[512]; + int X_Width; + int Y_Width; +} Img [MAX_SHAPES]; + +struct Sprite +{ + int X_pos; + int Y_pos; + int X_Dir; + int Y_Dir; + int Shape; + int Last_X [2]; + int Last_Y [2]; +} Obj [MAX_SPRITES]; + + + /* MAIN */ + + +int main(int argc, char *argv[]) +{ + + /* if (argc > 0) + { + while (argc > 0) + { + dos_print ("Unknown Argument: "); + dos_print (makefp argv[argc]); + argc--; + } + return (0); + + } + */ + + init_random (); + + load_shapes (); + + demo_res ( Mode_320x200, 320, 200 ); + demo_res ( Mode_320x400, 320, 400 ); + + demo_res ( Mode_360x200, 360, 200 ); + demo_res ( Mode_360x400, 360, 400 ); + + demo_res ( Mode_320x240, 320, 240 ); + demo_res ( Mode_320x480, 320, 480 ); + + demo_res ( Mode_360x240, 360, 240 ); + demo_res ( Mode_360x480, 360, 480 ); + + page_demo (); + + set_video_mode (3); + dos_print ("This Mode X Demo is Finished"); + return (0); + +} + + + /* Demonstrate a given resolution */ + + +void demo_res (int Screen_Mode, int X_max, int Y_max) +{ + +char *Error1 = "Failure while calling SET_MODEX"; +char *Error2 = "Failure during READ_PIXEL test"; + +char *Abort_Msg = "Demo aborted by User"; + +char *Demo_Msg = " This is a MODE X demo "; +char *Scrn_Msg = "Screen Resolution is by "; +char *Cont_Msg = "Press to Continue"; + +char *Line_Msg = "LINE TEST"; +char *Fill_Msg = "FILL TEST"; +char *Pixel_Msg = "PIXEL TEST"; + +char Text[10]; + +int x1, y1, x2, y2 = 0; +int x, y, z = 0; +int X_Center, gap = 0; + + + if (set_modex (Screen_Mode) == 0) + { + error_out (Error1); + } + + X_Center = X_max / 2; + + x1 = 10; + y1 = 10; + x2 = X_max - 1; + y2 = Y_max - 1; + + for (z = 0; z <= 3; z++) + { + y = 31 - z -z; + draw_line (x1+z, y1+z, x2-z, y1+z, y); + draw_line (x1+z, y1+z, x1+z, y2-z, y); + draw_line (x1+z, y2-z, x2-z, y2-z, y); + draw_line (x2-z, y1+z, x2-z, y2-z, y); + } + + for (x = 0; x < (X_max / 10); x++) + { + tgprintc (48 + ((x+1) % 10), x*10+1, 1, 9 + ((x/8) % 7) ); + draw_line (x*10+9, 0, x*10+9, 3, c_bWHITE); + } + + for (y = 0; y < (Y_max / 10); y++) + { + tgprintc (48 + ((y+1) % 10), 1, y*10+1, 9 + ((y/10) % 7) ); + draw_line (0, y*10+9, 3, y*10+9, c_bWHITE); + } + + for (x = 0; x <= 63; x++) + { + z = 15 + (x * 3 / 4); + set_dac_register (64+x, z, z, z); + set_dac_register (128+x, 0, z, z); + + draw_line (103-x, 60, 40+x, 123, 64+x); + draw_line (40, 60+x, 103, 123-x, 128+x); + + } + + tprint_str (Line_Msg, 9, 37, 130, c_BLUE); + + y = 60; + gap = 0; + for (x = 0; x <= 9; x++) + { + fill_block (120, y, 120+x, y+gap, 64+x); + fill_block (140 - (15-x), y, 150+x, y+gap, 230+x); + fill_block (170 - (15-x), y, 170, y+gap, 128+x); + y = y + gap + 2; + gap++; + } + + tprint_str (Fill_Msg, 9, 110, 46, c_GREEN); + + for (x = 190; x <= 250; x+=2) + { + for (y = 60; y <= 122; y+=2) + { + z = (x+x+y+y) & 0xff; + set_point (x, y, z); + } + } + + tprint_str (Pixel_Msg, 10, 182, 130, c_RED); + + for (x = 190; x <= 250; x+=2) + { + for (y = 60; y <= 122; y+=2) + { + z = (x+x+y+y) & 0xff; + if (read_point(x, y) != z) + { + error_out (Error2); + } + } + } + + print_str (Demo_Msg, 23, X_Center - 92, 20, c_bRED, c_BLUE); + + x = X_Center - 124; + print_str (Scrn_Msg, 28, x, 30, c_bGREEN, c_BLACK); + + sprintf (Text, "%3d", X_max); + print_str (Text, 3, x+168, 30, c_bPURPLE, c_BLACK); + + sprintf (Text, "%3d", Y_max); + print_str (Text, 3, x + 224, 30, c_bWHITE, c_BLACK); + + for (x = 0; x <= 15; x++) + { + set_dac_register (230+x, 63-x*4, 0, 15+x*3); + draw_line (30+x, Y_max-6-x, X_max-20-x, Y_max-6-x, 230+x); + } + + tprint_str (Cont_Msg, 27, X_Center - 103, Y_max-18, c_YELLOW); + + if (get_key () == Ky_ESC) + { + error_out (Abort_Msg); + } + + return ; + +} + + + /* Wait for a Keystroke */ + + +int get_key(void) +{ + +int c = 0; + + while (c == 0) + { + c = scan_keyboard (); + } + + return (c); + +} + + + /* Error Handling Routine */ + + +void error_out (char * text) +{ + + set_video_mode (3); + dos_print (text); + exit (EXIT_SUCCESS); + +} + + + /* Routine to generate random sprites */ + + +void load_shapes () +{ + +unsigned char Grid[33][33]; + +char *Error1 = "Bad Shape Selected Error"; + +int Shape; +int x, y, z; +int Style, Color; +int X_Width, Y_Width, Center, S_Width; +int Hollow_X, Hollow_Y; + + for (Shape = 0; Shape < MAX_SHAPES; Shape++) + { + for (y = 0; y <= 32; y++) + { + for (x = 0; x <= 32; x++) + { + Grid[x][y] = c_BLACK; + } + } + + Style = random_int (6); + Color = 1 + random_int (15); + + switch (Style) + + { + /* SOLID BOXES */ + + case 0: + + { + do + { + X_Width = 3 + random_int(30); + Y_Width = 3 + random_int(30); + + } while ( (X_Width * Y_Width) >= 512); + + for (x = 1; x <= X_Width; x++) + { + for (y = 1; y <= Y_Width; y++) + { + Grid[x][y] = Color; + } + } + + break; + + } + /* HOLLOW BOXES */ + + case 1: + + { + do { + X_Width = 6 + random_int(27); + Y_Width = 6 + random_int(27); + } while ( (X_Width * Y_Width) >= 512); + + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + Grid[x][y] = Color; + } + } + + Hollow_X = 1 + random_int ((X_Width / 2) -1); + Hollow_Y = 1 + random_int ((Y_Width / 2) -1); + + for (y = Hollow_Y+1; y <= Y_Width-Hollow_Y; y++) + { + for (x = Hollow_X+1; x <= X_Width-Hollow_X; x++) + { + Grid[x][y] = c_BLACK; + } + } + + break; + + } + + /* SOLID DIAMOND */ + + case 2: + + { + + X_Width = 3 + 2 * random_int(10); + Y_Width = X_Width; + Center = X_Width / 2; + + for (y = 0; y <= Center; y++) + { + for (x = 0; x <= y; x++) + { + Grid [Center-x+1][y+1] = Color; + Grid [Center+x+1][y+1] = Color; + Grid [Center-x+1][Y_Width-y] = Color; + Grid [Center+x+1][Y_Width-y] = Color; + } + } + + break; + + } + + /* HOLLOW DIAMOND */ + + case 3: + + { + + X_Width = 3 + 2 * random_int(10); + Y_Width = X_Width; + Center = X_Width / 2; + S_Width = random_int (Center); + + for (y = 0; y <= Center; y++) + { + for (x = 0; x <= y; x++) + { + if ( x+(Center-y) >= S_Width ) + { + Grid [Center-x+1][y+1] = Color; + Grid [Center+x+1][y+1] = Color; + Grid [Center-x+1][Y_Width-y] = Color; + Grid [Center+x+1][Y_Width-y] = Color; + } + } + } + + break; + + } + + /* BALL */ + + case 4: + + { + + X_Width = 7 + 2 * random_int (8); + Y_Width = X_Width; + Center = 1 + X_Width / 2; + + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + z = int_sqrt(Center-x, Center-y); + if (z < Center) + { + Grid[x][y] = 150 + Color * 2 + z * 3; + } + } + } + + break; + } + + /* HOLLOW BALLS */ + + case 5: + + { + X_Width = 7 + 2 * random_int (8); + Y_Width = X_Width; + Center = 1 + X_Width / 2; + S_Width = random_int (X_Width); + + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + z = int_sqrt(Center-x, Center-y); + if ( (z < Center) && (z >= S_Width) ) + { + Grid[x][y] = 150 + Color * 2 + z * 3; + } + } + } + + + break; + } + + default: + + { + error_out (Error1); + break; + + } + + } + + z = 0; + for (y = 1; y <= Y_Width; y++) + { + for (x = 1; x <= X_Width; x++) + { + Img[Shape].Image[z] = Grid[x][y]; + z++; + } + } + + Img[Shape].X_Width = X_Width; + Img[Shape].Y_Width = Y_Width; + + } + + return; +} + + + /* Quickie Psuedo Integer Square Root Routine */ + + +int int_sqrt ( int x, int y ) +{ + +int Sqr_Table[12] = {1, 4, 9, 6, 25, 36, 49, 64, 81, 100, 121, 144}; + +int r, d; + + d = (x * x) + (y * y); + r = 0; + + while ( d >= Sqr_Table[r] ) + { + r++; + } + + return (r); + +} + + + /* The Bit Sprite Demo */ + + +void page_demo () +{ + +char *Error1 = "Failure during SET_VGA_MODEX (0, 360, 240, 3) call"; + +int Last_Objects[2], Visible_Objects; + +int Screen_X = 360; +int Screen_Y = 240; + +int x, y, z; +int c, dc; +int x1, y1, x2, y2; + +int Sprite_X, Sprite_Y; +int Current_Page; +int New_X, New_Y; + +int View_X, View_Y, View_Max, View_Cnt, View_XD, View_YD; +int Set_Color, Prev_Color, S_Dir, P_Dir; + +int Demo_Running = True; +int redo, code; + + if (set_vga_modex(Mode_320x200, Screen_X, Screen_Y, 3) == 0) + { + error_out (Error1); + } + + set_active_page (0); + clear_vga_screen (c_BLACK); + + print_str ("This is a Test of the Following Functions:", 99, 10, 9, c_bWHITE, c_BLACK); + + draw_line (10, 18, 350, 18, c_YELLOW); + print_str ("SET_ACTIVE_PAGE", 99, 10, 20, c_bBLUE, c_BLACK); + print_str ("SET_DISPLAY_PAGE", 99, 10, 30, c_GREEN, c_BLACK); + print_str ("SET_DAC_REGISTER", 99, 10, 40, c_RED, c_BLACK); + print_str ("CLEAR_VGA_SCREEN", 99, 10, 50, c_CYAN, c_BLACK); + + print_str ("TDRAW_BITMAP", 99, 10, 60, c_PURPLE, c_BLACK); + print_str ("COPY_PAGE", 99, 10, 70, c_GREEN, c_BLACK); + print_str ("COPY_BITMAP", 99, 10, 80, c_CYAN, c_BLACK); + + print_str ("GPRINTC", 99, 10, 90, c_BLUE, c_BLACK); + print_str ("TGPRINTC", 99, 10, 100, c_GREEN, c_BLACK); + print_str ("SET_WINDOW", 99, 10, 110, c_RED, c_BLACK); + + print_str ("VIRTUAL SCREEN SIZES", 20, 190, 20, c_bBLUE, c_BLACK); + print_str (" SMOOTH SCROLLING", 20, 190, 30, c_GREEN, c_BLACK); + print_str (" SPRITE ANIMATION", 20, 190, 40, c_CYAN, c_BLACK); + print_str (" PAGE FLIPPING", 20, 190, 50, c_RED, c_BLACK); + print_str (" COLOR CYCLING", 20, 190, 60, c_PURPLE, c_BLACK); + + for (x = 0; x <=60; x++) + { + set_dac_register (50 + x, 3 + x, 0, 60 - x); + set_dac_register (150 + x, 3 + x, 0, 60 - x); + } + + c = 0; + dc = 1; + for (x = 0; x <= (Screen_X / 2); x++) + { + draw_line (Screen_X / 2 - 1, Screen_Y / 4, x, Screen_Y - 1, c + 50); + draw_line (Screen_X / 2, Screen_Y / 4, Screen_X - x - 1, Screen_Y - 1, c + 50); + c+= dc; + if ((c == 0) || (c == 60) ) { dc = -dc;} + } + + tprint_str ("Press to Continue", 99, 72, 190, c_bWHITE); + tprint_str ("< > = Faster < > = Slower", 99, 72, 204, c_bGREEN); + tprint_str ("< > = Fewer Shapes < > = More Shapes", 99, 32, 218, c_bCYAN); + + tgprintc (43, 80, 204, c_YELLOW); + tgprintc (45, 200, 204, c_YELLOW); + + tgprintc (25, 40, 218, c_YELLOW); + tgprintc (24, 200, 218, c_YELLOW); + + copy_page (0, 1); + copy_page (0, 2); + + for (x = 0; x < MAX_SPRITES; x++) + { + do { + Obj[x].X_Dir = random_int(7) - 3; + Obj[x].Y_Dir = random_int(7) - 3; + } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) ); + + Obj[x].Shape = x % MAX_SHAPES; + + Sprite_X = Img[Obj[x].Shape].X_Width; + Sprite_Y = Img[Obj[x].Shape].Y_Width; + + Obj[x].X_pos = 1 + random_int(Screen_X - Sprite_X - 2); + Obj[x].Y_pos = 1 + random_int(Screen_Y - Sprite_Y - 2); + + Obj[x].Last_X[0] = Obj[x].X_pos; + Obj[x].Last_X[1] = Obj[x].X_pos; + Obj[x].Last_Y[0] = Obj[x].Y_pos; + Obj[x].Last_Y[1] = Obj[x].Y_pos; + + } + + Current_Page = 0; + + View_X = 0; + View_Y = 0; + View_Max = 3; + View_Cnt = 0; + View_XD = 1; + View_YD = 1; + + Set_Color = 3; + S_Dir = 1; + Prev_Color = 0; + P_Dir = 1; + + Visible_Objects = MAX_SPRITES / 2; + Last_Objects[0] = 0; + Last_Objects[1] = 0; + + while (Demo_Running) + { + + set_active_page (Current_Page); + + /* Erase Old Images */ + + for (x = 0; x <= Last_Objects[Current_Page]; x++) + { + z = 2; + y = Obj[x].Shape; + x1 = Obj[x].Last_X[Current_Page]; + y1 = Obj[x].Last_Y[Current_Page]; + x2 = x1 + Img[y].X_Width -1; + y2 = y1 + Img[y].Y_Width -1; + + x1 = x1 & 0xfffc; + x2 = x2 | 0x0003; + + copy_bitmap (z, x1, y1, x2, y2, Current_Page, x1, y1); + } + + /* Draw new images */ + + for (x = 0; x <= Visible_Objects; x++) + { + Sprite_X = Img[Obj[x].Shape].X_Width; + Sprite_Y = Img[Obj[x].Shape].Y_Width; + + /* Move Sprite */ + + do + { + redo = False; + New_X = Obj[x].X_pos + Obj[x].X_Dir; + + if (( New_X < 0 ) || (New_X + Sprite_X > Screen_X) ) + { + Obj[x].X_Dir = -Obj[x].X_Dir; + if (random_int(20) == 1) + { + do + { + Obj[x].X_Dir = random_int(7) - 3; + Obj[x].Y_Dir = random_int(7) - 3; + } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) ); + redo = True; + } + } + } while (redo); + Obj[x].X_pos = Obj[x].X_pos + Obj[x].X_Dir; + + + do + { + redo = False; + New_Y = Obj[x].Y_pos + Obj[x].Y_Dir; + + if ( (New_Y < 0) || (New_Y + Sprite_Y > Screen_Y) ) + { + Obj[x].Y_Dir = -Obj[x].Y_Dir; + if (random_int(20) == 1) + { + do + { + Obj[x].X_Dir = random_int(7) - 3; + Obj[x].Y_Dir = random_int(7) - 3; + } while ( (Obj[x].X_Dir == 0) && (Obj[x].Y_Dir == 0) ); + redo = True; + } + } + } while (redo); + + Obj[x].Y_pos = Obj[x].Y_pos + Obj[x].Y_Dir; + + /* Draw Sprite */ + + tdraw_bitmap ((char far*) &Img[Obj[x].Shape], Obj[x].X_pos, Obj[x].Y_pos, Sprite_X, Sprite_Y); + + Obj[x].Last_X[Current_Page] = Obj[x].X_pos; + Obj[x].Last_Y[Current_Page] = Obj[x].Y_pos; + + } + + Last_Objects[Current_Page] = Visible_Objects; + + + /* Pan Screen Back & Forth */ + + View_Cnt++; + if (View_Cnt >= View_Max) + { + View_X+= View_XD; + if ( (View_X == 0) || (View_X == 39) ) {View_XD = -View_XD;} + if (View_XD < 0) + { + View_Y+= View_YD; + if ( (View_Y == 0) || (View_Y == 39) ) {View_YD = -View_YD;} + } + + set_window (Current_Page, View_X, View_Y); + + View_Cnt = 0; + } + else + { + set_display_page (Current_Page); + } + + /* Cycle Colors */ + + set_dac_register (50 + Prev_Color, 3 + Prev_Color, 0, 60 - Prev_Color); + set_dac_register (50 + Set_Color, Set_Color, 10, 63 - Set_Color); + + set_dac_register (150 + Prev_Color, 3 + Prev_Color, 0, 60 - Prev_Color); + set_dac_register (150 + Set_Color, 63, 63, Set_Color); + + Set_Color+= S_Dir; + if ( (Set_Color == 60) || (Set_Color == 0) ) {S_Dir = -S_Dir;} + + Prev_Color+= P_Dir; + if ( (Prev_Color == 60) || (Prev_Color == 0) ) {P_Dir = -P_Dir;} + + /* Check for Keystroke */ + + Current_Page = Current_Page ^ 0x01; + + code = scan_keyboard (); + + if (code == Ky_ESC) {Demo_Running = False;} + + if (code == Ky_Plus) + { + if (View_Max < 12) {View_Max++;} + } + + if (code == Ky_Minus) + { + if (View_Max > 1) {View_Max--;} + if (View_Cnt >= View_Max) {View_Cnt = 0;} + } + + if (code == Ky_Up) + { + if (Visible_Objects < MAX_SPRITES-1) {Visible_Objects++;} + } + + if (code == Ky_Down) + { + if (Visible_Objects > 0) {Visible_Objects--;} + } + + } + +} diff --git a/16/lib/modex105/DEMOS/C/X-DEMO.EXE b/16/lib/modex105/DEMOS/C/X-DEMO.EXE new file mode 100644 index 00000000..7742d145 Binary files /dev/null and b/16/lib/modex105/DEMOS/C/X-DEMO.EXE differ diff --git a/16/lib/modex105/DEMOS/C/X-DEMO.OBJ b/16/lib/modex105/DEMOS/C/X-DEMO.OBJ new file mode 100644 index 00000000..2ae83ee9 Binary files /dev/null and b/16/lib/modex105/DEMOS/C/X-DEMO.OBJ differ diff --git a/16/lib/modex105/DEMOS/C/X-DEMO.PRJ b/16/lib/modex105/DEMOS/C/X-DEMO.PRJ new file mode 100644 index 00000000..7bc4a069 Binary files /dev/null and b/16/lib/modex105/DEMOS/C/X-DEMO.PRJ differ diff --git a/16/lib/modex105/DEMOS/C/x.exe b/16/lib/modex105/DEMOS/C/x.exe new file mode 100644 index 00000000..7742d145 Binary files /dev/null and b/16/lib/modex105/DEMOS/C/x.exe differ diff --git a/16/lib/modex105/DEMOS/CHARDEMO.EXE b/16/lib/modex105/DEMOS/CHARDEMO.EXE new file mode 100644 index 00000000..4015bdf1 Binary files /dev/null and b/16/lib/modex105/DEMOS/CHARDEMO.EXE differ diff --git a/16/lib/modex105/DEMOS/PASCAL/TEST5.PAS b/16/lib/modex105/DEMOS/PASCAL/TEST5.PAS new file mode 100644 index 00000000..7cc56bbb --- /dev/null +++ b/16/lib/modex105/DEMOS/PASCAL/TEST5.PAS @@ -0,0 +1,488 @@ +{ ModeX Turbo Pascal Demo Program } +{ Converted to Turbo Pascal by Scott Wyatt } +{ Original program written in QuickBasic by Matt Prichard } +{ Released to the Public Domain } +{ } +{ Thanks to Matt Prichard for his *EXCELLENT* ModeX Library } +{ Additional Comments by Matt Pritchard } + +Uses Crt; + +{$L modex2.obj} { This file is the external ModeX Library .OBJ } +{$F+} + + { Mode Setting Routines } + +Function SET_VGA_MODEX (Mode,MaxXpos,MaxYpos,Pages : integer) : integer; external; +Function SET_MODEX (Mode:integer) : Integer; external; + + { Graphics Primitives } + +Procedure CLEAR_VGA_SCREEN (Color:integer); external; +Procedure SET_POINT (Xpos,Ypos,Color : integer); external; +Function READ_POINT (Xpos,Ypos:integer) : integer; external; +Procedure FILL_BLOCK (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external; +Procedure DRAW_LINE (Xpos1,Ypos1,Xpos2,Ypos2,Color:integer); external; + + { VGA DAC Routines } + +Procedure SET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external; +Procedure GET_DAC_REGISTER (RegNo,Red,Green,Blue:integer); external; + + { Page and Window Control Routines } + +Procedure SET_ACTIVE_PAGE (PageNo:integer); external; +Function GET_ACTIVE_PAGE : integer; external; +Procedure SET_DISPLAY_PAGE (PageNo:integer); external; +Function GET_DISPLAY_PAGE : integer; external; +Procedure SET_WINDOW (DisplayPage,XOffset,YOffset : integer); external; +Function GET_X_OFFSET : integer; external; +Function GET_Y_OFFSET : integer; external; +Procedure SYNC_DISPLAY; external; + + { Text Display Routines } + +Procedure GPRINTC (CharNum,Xpos,Ypos,ColorF,ColorB:integer); external; +Procedure TGPRINTC ( CharNum,Xpos,Ypos,ColorF : integer); external; +Procedure PRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF,ColorB:integer); external; +Procedure TPRINT_STR (Var Text;MaxLen,Xpos,Ypos,ColorF:integer); external; +Procedure SET_DISPLAY_FONT (Var FontData;FontNumber:integer); external; + + { Sprite and VGA memory -> Vga memory Copy Routines } + +Procedure DRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external; +Procedure TDRAW_BITMAP (Var Image;Xpos,Ypos,Width,Height:integer); external; +Procedure COPY_PAGE (SourcePage,DestPage:integer); external; +Procedure COPY_BITMAP (SourcePage,X1,Y1,X2,Y2,DestPage,DestX1,DestY1:integer); external; + +{$F-} + + +TYPE Sprite = Record + Xpos : INTEGER; + Ypos : INTEGER; + XDir : INTEGER; + YDir : INTEGER; + Shape : INTEGER; + LastX : INTEGER; + LastY : INTEGER; + END; + + +CONST MaxShapes = 32; + Circle_16 : Array[1..16,1..16] of byte = + (( 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0), + ( 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0), + ( 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0), + ( 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0), + ( 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0), + ( 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20), + ( 0, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 0), + ( 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0), + ( 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0), + ( 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0), + ( 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0), + ( 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0)); + Square_16 : Array[1..16,1..16] of byte = + (( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21), + ( 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21)); + Diamond : Array[1..8,1..8] of byte = + (( 0, 0, 0, 22, 22, 0, 0, 0), + ( 0, 0, 22, 22, 22, 22, 0, 0), + ( 0, 22, 22, 0, 0, 22, 22, 0), + ( 22, 22, 0, 0, 0, 0, 22, 22), + ( 22, 22, 0, 0, 0, 0, 22, 22), + ( 0, 22, 22, 0, 0, 22, 22, 0), + ( 0, 0, 22, 22, 22, 22, 0, 0), + ( 0, 0, 0, 22, 22, 0, 0, 0)); + Rectangle : Array[1..8,1..3] of byte = + (( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23), + ( 23, 23, 23)); + + { Global Variables ? } + +Var + XCenter,X1,Y1,X2,Y2,Z,Colr,XChars,YChars,X,Y,N,Gap : Integer; + s : string; + s1 : Array[1..35] of Char; + ch : Char; + obj : Array[1..64] of Sprite; + ScreenX,ScreenY : Integer; + c, dc, SpriteX, SpriteY, CurrentPage, LastPage : Integer; + SetColor, SDir, PrevColor, PDir : Byte; + XView, YView : Integer; + XView_Change, YView_Change : Integer; + Right : Boolean; + Number_Of_Shapes : Byte; + + + { Error Handler - Returns to Text Mode & Displays Error } + +Procedure ERROR_OUT(s : string); + Begin + asm + mov ah,0 + mov al,3 + int 10h + end; + WriteLn(s); + Halt(0); +END; + + { Routine to Print a PASCAL string using Print_Str } + +Procedure Print_Text(s : string; X,Y,BColor,FColor : integer); +Var + s1 : Array[1..135] of Char; + i : byte; +Begin + For i := 1 to Length(s) DO + s1[i] := s[i]; + Print_Str(s1,Length(s),X,Y,BColor,FColor); +End; + + { Routine to Transparently Print a PASCAL string using TPrint_Str } + +Procedure TPrint_Text(s : string; X,Y,Color : integer); +Var + s1 : Array[1..135] of Char; + i : byte; +Begin + For i := 1 to Length(s) DO + s1[i] := s[i]; + TPrint_Str(s1,Length(s),X,Y,Color); +End; + + { Routines to show test patterns for a given mode } + +Procedure Demo_Res(Mode, Xmax, Ymax : integer); +Begin + + Str(mode,s); + If Set_ModeX(Mode) = 0 Then + Error_Out('Unable to SET_MODEX '+s); + Clear_VGA_Screen(0); + + XCenter := Xmax div 2; + X1 := 10; + Y1 := 10; + X2 := Xmax - 1; + Y2 := Ymax - 1; + + FOR Z := 0 TO 3 DO + Begin + Colr := 31 - Z * 2; + Draw_Line(X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr); + Draw_Line(X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr); + Draw_Line(X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr); + Draw_Line(X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr); + End; + + XChars := Xmax div 10; + YChars := Ymax div 10; + + FOR X := 0 TO XChars - 1 DO + Begin + TGPRINTC(48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X div 8) MOD 7)); + DRAW_LINE(X * 10 + 9, 0, X * 10 + 9, 3, 15); + End; + FOR Y := 0 TO YChars - 1 DO + Begin + TGPRINTC(48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y div 10) MOD 7)); + DRAW_LINE(0, Y * 10 + 9, 3, Y * 10 + 9, 15); + End; + + { Test Line Drawing } + + FOR X := 0 TO 63 DO + Begin + N := 15 + ((X * 3) div 4); + SET_DAC_REGISTER(64 + X, N, N, N); + SET_DAC_REGISTER(128 + X, 0, N, N); + DRAW_LINE(103 - X, 60, 40 + X, 123, 64 + X); + DRAW_LINE(40, 60 + X, 103, 123 - X, 128 + X); + End; + s := 'Line Test'; + PRINT_Text(s,37,130,1,0); + + { Test Block Fills } + + Y := 60; + Gap := 0; + FOR X := 0 TO 9 DO + Begin + FILL_BLOCK(120, Y, 120 + X, Y + Gap, 64 + X); + FILL_BLOCK(140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X); + FILL_BLOCK(170 - (15 - X), Y, 170, Y + Gap, 128 + X); + Y := Y + Gap + 2; + Gap := Gap + 1; + End; + s := 'Fill Test'; + Print_Text(s,110, 46, 2,0); + + { Test Pixel Write and Read } + + FOR X := 190 TO 250 DO + FOR Y := 60 TO 122 DO + SET_POINT( X, Y, X + Y + X + Y); + + s := 'Pixel Test'; + Print_Text(s,182, 130, 3,0); + + FOR X := 190 TO 250 DO + FOR Y := 60 TO 122 DO + IF READ_POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN + WriteLn('READ_PIXEL Failure'); + + { Display rest of screen } + + s := ' This is a MODE X demo '; + Print_Text(s,XCenter - (Length(s) * 4), 20, 3, 1); + s := 'Screen Resolution is by '; + X := XCenter - (Length(s) * 4); + Print_Text(s,X,30,4,0); + Str(XMax,s); + Print_Text(s, X + 8 * 21, 30, 8, 0); + Str(YMax,s); + Print_Text(s, X + 8 * 28, 30, 15, 0); + + FOR X := 0 TO 15 DO + Begin + SET_DAC_REGISTER( 230 + X, 63 - X * 4, 0, 15 + X * 3); + DRAW_LINE(30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X); + End; + s := 'Press to Continue'; + For x := 1 to length(s) DO + s1[x] := s[x]; + TPrint_Str(s1, length(s), XCenter - (26 * 4), Ymax - 18, 5); + + Ch := ReadKey; + IF Ch = #27 Then + Error_Out('Abort'); + +End; + + + { Initialize Sprites for Sprite Demo } + +Procedure Init_Sprites; +Var i : byte; +Begin + For i := 1 to 64 DO + Begin + Obj[i].XPos := Random(300)+10; + Obj[i].YPos := Random(200)+20; + Obj[i].XDir := Random(10)-5; + Obj[i].YDir := Random(10)-5; + If (Obj[i].XDir = 0) AND (Obj[i].YDir = 0) Then + Begin + Obj[i].XDir := Random(5) + 1; + Obj[i].YDir := Random(5) + 1; + End; + Obj[i].Shape := Random(4)+1; + Obj[i].LastX := obj[i].XPos; + Obj[i].LastY := obj[i].YPos; + End; +End; + +Procedure Set_Sprites(number : byte); +Var i : Byte; +Begin + For i := 1 to number DO + Begin + obj[i].LastX := obj[i].XPos; + obj[i].LastY := obj[i].YPos; + obj[i].XPos := obj[i].XPos + obj[i].XDir; + obj[i].YPos := obj[i].YPos + obj[i].YDir; + If (obj[i].XPos > 335) OR (obj[i].XPos < 5 ) Then + obj[i].XDir := -(obj[i].XDir); + If (obj[i].YPos > 220) OR (obj[i].YPos < 5) Then + obj[i].YDir := -(obj[i].YDir); + End; + For i := 1 to number DO + Case obj[i].Shape of + 1 : TDraw_Bitmap(Circle_16,obj[i].XPos,obj[i].YPos,16,16); + 2 : TDraw_Bitmap(Square_16,obj[i].XPos,obj[i].YPos,16,16); + 3 : TDraw_Bitmap(Diamond,obj[i].XPos,obj[i].YPos,8,8); + 4 : TDraw_Bitmap(Rectangle,obj[i].XPos,obj[i].YPos,3,8); + End; +End; + +Procedure Remove_Sprites(p,number : byte); +Var i : byte; +Begin + For i := 1 to number DO + Copy_Bitmap(2,obj[i].LastX,obj[i].LastY,obj[i].LastX+16,obj[i].LastY+16,p,Obj[i].LastX,Obj[i].LastY); +End; + +Procedure Page_Demo; +Begin + Number_Of_Shapes := 64; + XView_Change := 1; + YView_Change := 1; + XView := 1; + YView := 1; + Right := TRUE; + ScreenX := 360; + ScreenY := 240; + PrevColor := 0; + SetColor := 3; + SDir := 1; + PDir := 1; + Str(0,s); + + IF SET_VGA_MODEX(0, ScreenX, ScreenY, 3) = 0 THEN + ERROR_OUT('Unable to SET_VGA_MODEX' + S); + + SET_ACTIVE_PAGE(0); + CLEAR_VGA_SCREEN(0); + PRINT_TEXT('This is a Test of the Following Functions:', 10, 9, 15, 0); + DRAW_LINE( 10, 18, 350, 18, 4); + Print_Text('SET_ACTIVE_PAGE', 10, 20, 1, 0); + Print_Text('SET_DISPLAY_PAGE', 10, 30, 3,0); + Print_Text('SET_DAC_REGISTER', 10, 40, 3, 0); + Print_Text('CLEAR_VGA_SCREEN', 10, 50, 13, 0); + Print_Text('TDRAW_BITMAP', 10, 60, 14, 0); + Print_Text('COPY_PAGE', 10, 70, 3, 0); + Print_Text('COPY_BITMAP', 10, 80, 13, 0); + Print_Text('GPRINTC', 10, 90, 1, 0); + Print_Text('TGPRINTC', 10, 100, 3, 0); + Print_Text('SYNC_DISPLAY', 10, 110, 3, 0); + Print_Text('SET_WINDOW', 10, 120, 14, 0); + Print_Text('VIRTUAL SCREEN SIZES', 190, 20, 1, 0); + Print_Text(' SMOOTH SCROLLING', 190, 30, 3, 0); + Print_Text(' SPRITE ANIMATION', 190, 40, 13, 0); + Print_Text(' PAGE FLIPPING', 190, 50, 3, 0); + Print_Text(' COLOR CYCLING', 190, 60, 14, 0); + + FOR X := 0 TO 60 DO + Begin + SET_DAC_REGISTER( 50 + X, 3 + X, 0, 60 - X); + SET_DAC_REGISTER( 150 + X, 3 + X, 0, 60 - X); + End; + + c := 0; + DC := 1; + FOR X := 0 TO ScreenX div 2 DO + Begin + DRAW_LINE( ScreenX div 2 - 1, ScreenY div 4, X, ScreenY - 1, c + 50); + DRAW_LINE( ScreenX div 2, ScreenY div 4, ScreenX - X - 1, ScreenY - 1, c + 50); + c := c + DC; + IF (c = 0) OR (c = 60) THEN DC := -DC; + End; + + TPrint_Text('Press to Continue', 82, 190, 15); + TPrint_Text('<+> = Fewer Shapes <-> = More Shapes', 32, 204, 12); + COPY_PAGE( 0, 1); + COPY_PAGE( 0, 2); + + Ch := #0; + CurrentPage := 1; + LastPage := 0; + Set_Sprites(Number_Of_Shapes); + For c := 1 to 4 DO + Set_Dac_Register(19+c,63-(c*10),0,0); + + While Ch <> #27 DO + Begin + Set_Active_Page(currentpage); + Set_Sprites(Number_Of_Shapes); + If Right Then + Begin + XView := XView + XView_Change; + If (XView > 38) OR (XView < 2) Then + Begin + XView_Change := -(XView_Change); + Right := FALSE; + End; + End + Else + Begin + YView := YView + YView_Change; + If (YView > 38) OR (YView < 2) Then + Begin + YView_Change := -(YView_Change); + Right := TRUE; + End; + End; + + Set_Window(currentpage,XView,YView); + Set_Display_Page(currentpage); + Set_Dac_Register(50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor); + Set_Dac_Register(50 + SetColor, SetColor, 10, 63 - SetColor); + Set_Dac_Register(150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor); + Set_Dac_Register(150 + SetColor, 63, 63, SetColor); + SetColor := SetColor + SDir; + IF (SetColor = 60) OR (SetColor = 0) THEN SDir := -SDir; + PrevColor := PrevColor + PDir; + IF (PrevColor = 60) OR (PrevColor = 0) THEN PDir := -PDir; + Remove_Sprites(lastpage,Number_Of_Shapes); + + If Keypressed Then + Begin + Ch := ReadKey; + Case Ch of + '-' : If Number_Of_Shapes > 1 Then + Begin + c := Number_Of_Shapes; + Copy_Bitmap(2,obj[c].XPos,obj[c].YPos,obj[c].XPos+16,obj[c].YPos+16, + currentpage,obj[c].XPos,obj[c].YPos); + Dec(Number_Of_Shapes); + End; + '+' : If Number_Of_Shapes < 64 Then Inc(Number_Of_Shapes); + End; + End; + lastpage := (lastpage+1) MOD 2; + currentpage := (currentpage+1) MOD 2; + End; +END; + + { MAIN ROUTINE - Run Through Demos and Exit } + +Begin + + Randomize; + Init_Sprites; + + Demo_Res(0, 320, 200); + Demo_Res(1, 320, 400); + Demo_Res(2, 360, 200); + Demo_Res(3, 360, 400); + Demo_Res(4, 320, 240); + Demo_Res(5, 320, 480); + Demo_Res(6, 360, 240); + Demo_Res(7, 360, 480); + Page_Demo; + + asm + mov ah,0 + mov al,3 + int 10h + end; + WriteLn('THIS MODE X DEMO IS FINISHED'); + +END. \ No newline at end of file diff --git a/16/lib/modex105/DEMOS/QB45/MAKE-LIB.BAT b/16/lib/modex105/DEMOS/QB45/MAKE-LIB.BAT new file mode 100644 index 00000000..b04876ad --- /dev/null +++ b/16/lib/modex105/DEMOS/QB45/MAKE-LIB.BAT @@ -0,0 +1,5 @@ +ECHO ... Building MODEX.QLB for QUICKBASIC 4.5 +LIB MODEX -+MODEX,, +LIB MODEX -+UTILS,, +DEL MODEX.BAK +LINK /Q MODEX+UTILS, MODEX.QLB, NUL, C:\QB45\BQLB45.LIB; diff --git a/16/lib/modex105/DEMOS/QB45/MODEX.BI b/16/lib/modex105/DEMOS/QB45/MODEX.BI new file mode 100644 index 00000000..6b1d7afe --- /dev/null +++ b/16/lib/modex105/DEMOS/QB45/MODEX.BI @@ -0,0 +1,63 @@ + + ' ===== SCREEN RESOLUTIONS ===== + +CONST Mode320x200 = 0, Mode320x400 = 1 +CONST Mode360x200 = 2, Mode360x400 = 3 +CONST Mode320x240 = 4, Mode320x480 = 5 +CONST Mode360x240 = 6, Mode360x480 = 7 + + ' ===== MODE X SETUP ROUTINES ===== + +DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%) +DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%) + + ' ===== BASIC GRAPHICS PRIMITIVES ===== + +DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%) +DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%) +DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%) +DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) +DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) + + ' ===== DAC COLOR REGISTER ROUTINES ===== + +DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%) +DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%) +DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) +DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%) + + + ' ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE" +DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE" +DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%) +DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" () +DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" () +DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY" + + ' ===== TEXT DISPLAY ROUTINES ===== + +DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%) + + ' ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) +DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) + + ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%) +DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%) + + + + + + diff --git a/16/lib/modex105/DEMOS/QB45/MODEX.LIB b/16/lib/modex105/DEMOS/QB45/MODEX.LIB new file mode 100644 index 00000000..7baeb85e Binary files /dev/null and b/16/lib/modex105/DEMOS/QB45/MODEX.LIB differ diff --git a/16/lib/modex105/DEMOS/QB45/MODEX.OBJ b/16/lib/modex105/DEMOS/QB45/MODEX.OBJ new file mode 100644 index 00000000..80b311d6 Binary files /dev/null and b/16/lib/modex105/DEMOS/QB45/MODEX.OBJ differ diff --git a/16/lib/modex105/DEMOS/QB45/MODEX.QLB b/16/lib/modex105/DEMOS/QB45/MODEX.QLB new file mode 100644 index 00000000..90122c13 Binary files /dev/null and b/16/lib/modex105/DEMOS/QB45/MODEX.QLB differ diff --git a/16/lib/modex105/DEMOS/QB45/TEST6A.BAS b/16/lib/modex105/DEMOS/QB45/TEST6A.BAS new file mode 100644 index 00000000..b2487d57 --- /dev/null +++ b/16/lib/modex105/DEMOS/QB45/TEST6A.BAS @@ -0,0 +1,561 @@ +'File: TEST6A.BAS +'Descp.: A Mode "X" demonstration for Quickbasic 4.5 +'Author: Matt Pritchard +'Date: 14 April, 1993 +' +DECLARE SUB DEMO.RES (Mode%, Xmax%, Ymax%) +DECLARE SUB ERROR.OUT (Message$) +DECLARE FUNCTION GET.KEY% () +DECLARE SUB LOAD.SHAPES () +DECLARE SUB PAGE.DEMO () +DECLARE SUB PRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%, ColorB%) +DECLARE SUB TPRINT.TEXT (Text$, Xpos%, Ypos%, ColorF%) +DEFINT A-Z + + +TYPE ShapeType + ImgData AS STRING * 512 + xWidth AS INTEGER + yWidth AS INTEGER +END TYPE + +TYPE Sprite + Xpos AS INTEGER + Ypos AS INTEGER + XDir AS INTEGER + YDir AS INTEGER + Shape AS INTEGER +END TYPE + + +CONST MaxShapes = 32 + + REM $INCLUDE: 'UTILS.BI' + REM $INCLUDE: 'MODEX.BI' + +DIM SHARED Img(32) AS ShapeType +COMMON SHARED Img() AS ShapeType + + + CALL INIT.RANDOM + + CALL LOAD.SHAPES + + CALL DEMO.RES(Mode320x200, 320, 200) + CALL DEMO.RES(Mode320x400, 320, 400) + + CALL DEMO.RES(Mode360x200, 360, 200) + CALL DEMO.RES(Mode360x400, 360, 400) + + CALL DEMO.RES(Mode320x240, 320, 240) + CALL DEMO.RES(Mode320x480, 320, 480) + + CALL DEMO.RES(Mode360x240, 360, 240) + CALL DEMO.RES(Mode360x480, 360, 480) + + CALL PAGE.DEMO + + SET.VIDEO.MODE 3 + DOS.PRINT "THIS MODE X DEMO IS FINISHED" + END + +SUB DEMO.RES (Mode, Xmax, Ymax) + + IF SET.MODEX%(Mode) = 0 THEN + ERROR.OUT "Unable to SET_MODEX" + STR$(Mode) + END IF + + XCenter = Xmax \ 2 + + X1 = 10 + Y1 = 10 + X2 = Xmax - 1 + Y2 = Ymax - 1 + + FOR Z = 0 TO 3 + Colr = 31 - Z * 2 + DRAW.LINE X1 + Z, Y1 + Z, X2 - Z, Y1 + Z, Colr + DRAW.LINE X1 + Z, Y1 + Z, X1 + Z, Y2 - Z, Colr + DRAW.LINE X1 + Z, Y2 - Z, X2 - Z, Y2 - Z, Colr + DRAW.LINE X2 - Z, Y1 + Z, X2 - Z, Y2 - Z, Colr + NEXT Z + + XChars = Xmax \ 10 + YChars = Ymax \ 10 + + FOR X = 0 TO XChars - 1 + TGPRINTC 48 + ((X + 1) MOD 10), X * 10 + 1, 1, 9 + ((X \ 8) MOD 7) + DRAW.LINE X * 10 + 9, 0, X * 10 + 9, 3, 15 + NEXT X + + FOR Y = 0 TO YChars - 1 + TGPRINTC 48 + ((Y + 1) MOD 10), 1, Y * 10 + 1, 9 + ((Y \ 10) MOD 7) + DRAW.LINE 0, Y * 10 + 9, 3, Y * 10 + 9, 15 + NEXT Y + + ' Draw Lines + + FOR X = 0 TO 63 + N = 15 + X * .75 + SET.DAC.REGISTER 64 + X, N, N, N + SET.DAC.REGISTER 128 + X, 0, N, N + + DRAW.LINE 103 - X, 60, 40 + X, 123, 64 + X + DRAW.LINE 40, 60 + X, 103, 123 - X, 128 + X + + NEXT X + TPRINT.TEXT "LINE TEST", 37, 130, c.BLUE + + Y = 60: Gap = 0 + FOR X = 0 TO 9 + FILL.BLOCK 120, Y, 120 + X, Y + Gap, 64 + X + FILL.BLOCK 140 - (15 - X), Y, 150 + X, Y + Gap, 230 + X + FILL.BLOCK 170 - (15 - X), Y, 170, Y + Gap, 128 + X + Y = Y + Gap + 2 + Gap = Gap + 1 + NEXT X + TPRINT.TEXT "FILL TEST", 110, 46, c.GREEN + + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + SET.POINT X, Y, X + Y + X + Y + NEXT Y + NEXT X + + TPRINT.TEXT "PIXEL TEST", 182, 130, c.RED + + FOR X = 190 TO 250 STEP 2 + FOR Y = 60 TO 122 STEP 2 + IF READ.POINT(X, Y) <> ((X + Y + X + Y) AND 255) THEN + ERROR.OUT "READ.PIXEL Failure" + END IF + NEXT Y + NEXT X + + + + Msg$ = " This is a MODE X demo " + PRINT.TEXT Msg$, XCenter - (LEN(Msg$) * 4), 20, c.bRED, c.BLUE + Msg$ = "Screen Resolution is by " + Xp = XCenter - (LEN(Msg$) * 4) + PRINT.TEXT Msg$, Xp, 30, c.bGREEN, c.BLACK + + PRINT.TEXT LTRIM$(STR$(Xmax)), Xp + 8 * 21, 30, c.bPURPLE, c.BLACK + PRINT.TEXT LTRIM$(STR$(Ymax)), Xp + 8 * 28, 30, c.bWHITE, c.BLACK + + FOR X = 0 TO 15 + SET.DAC.REGISTER 230 + X, 63 - X * 4, 0, 15 + X * 3 + DRAW.LINE 30 + X, Ymax - 6 - X, Xmax - 20 - X, Ymax - 6 - X, 230 + X + NEXT X + TPRINT.TEXT "Press to Continue", XCenter - (26 * 4), Ymax - 18, c.YELLOW + + X = GET.KEY% + IF X = KyESC THEN ERROR.OUT "ABORT" + +END SUB + +SUB ERROR.OUT (Message$) + + SET.VIDEO.MODE 3 + DOS.PRINT Message$ + END + +END SUB + +FUNCTION GET.KEY% + + DO + X = SCAN.KEYBOARD + LOOP UNTIL X + + GET.KEY% = X + +END FUNCTION + +SUB LOAD.SHAPES + +DIM Grid(1 TO 32, 1 TO 32) + + FOR Shape = 0 TO MaxShapes - 1 + + FOR Y = 1 TO 32 + FOR X = 1 TO 32 + Grid(X, Y) = 0 + NEXT X + NEXT Y + + Style = RANDOM.INT(6) + Colour = 1 + RANDOM.INT(15) + + SELECT CASE Style + + CASE 0: ' Solid Box + + DO + xWidth = 3 + RANDOM.INT(30) + yWidth = 3 + RANDOM.INT(30) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + CASE 1: ' Hollow Box + + DO + xWidth = 5 + RANDOM.INT(28) + yWidth = 5 + RANDOM.INT(28) + LOOP UNTIL ((xWidth * yWidth) <= 512) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + Grid(X, Y) = Colour + NEXT X + NEXT Y + + HollowX = 1 + RANDOM.INT(xWidth \ 2 - 1) + HollowY = 1 + RANDOM.INT(yWidth \ 2 - 1) + + FOR Y = HollowY + 1 TO yWidth - HollowY + FOR X = HollowX + 1 TO xWidth - HollowX + Grid(X, Y) = nil + NEXT X + NEXT Y + + CASE 2: ' Solid Diamond + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + NEXT X + NEXT Y + + + CASE 3: ' Hollow Diamond + + + xWidth = 3 + 2 * RANDOM.INT(10) + yWidth = xWidth + Centre = xWidth \ 2 + sWidth = RANDOM.INT(Centre) + + FOR Y = 0 TO Centre + FOR X = 0 TO Y + IF X + (Centre - Y) >= sWidth THEN + Grid(Centre - X + 1, Y + 1) = Colour + Grid(Centre + X + 1, Y + 1) = Colour + Grid(Centre - X + 1, yWidth - Y) = Colour + Grid(Centre + X + 1, yWidth - Y) = Colour + END IF + NEXT X + NEXT Y + + CASE 4: ' Ball + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + CASE 5: ' Ball + + + xWidth = 7 + 2 * RANDOM.INT(8) + yWidth = xWidth + Centre = 1 + xWidth \ 2 + sWidth = RANDOM.INT(xWidth) + + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + D = SQR(((Centre - X) * (Centre - X)) + ((Centre - Y) * (Centre - Y))) + IF D < Centre AND D >= sWidth THEN Grid(X, Y) = 150 + Colour * 2 + D * 3 + NEXT X + NEXT Y + + END SELECT + + Img(Shape).xWidth = xWidth + Img(Shape).yWidth = yWidth + + A$ = STRING$(xWidth * yWidth, nil) + + c = 1 + FOR Y = 1 TO yWidth + FOR X = 1 TO xWidth + MID$(A$, c, 1) = CHR$(Grid(X, Y)) + c = c + 1 + NEXT X + NEXT Y + + Img(Shape).ImgData = A$ + + + NEXT Shape + +END SUB + +SUB PAGE.DEMO + +CONST MaxSprites = 64 + +DIM Obj(MaxSprites) AS Sprite +DIM LastX(MaxSprites, 1), LastY(MaxSprites, 1) +DIM LastObjects(1) + + ScreenX = 360: ScreenY = 240 + + IF SET.VGA.MODEX%(Mode320x200, ScreenX, ScreenY, 3) = 0 THEN + ERROR.OUT "Unable to SET_VGA_MODEX" + STR$(Mode) + END IF + + SET.ACTIVE.PAGE 0 + + CLEAR.VGA.SCREEN c.BLACK + + PRINT.TEXT "This is a Test of the Following Functions:", 10, 9, c.bWHITE, c.BLACK + + DRAW.LINE 10, 18, 350, 18, c.YELLOW + PRINT.TEXT "SET_ACTIVE_PAGE", 10, 20, c.bBLUE, c.BLACK + PRINT.TEXT "SET_DISPLAY_PAGE", 10, 30, c.GREEN, c.BLACK + PRINT.TEXT "SET_DAC_REGISTER", 10, 40, c.RED, c.BLACK + PRINT.TEXT "CLEAR_VGA_SCREEN", 10, 50, c.CYAN, c.BLACK + + PRINT.TEXT "TDRAW_BITMAP", 10, 60, c.PURPLE, c.BLACK + PRINT.TEXT "COPY_PAGE", 10, 70, c.GREEN, c.BLACK + PRINT.TEXT "COPY_BITMAP", 10, 80, c.CYAN, c.BLACK + + PRINT.TEXT "GPRINTC", 10, 90, c.BLUE, c.BLACK + PRINT.TEXT "TGPRINTC", 10, 100, c.GREEN, c.BLACK + PRINT.TEXT "SET_WINDOW", 10, 110, c.RED, c.BLACK + + PRINT.TEXT "VIRTUAL SCREEN SIZES", 190, 20, c.bBLUE, c.BLACK + PRINT.TEXT " SMOOTH SCROLLING", 190, 30, c.GREEN, c.BLACK + PRINT.TEXT " SPRITE ANIMATION", 190, 40, c.CYAN, c.BLACK + PRINT.TEXT " PAGE FLIPPING", 190, 50, c.RED, c.BLACK + PRINT.TEXT " COLOR CYCLING", 190, 60, c.PURPLE, c.BLACK + + + FOR X = 0 TO 60 + SET.DAC.REGISTER 50 + X, 3 + X, 0, 60 - X + SET.DAC.REGISTER 150 + X, 3 + X, 0, 60 - X + NEXT X + + c = 0: DC = 1 + FOR X = 0 TO ScreenX \ 2 + DRAW.LINE ScreenX \ 2 - 1, ScreenY \ 4, X, ScreenY - 1, c + 50 + DRAW.LINE ScreenX \ 2, ScreenY \ 4, ScreenX - X - 1, ScreenY - 1, c + 50 + c = c + DC + IF c = 0 OR c = 60 THEN DC = -DC + NEXT X + + TPRINT.TEXT "Press to Continue", 72, 190, c.bWHITE + TPRINT.TEXT "< > = Faster < > = Slower", 72, 204, c.bGREEN + TPRINT.TEXT "< > = Fewer Shapes < > = More Shapes", 32, 218, c.bCYAN + + TGPRINTC 43, 80, 204, c.YELLOW + TGPRINTC 45, 200, 204, c.YELLOW + + TGPRINTC 25, 40, 218, c.YELLOW + TGPRINTC 24, 200, 218, c.YELLOW + + COPY.PAGE 0, 1 + COPY.PAGE 0, 2 + + FOR X = 1 TO MaxSprites + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + + Obj(X).Shape = X MOD MaxShapes + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + Obj(X).Xpos = 1 + RANDOM.INT(ScreenX - SpriteX - 2) + Obj(X).Ypos = 1 + RANDOM.INT(ScreenY - SpriteY - 2) + + LastX(X, 0) = Obj(X).Xpos + LastX(X, 1) = Obj(X).Xpos + LastY(X, 0) = Obj(X).Ypos + LastY(X, 1) = Obj(X).Ypos + NEXT X + + CurrentPage = 0 + + 'View Shift... + + ViewX = 0 + ViewY = 0 + ViewMax = 3 + ViewCnt = 0 + ViewXD = 1 + ViewYD = 1 + + SetColor = 3: SDir = 1 + PrevColor = 0: PDir = 1 + + VisObjects = MaxSprites \ 2 + LastObjects(0) = 0 + LastObjects(1) = 0 + +DRAW.LOOP: + + + SET.ACTIVE.PAGE CurrentPage + + ' Erase Old Images + + FOR X = 1 TO LastObjects(CurrentPage) + + X1 = LastX(X, CurrentPage) AND &HFFFC + Y1 = LastY(X, CurrentPage) + X2 = ((LastX(X, CurrentPage) + Img(Obj(X).Shape).xWidth)) OR 3 + Y2 = Y1 + Img(Obj(X).Shape).yWidth - 1 + + COPY.BITMAP 2, X1, Y1, X2, Y2, CurrentPage, X1, Y1 + + NEXT X + + ' Draw new images + + FOR X = 1 TO VisObjects + + SpriteX = Img(Obj(X).Shape).xWidth + SpriteY = Img(Obj(X).Shape).yWidth + + ' Move Sprite + +REDOX: + NewX = Obj(X).Xpos + Obj(X).XDir + IF NewX < 0 OR NewX + SpriteX > ScreenX THEN + Obj(X).XDir = -Obj(X).XDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOX + END IF + END IF + Obj(X).Xpos = Obj(X).Xpos + Obj(X).XDir + +REDOY: + NewY = Obj(X).Ypos + Obj(X).YDir + IF NewY < 0 OR NewY + SpriteY > ScreenY THEN + Obj(X).YDir = -Obj(X).YDir + IF RANDOM.INT(20) = 1 THEN + DO + Obj(X).XDir = RANDOM.INT(7) - 3 + Obj(X).YDir = RANDOM.INT(7) - 3 + LOOP WHILE (Obj(X).XDir = 0 AND Obj(X).YDir = 0) + GOTO REDOY + END IF + END IF + Obj(X).Ypos = Obj(X).Ypos + Obj(X).YDir + + 'Draw Sprite + + TDRAW.BITMAP Img(Obj(X).Shape), Obj(X).Xpos, Obj(X).Ypos, SpriteX, SpriteY + + LastX(X, CurrentPage) = Obj(X).Xpos + LastY(X, CurrentPage) = Obj(X).Ypos + + NEXT X + + LastObjects(CurrentPage) = VisObjects + + ' Pan Screen Back & Forth + + ViewCnt = ViewCnt + 1 + IF ViewCnt >= ViewMax THEN + ViewX = ViewX + ViewXD + IF ViewX = 0 OR ViewX = 39 THEN ViewXD = -ViewXD + IF ViewXD < 0 THEN + ViewY = ViewY + ViewYD + IF ViewY = 0 OR ViewY = 39 THEN ViewYD = -ViewYD + END IF + + SET.WINDOW CurrentPage, ViewX, ViewY + + ViewCnt = 0 + ELSE + SET.DISPLAY.PAGE CurrentPage + END IF + + ' Cycle Colors + + SET.DAC.REGISTER 50 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 50 + SetColor, SetColor, 10, 63 - SetColor + + SET.DAC.REGISTER 150 + PrevColor, 3 + PrevColor, 0, 60 - PrevColor + SET.DAC.REGISTER 150 + SetColor, 63, 63, SetColor + + SetColor = SetColor + SDir + IF SetColor = 60 OR SetColor = 0 THEN SDir = -SDir + + PrevColor = PrevColor + PDir + IF PrevColor = 60 OR PrevColor = 0 THEN PDir = -PDir + + CurrentPage = 1 - CurrentPage + + Code = SCAN.KEYBOARD + + IF Code = False THEN GOTO DRAW.LOOP + + IF Code = KyPlus THEN + IF ViewMax < 12 THEN ViewMax = ViewMax + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyMinus THEN + IF ViewMax > 1 THEN ViewMax = ViewMax - 1 + IF ViewCnt >= ViewMax THEN ViewCnt = 0 + GOTO DRAW.LOOP + END IF + + IF Code = KyUp THEN + IF VisObjects < MaxSprites THEN VisObjects = VisObjects + 1 + GOTO DRAW.LOOP + END IF + + IF Code = KyDown THEN + IF VisObjects > 1 THEN VisObjects = VisObjects - 1 + GOTO DRAW.LOOP + END IF + + +END SUB + +SUB PRINT.TEXT (Text$, Xpos, Ypos, ColorF, ColorB) + + IF LEN(Text$) = 0 THEN EXIT SUB + PRINT.STR VARSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF, ColorB + + +END SUB + +SUB TPRINT.TEXT (Text$, Xpos, Ypos, ColorF) + + IF LEN(Text$) = 0 THEN EXIT SUB + + TPRINT.STR VARSEG(Text$), SADD(Text$), LEN(Text$), Xpos, Ypos, ColorF + +END SUB + diff --git a/16/lib/modex105/DEMOS/QB45/TEST6A.EXE b/16/lib/modex105/DEMOS/QB45/TEST6A.EXE new file mode 100644 index 00000000..e61d0387 Binary files /dev/null and b/16/lib/modex105/DEMOS/QB45/TEST6A.EXE differ diff --git a/16/lib/modex105/DEMOS/QB45/UASM-QB4.BAT b/16/lib/modex105/DEMOS/QB45/UASM-QB4.BAT new file mode 100644 index 00000000..e4aa87e0 --- /dev/null +++ b/16/lib/modex105/DEMOS/QB45/UASM-QB4.BAT @@ -0,0 +1 @@ +MASM utils, utils, utils, nul; \ No newline at end of file diff --git a/16/lib/modex105/DEMOS/QB45/UTILS.ASM b/16/lib/modex105/DEMOS/QB45/UTILS.ASM new file mode 100644 index 00000000..811b8f8e --- /dev/null +++ b/16/lib/modex105/DEMOS/QB45/UTILS.ASM @@ -0,0 +1,406 @@ +;======================================================= +;=== UTILS.ASM - Asm Utilities for QuickBasic/BC7 === +;======================================================= + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ==== MACROS ==== + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + push R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + pop R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear a Register to 0 + +CLR MACRO Register + xor Register, Register ; Set Register = 0 +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + dec Register ; Counter-- + jnz Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + dec Register ; Counter-- + jz Destination ; Jump if 0 +ENDM + + + ; ==== General Constants ==== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + +IFDEF FARSTRINGS + + EXTRN stringaddress:far + EXTRN stringlength:far + +ENDIF + + + .Data + + EVEN + +RND_Seed DW 7397, 29447, 802 +RND_Mult DW 179, 183, 182 +RND_ModV DW 32771, 32779, 32783 + +CR_LF DB 13, 10 ; the CRLF data + + .Code + +;================= +;DOS_PRINT (Text$) +;================= +; +; Prints Text Directly to DOS console w/ CR/LF +; + + PUBLIC DOS_PRINT + +DP_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DP_Text DW ? ; Address of Text$ Descriptor +DP_Stack ENDS + + +DOS_PRINT PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @No_Print ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@No_Print: + mov AX, SEG DGROUP ; Restore DGroup + mov DS, AX + + mov DX, o CR_LF ; Get Addr of CR/LF pair + mov CX, 2 ; 2 Characters to Write + mov BX, 1 ; 1= DOS Handle for Display + + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINT ENDP + + +;================== +;DOS_PRINTS (Text$) +;================== +; +; Print Text$ Directly to DOS console +; without a trailing CR/LF +; + + PUBLIC DOS_PRINTS + +DOS_PRINTS PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + mov SI, [BP].DP_Text ; Get Addr of Text$ descriptor + +IFDEF FARSTRINGS + push SI ; Push Addr of BC7 Decriptor Ptr + call stringaddress ; Get Address + Len of string!!! + ; DX:AX = Addr CX = Len + mov DS, DX ; DS = DX = Segment of string + mov DX, AX ; DX = AX = Offset of String +ELSE + mov CX, [SI] ; put its length into CX + mov DX, [SI+02] ; now DS:DX points to the String +ENDIF + + jcxz @DPS_Exit ; Don't Print if empty + + mov BX, 1 ; 1= DOS Handle for Display + mov AH, 40h ; Write Text Function + int 21h ; Call DOS to do it + +@DPS_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +DOS_PRINTS ENDP + + +;====================== +;SET_VIDEO_MODE (Mode%) +;====================== +; +; Sets the Video Mode through the BIOS +; + + PUBLIC SET_VIDEO_MODE + +SVM_Stack STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Mode DB ?,? ; Desired Video Mode +SVM_Stack ENDS + + +SET_VIDEO_MODE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR AH ; Function 0 + mov AL, [BP].SVM_Mode ; Get Mode # + + int 10H ; Change Video Modes + +@SVM_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + ret 2 ; Exit & Clean Up Stack + +SET_VIDEO_MODE ENDP + + +;============== +;SCAN_KEYBOARD% +;============== +; +; Function to scan keyboard for a pressed key +; + + PUBLIC SCAN_KEYBOARD + +SCAN_KEYBOARD PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + + mov AH, 01H ; Function #1 + int 16H ; Call Keyboard Driver + jz @SK_NO_KEY ; Exit if Zero flag set + + mov AH, 00H ; Remove Key from Buffer + int 16H ; Get Keycode in AX + + or AL, AL ; Low Byte Set (Ascii?) + jz @SK_Exit ; if not, it's a F-Key + + CLR AH ; Clear ScanCode if Ascii + jmp s @SK_Exit ; Return Key in AX + +@SK_NO_KEY: + CLR AX ; Return Nil (no Keypress) + +@SK_Exit: + cld ; Reset Direction Flag + POPx DI, SI, DS, BP ; Restore Saved Registers + ret ; Exit & Clean Up Stack + +SCAN_KEYBOARD ENDP + + +;==================== +;RANDOM_INT (MaxInt%) +;==================== +; +; Returns a pseudo-random number in the range of (0.. MaxInt-1) +; + + + PUBLIC RANDOM_INT + +RI_Stack STRUC + DW ? ; BP + DD ? ; Caller + RI_MaxVal DW ? ; Maximum Value to Return + 1 +RI_Stack ENDS + + +RANDOM_INT PROC FAR + + push BP ; Preserve Important Registers + mov BP, SP ; Set up Stack Frame + + CLR BX ; BX is the data index + CLR CX ; CX is the accumulator + +REPT 3 + mov AX, RND_Seed[BX] ; load the initial seed + mul RND_Mult[BX] ; multiply it + div RND_ModV[BX] ; and obtain the Mod value + mov RND_Seed[BX], DX ; save that for the next time + + add CX, DX ; add it into the accumulator + inc BX + inc BX ; point to the next set of values +ENDM + + mov AX, CX ; AX = Random # + CLR DX ; DX = 0 + div [BP].RI_MaxVal ; DX = DX:AX / MAxVal Remainder + + mov AX, DX + + pop BP ; Restore BP + ret 2 ; back to BASIC with AX holding the result + +RANDOM_INT ENDP + + +;=========== +;INIT_RANDOM +;=========== +; +; Scrambles the psuedo-random number sequence +; (XOR's the seed value with the timer) +; + + PUBLIC INIT_RANDOM + +INIT_RANDOM PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX + mov AX, ES:[046Ch] ; Get Timer Lo Word + + xor RND_Seed, AX ; Scramble 1st Seed + + ret ; Exit & Clean Up Stack + +INIT_RANDOM ENDP + + +;==================== +;INT_SQR (X%, Round%) +;==================== +; +; Returns the Integer Square Root of (X) +; Round allows the return value to be rounded to the +; nearest integer value by passing 0x80. Passing 0 +; return the Integer Portion only. The rounding amound is +; a number from 0 to 1 multiplied by 256, thus +; 0.5 * 0x100 = 0x80! +; + +ISQ_Stack STRUC + DW ?,? ; BP, DI + DD ? ; Caller + ISQ_Round DW ? ; Amount to Round Result * 256 + ISQ_X DW ? ; "X" +ISQ_Stack ENDS + + PUBLIC INT_SQR + +INT_SQR PROC FAR + + PUSHx BP, DI ; Save BP + mov BP, SP ; Set up Stack Frame + + xor AX, AX ; {xor eax,eax} + xor DX, DX ; {xor edx,edx} + mov DI, [BP].ISQ_X ; {mov edi,x} + + mov CX, 16 ; {mov cx, 32} + +@ISQ_L: + + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl DI, 1 ; {shl edi,1} + rcl DX, 1 ; {rcl edx,1} + shl AX, 1 ; {shl eax,1} + mov BX, AX ; {mov ebx,eax} + shl BX, 1 ; {shl ebx,1} + inc BX ; {inc ebx} + cmp DX, BX ; {cmp edx,ebx} + jl @ISQ_S + + sub DX, BX ; {sub edx,ebx} + inc AX ; {inc eax} + +@ISQ_S: + loop @ISQ_L + + add ax, [BP].ISQ_Round ; {add eax,$00008000} + ; {*round* result in hi word: ie. +0.5} + shr ax, 8 ; {shr eax,16} {to ax (result)} + + POPx DI, BP ; Restore Registers + ret 4 ; Exit + +INT_SQR ENDP + + +;============ +;TIMER_COUNT& +;============ +; +; Returns the current timer value as an integer/long integer +; + + + PUBLIC TIMER_COUNT + +TIMER_COUNT PROC FAR + + clr AX ; Segment = 0000 + mov ES, AX ; use ES to get at data + mov AX, ES:[046Ch] ; Get Timer Lo Word + mov DX, ES:[046Eh] ; Get Timer Hi Word + ret ; Exit & Return value in DX:AX + +TIMER_COUNT ENDP + + + END diff --git a/16/lib/modex105/DEMOS/QB45/UTILS.BI b/16/lib/modex105/DEMOS/QB45/UTILS.BI new file mode 100644 index 00000000..aeafeef4 --- /dev/null +++ b/16/lib/modex105/DEMOS/QB45/UTILS.BI @@ -0,0 +1,51 @@ + + ' Misc Constants + +CONST True = -1, False = 0, nil = 0 + + ' Keyboard Codes: Extended + +CONST KyF1 = &H3B00, KyF2 = &H3C00, KyF3 = &H3D00, KyF4 = &H3E00, KyF5 = &H3F00 +CONST KyF6 = &H4000, KyF7 = &H4100, KyF8 = &H4200, KyF9 = &H4300, KyF10 = &H4400 + +CONST KyUp = &H4800, KyLeft = &H4B00, KyRight = &H4D00, KyDown = &H5000 +CONST KySLeft = &HCB00, KySRight = &HCD00, KySUp = &HC800, KySDown = &HD000 + +CONST KyHome = &H4700, KyPgUp = &H4900, KyEnd = &H4F00, KyPgDn = &H5100 +CONST KySHome = &HC700, KySPgUp = &HC900, KySEnd = &HCF00, KySPgDn = &HD100 + +CONST KyIns = &H5200, KyDel = &H5300, KyRvsTab = &H8F00 +CONST KySIns = &HC200, KySDel = &HC300 + +CONST KyAltA = &H1E00, KyAltB = &H3000, KyAltC = &H2E00, KyAltD = &H2000 +CONST KyAltE = &H1200, KyAltF = &H2100, KyAltG = &H2200, KyAltH = &H2300 +CONST KyAltI = &H1700, KyAltJ = &H2400, KyAltK = &H2500, KyAltL = &H2600 +CONST KyAltM = &H3200, KyAltN = &H3100, KyAltO = &H1800, KyAltP = &H1900 +CONST KyAltQ = &H1000, KyAltR = &H1300, KyAltS = &H1F00, KyAltT = &H1400 +CONST KyAltU = &H1600, KyAltV = &H2F00, KyAltW = &H1100, KyAltX = &H2D00 +CONST KyAltY = &H1500, KyAltZ = &H2C00 + + ' Keyboard Codes: Ascii + +CONST KyBS = 8, KyTab = 9, KyCR = 13, KyESC = &H1B, KyClr = &H7F +CONST KyPlus = 45, KyMinus = 43 + + ' Color Constants + +CONST c.BLACK = 0, c.BLUE = 1, c.GREEN = 2, c.CYAN = 3 +CONST c.RED = 4, c.PURPLE = 5, c.BROWN = 6, c.WHITE = 7 +CONST c.GREY = 8, c.bBLUE = 9, c.bGREEN = 10, c.bCYAN = 11 +CONST c.bRED = 12, c.bPURPLE = 13, c.YELLOW = 14, c.bWHITE = 15 +CONST c.BRIGHT = 8 + + ' From UTILS.ASM + +DECLARE SUB DOS.PRINT ALIAS "DOS_PRINT" (Text$) +DECLARE SUB DOS.PRINTS ALIAS "DOS_PRINTS" (Text$) +DECLARE SUB SET.VIDEO.MODE ALIAS "SET_VIDEO_MODE" (BYVAL Mode%) +DECLARE FUNCTION SCAN.KEYBOARD% ALIAS "SCAN_KEYBOARD" +DECLARE FUNCTION RANDOM.INT ALIAS "RANDOM_INT" (BYVAL MaxInt%) +DECLARE SUB INIT.RANDOM ALIAS "INIT_RANDOM" +DECLARE FUNCTION TIMER.COUNT& ALIAS "TIMER_COUNT" +DECLARE FUNCTION INT.SQR ALIAS "INT_SQR" (BYVAL X%, BYVAL Round%) + diff --git a/16/lib/modex105/DEMOS/QB45/UTILS.OBJ b/16/lib/modex105/DEMOS/QB45/UTILS.OBJ new file mode 100644 index 00000000..63d818a9 Binary files /dev/null and b/16/lib/modex105/DEMOS/QB45/UTILS.OBJ differ diff --git a/16/lib/modex105/DEMOS/ROM_8X8.FNT b/16/lib/modex105/DEMOS/ROM_8X8.FNT new file mode 100644 index 00000000..708a4f92 Binary files /dev/null and b/16/lib/modex105/DEMOS/ROM_8X8.FNT differ diff --git a/16/lib/modex105/DEMOS/SPACEAGE.FNT b/16/lib/modex105/DEMOS/SPACEAGE.FNT new file mode 100644 index 00000000..029bae4e Binary files /dev/null and b/16/lib/modex105/DEMOS/SPACEAGE.FNT differ diff --git a/16/lib/modex105/DEMOS/SYSTEM.FNT b/16/lib/modex105/DEMOS/SYSTEM.FNT new file mode 100644 index 00000000..9a1965eb Binary files /dev/null and b/16/lib/modex105/DEMOS/SYSTEM.FNT differ diff --git a/16/lib/modex105/DEMOS/TEST6.EXE b/16/lib/modex105/DEMOS/TEST6.EXE new file mode 100644 index 00000000..5682c475 Binary files /dev/null and b/16/lib/modex105/DEMOS/TEST6.EXE differ diff --git a/16/lib/modex105/FONTEDIT/CHARSETS.CS b/16/lib/modex105/FONTEDIT/CHARSETS.CS new file mode 100644 index 00000000..97fe608f Binary files /dev/null and b/16/lib/modex105/FONTEDIT/CHARSETS.CS differ diff --git a/16/lib/modex105/FONTEDIT/CSEDIT.DOC b/16/lib/modex105/FONTEDIT/CSEDIT.DOC new file mode 100644 index 00000000..97ff07e0 --- /dev/null +++ b/16/lib/modex105/FONTEDIT/CSEDIT.DOC @@ -0,0 +1,196 @@ + +CSEDIT - A Simple Font Editor by Matt Pritchard + + +CSEDIT is distributed with MODEXnnn.ZIP, the general purpose MODE X +Library for VGA Graphics. + +WHAT YOU NEED TO RUN CSEDIT: + + * A Vga Monitor + * A Microsoft Compatible Mouse + + A Mouse is most definitely required, as the keyboard is used for + nothing except entering file names. + +FILES NEEDED IN THE CURRENT DIRECTORY: + + CSEDIT.EXE - The Font Editor Program + CHARSETS.CS - The Font Editor's Internal Fonts + PALETTE.CS - The Font Editor's Palette + MOUSEIMG.CS - The Font Editor's Mouse Pointer + +SAMPLE FONT FILE THAT SHOULD BE INCLUDED: + + SYSTEM.FNT - The Font used by CSEDIT.EXE + INVERSE.FNT - An Inverted version of SYSTEM.FNT + SPACEAGE.FNT - A Futuristic, Tech style font + ROM_8X8.FNT - The Lower 128 characters from the VGA BIOS Rom + +WHAT IT EDITS: + + 8 by 8 character fonts, 128 characters at a time. 2 fonts at a time. + +HOW IT WORKS/FEATURES: + + CSEDIT allows the user to edit 2 different font groups at a time, + which may be loaded and saved separately. + + A enlarged character grid allows the user to edit individual pixels + on a selected character. + + The Following operations can be performed on a single character or + simultaneously on a selected block of characters. + + * Shift the selected character(s) in any direction + with or without clipping at the edges. + * Vertically Flip the selected character(s) + * Horizontally Flip the selected character(s) + * Rotate the selected character(s) 90 Degrees Clockwise + * Rotate the selected character(s) 90 Degrees Counterclockwise + * Clear the selected character(s) + * Invert the selected character(s) + * XOR the selected character(s) with other character(s) + * AND the selected character(s) with other character(s) + * OR the selected character(s) with other character(s) + * Copy the selected character(s) to another position or font. + + An UNDO feature allows the reversal of the most recent operation. + +DESCRIPTION OF OBJECTS/FEATURES FROM THE TOP DOWN: + + Character Grid: (RED) Box in Upper Left corner of screen. This is + where you edit an individual character. The Left Button sets the + pixel the mouse pointer is on, while the Right Button clears that + pixel. + + Scroll Buttons: The Four Scroll Buttons are labeled with directional + arrows, and arranged in a diamond pattern. Left Clicking on a + directional button will scroll the currently selected character + in that direction, with the pixels on the edge rolling off and + appearing on the other size. Right Clicking will prevent the + pixels from rolling to the other side. + + Vertical Flip Button: + Horizontal Flip Button: Clicking these buttons will flip the pattern + of the currently selected character(s) around the indicated axis. + i.e. the top row will be swapped with the bottom row, etc. or the + left row column will be swapped with right column, etc. + depending upon which button you push. + + Invert Button: Clicking this button causes all pixels in the selected + character(s) to flip flop between on and off. + + Clear Button: Clicking this button erases the selected characters + + Rotate Buttons: Clicking these buttons will rotate the pattern in the + selected character(s) 90 degrees in the indicated direction. + + XOR Button: Clicking this button will let you XOR the currently + selected character(s) with other character(s) in either font. + The Button will turn RED, indicating that it is waiting for + you to click on the desired character (or upper left corner + of the desired block of characters) in either the Red or Green + Character Set Displays. Clicking anywhere else will abort this + process without doing anything. If you click on (any of) the + selected character(s) the operation is aborted. If a block is + selected and the character you click on is in a position where + it can't represent the upper left corner of a block of the same + size, then the operation is not performed. + + AND Button & OR Button: These buttons work just like the XOR Button + except that the Binary operation performed is either an AND or OR + depending upon which button you have selected. + + COPY Button: This button lets you copy a character or selected block + of characters to another area in the current font or the other + font. After clicking, the button turns RED and works much like + the XOR Button. Clicking on a valid position in either font + window will copy the selected character(s) to that location. + + MODE Button: Clicking this button toggles the editor between BLOCK + mode and CHARACTER mode. The current mode is displayed on a plate + at the top of the screen, just to the right of the enlarged + character grid. In character mode the plate will read "CHAR" and + the currently selected character is displayed just to the right + of the plate. In Block mode the plate will read "BLOCK" and the + enlarged character grid is disabled. + + UNDO Button: Clicking this Button will UNDO or reverse the effects of + the most recent operation. + + QUIT Button: Clicking this button will return you to DOS. Any loaded + fonts are not saved, and no confirmation is given. + + + GREEN FONT AREA: This area displays one of the current fonts which + can be edited. The characters are display in order from #0 to #127 + from the upper left, going right, then down. The Font Box is 32 + characters wide and 4 characters Tall. When the editor is in + character mode, just point at and Left Click on the character you + wish to edit and a Cyan box will appear around that character. + + * If you Right Click on a character, the last current character, + which will still appear in the enlarged character grid, will be + copied onto the character you pointed at, replacing it. This is + a shortcut for copying characters: You can hold the right button + down an fill in a large area with a single character pattern. + When the editor is in Block Mode, you select an area by clicking + on any corner of the desired block. Then drag the mouse to the + opposite corner while holding down the left button. A Cyan Box + will stretch to surround the selected block of characters. + + GREEN FONT FILE NAME BOX: This Text Box is used to enter the name + of a font file to load or the name to save the current Green font + as. Just click on the Box, and it will change color and a + flashing cursor will appear. Now you type in a filename or edit + the existing filename. Press or click outside the text + box to end editing. + + GREEN FONT LOAD BUTTON: Clicking this button will load the font file + that is named in the Green File name box. If no name is given or + no such file exists, then nothing will be loaded. + + GREEN FONT SAVE BUTTON: Clicking this button will save the current + font in the Green Font Area under the name given in the File Name + Box. If a Valid name is not provided, nothing will be saved. + + RED FONT AREA: This is just the same as the GREEN FONT AREA; providing + you with the ability to copy and edit between multiple fonts. + + RED FONT FILE NAME BOX: This works just like the GREEN FONT FILE + NAME BOX. + + RED FONT LOAD BUTTON: This works just like the GREEN FONT LOAD BUTTON. + + RED FONT SAVE BUTTON: This works just like the GREEN FONT SAVE BUTTON. + + Message Bar: At the very bottom of the screen, this Bar will display + information and messages for various functions. + + +FONT FILE FORMAT: + + BINARY Image, in order of character. The format is identical to that + used by the VGA ROM. The Files will be exactly 1024 (128 * 8) bytes + long. + + CHARACTER: 8 Bytes + + FONT: Array (0 to 127) of CHARACTER + + +COMMENTS, QUESTIONS, BUG REPORTS, etc: + + Send the to the Author: Matt Pritchard + + Through the 80xxx Fidonet Echo or + + Matt Pritchard + P.O. Box 140264 + Irving, TX 75014 + +CREDITS: + + This Font Editor was written in QuickBASIC 4.5 + diff --git a/16/lib/modex105/FONTEDIT/CSEDIT.EXE b/16/lib/modex105/FONTEDIT/CSEDIT.EXE new file mode 100644 index 00000000..58b07325 Binary files /dev/null and b/16/lib/modex105/FONTEDIT/CSEDIT.EXE differ diff --git a/16/lib/modex105/FONTEDIT/INVERSE.FNT b/16/lib/modex105/FONTEDIT/INVERSE.FNT new file mode 100644 index 00000000..5901c517 Binary files /dev/null and b/16/lib/modex105/FONTEDIT/INVERSE.FNT differ diff --git a/16/lib/modex105/FONTEDIT/MOUSEIMG.CS b/16/lib/modex105/FONTEDIT/MOUSEIMG.CS new file mode 100644 index 00000000..101e2084 Binary files /dev/null and b/16/lib/modex105/FONTEDIT/MOUSEIMG.CS differ diff --git a/16/lib/modex105/FONTEDIT/PALETTE.CS b/16/lib/modex105/FONTEDIT/PALETTE.CS new file mode 100644 index 00000000..09c5549e Binary files /dev/null and b/16/lib/modex105/FONTEDIT/PALETTE.CS differ diff --git a/16/lib/modex105/FONTEDIT/ROM_8X8.FNT b/16/lib/modex105/FONTEDIT/ROM_8X8.FNT new file mode 100644 index 00000000..708a4f92 Binary files /dev/null and b/16/lib/modex105/FONTEDIT/ROM_8X8.FNT differ diff --git a/16/lib/modex105/FONTEDIT/SPACEAGE.FNT b/16/lib/modex105/FONTEDIT/SPACEAGE.FNT new file mode 100644 index 00000000..029bae4e Binary files /dev/null and b/16/lib/modex105/FONTEDIT/SPACEAGE.FNT differ diff --git a/16/lib/modex105/FONTEDIT/SYSTEM.FNT b/16/lib/modex105/FONTEDIT/SYSTEM.FNT new file mode 100644 index 00000000..9a1965eb Binary files /dev/null and b/16/lib/modex105/FONTEDIT/SYSTEM.FNT differ diff --git a/16/lib/modex105/MODE-X.TXT b/16/lib/modex105/MODE-X.TXT new file mode 100644 index 00000000..4e18d962 --- /dev/null +++ b/16/lib/modex105/MODE-X.TXT @@ -0,0 +1,44 @@ +The following is a FAQ (Frequently Asked Question) summary of +information and assembly routines for Mode "X" Graphics. + +An overview of Mode "X" for the VGA Adaptor: + +1) Mode "X" is a 256 color graphics mode that is available on *ANY* VGA +card with the minimum of 256K video RAM. It is capable of providing +higher resoultions than the only "Official" 256 color mode, mode 13h. +(In quickbasic that is mode 13) + +2) Mode "X" comes in 8 different flavors: 320 or 360 pixels +horizontally, and 200, 240, 400, and 480 pixels vertically. + +3) Since mode X is not supported by the VGA BIOS, there is no built in +support for it. A program must provide its own routines for *ALL* +operations in Mode "X", including setting up the video mode. + +4) Unlike Mode 13h, which has one display page, Mode "X" allows from 1 +to 4 video pages, depending upon the resoultion selected. The reason +that Mode 13h has but one page is that it activates a VGA hardware +feature known as CHAIN4, which prevents access to all but 64K of VGA's +video RAM. CHAIN4 is what provides mode 13h's linear addres space. + +5) Unlike Mode 13h, where each 256 color (1-byte) pixel has a unique +address in the E000: segement, in Mode X there are Four (4) Pixels +at each address in E000: segment. The VGA's control registers allow you +to control which of the 4 pixels is currently available at an address. + +6) It is possible to use the VGA's control registers to operate on 2 or +more of the Pixels at the same address at the same time. The CPU can +write one color value, and set up to 4 pixels with that value at the +same time. + +7) Video RAM that is not being used for the current screen display can +be used to store images and patterns. These images and patterns can be +copied to other parts of the Video RAM 4 bytes (32 bits) at a time, +which is much faster than the 8 bits (1 byte) at time that is possible +over the ISA BUS. (16 Bit BUS operations can produce erroneous results) + +If anything is unclear, inadequate, or you just plain want to know more +or have other specific questions, please send me a message. + + +-Matt Pritchard diff --git a/16/lib/modex105/MODEX.ASM b/16/lib/modex105/MODEX.ASM new file mode 100644 index 00000000..2985fd80 --- /dev/null +++ b/16/lib/modex105/MODEX.ASM @@ -0,0 +1,3295 @@ +;======================================================== +; MODEX.ASM - A Complete Mode X Library +; +; Version 1.04 Release, 3 May 1993, By Matt Pritchard +; With considerable input from Michael Abrash +; +; The following information is donated to the public domain in +; the hopes that save other programmers much frustration. +; +; If you do use this code in a product, it would be nice if +; you include a line like "Mode X routines by Matt Pritchard" +; in the credits. +; +; ========================================================= +; +; All of this code is designed to be assembled with MASM 5.10a +; but TASM 3.0 could be used as well. +; +; The routines contained are designed for use in a MEDIUM model +; program. All Routines are FAR, and is assumed that a DGROUP +; data segment exists and that DS will point to it on entry. +; +; For all routines, the AX, BX, CX, DX, ES and FLAGS registers +; will not be preserved, while the DS, BP, SI and DI registers +; will be preserved. +; +; Unless specifically noted, All Parameters are assumed to be +; "PASSED BY VALUE". That is, the actual value is placed on +; the stack. When a reference is passed it is assumed to be +; a near pointer to a variable in the DGROUP segment. +; +; Routines that return a single 16-Bit integer value will +; return that value in the AX register. +; +; This code will *NOT* run on an 8086/8088 because 80286+ +; specific instructions are used. If you have an 8088/86 +; and VGA, you can buy an 80386-40 motherboard for about +; $160 and move into the 90's. +; +; This code is reasonably optimized: Most drawing loops have +; been unrolled once and memory references are minimized by +; keeping stuff in registers when possible. +; +; Error Trapping varies by Routine. No Clipping is performed +; so the caller should verify that all coordinates are valid. +; +; Several Macros are used to simplify common 2 or 3 instruction +; sequences. Several Single letter Text Constants also +; simplify common assembler expressions like "WORD PTR". +; +; ------------------ Mode X Variations ------------------ +; +; Mode # Screen Size Max Pages Aspect Ratio (X:Y) +; +; 0 320 x 200 4 Pages 1.2:1 +; 1 320 x 400 2 Pages 2.4:1 +; 2 360 x 200 3 Pages 1.35:1 +; 3 360 x 400 1 Page 2.7:1 +; 4 320 x 240 3 Pages 1:1 +; 5 320 x 480 1 Page 2:1 +; 6 360 x 240 3 Pages 1.125:1 +; 7 360 x 480 1 Page 2.25:1 +; +; -------------------- The Legal Stuff ------------------ +; +; No warranty, either written or implied, is made as to +; the accuracy and usability of this code product. Use +; at your own risk. Batteries not included. Pepperoni +; and extra cheese available for an additional charge. +; +; ----------------------- The Author -------------------- +; +; Matt Pritchard is a paid programmer who'd rather be +; writing games. He can be reached at: P.O. Box 140264, +; Irving, TX 75014 USA. Michael Abrash is a living +; god, who now works for Bill Gates (Microsoft). +; +; -------------------- Revision History ----------------- +; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI +; SET_MODEX now saves SI +; 5-3-93: v1.04 - added LOAD_DAC_REGISTERS and +; READ_DAC_REGISTERS. Expanded CLR Macro +; to handle multiple registers +; + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ===== MACROS ===== + + ; Macro to OUT a 16 bit value to an I/O port + +OUT_16 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AX not setup + MOV AX, Value ; then Get Data Value + ENDIF + OUT DX, AX ; Set I/O Register(s) +ENDM + + ; Macro to OUT a 8 bit value to an I/O Port + +OUT_8 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AL not Setup + MOV AL, Value ; then Get Data Value + ENDIF + OUT DX, AL ; Set I/O Register +ENDM + + ; macros to PUSH and POP multiple registers + +PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + PUSH R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + +POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + POP R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF +ENDM + + ; Macro to Clear Registers to 0 + +CLR MACRO Register, R2, R3, R4, R5, R6 + IFNB + XOR Register, Register ; Set Register = 0 + CLR R2, R3, R4, R5, R6 + ENDIF +ENDM + + ; Macros to Decrement Counter & Jump on Condition + +LOOPx MACRO Register, Destination + DEC Register ; Counter-- + JNZ Destination ; Jump if not 0 +ENDM + +LOOPjz MACRO Register, Destination + DEC Register ; Counter-- + JZ Destination ; Jump if 0 +ENDM + + + ; ===== General Constants ===== + + False EQU 0 + True EQU -1 + nil EQU 0 + + b EQU BYTE PTR + w EQU WORD PTR + d EQU DWORD PTR + o EQU OFFSET + f EQU FAR PTR + s EQU SHORT + ?x4 EQU + ?x3 EQU + + ; ===== VGA Register Values ===== + + VGA_Segment EQU 0A000h ; Vga Memory Segment + + ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller + GC_Index EQU 03CEh ; VGA Graphics Controller + SC_Index EQU 03C4h ; VGA Sequencer Controller + SC_Data EQU 03C5h ; VGA Sequencer Data Port + CRTC_Index EQU 03D4h ; VGA CRT Controller + CRTC_Data EQU 03D5h ; VGA CRT Controller Data + MISC_OUTPUT EQU 03C2h ; VGA Misc Register + INPUT_1 EQU 03DAh ; Input Status #1 Register + + DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register + DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register + PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W + + PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg + MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg + READ_MAP EQU 004h ; GC Index: Read Map Register + START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi + START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo + + MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1 + MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1 + ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes + + CHAIN4_OFF EQU 00604h ; Chain 4 mode Off + ASYNC_RESET EQU 00100h ; (A)synchronous Reset + SEQU_RESTART EQU 00300h ; Sequencer Restart + + LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches + LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU + + VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit + PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane # + ALL_PLANES EQU 0Fh ; All Bit Planes Selected + CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data + + GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set + ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer + ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer + + ; Constants Specific for these routines + + NUM_MODES EQU 8 ; # of Mode X Variations + + ; Specific Mode Data Table format... + +Mode_Data_Table STRUC + M_MiscR DB ? ; Value of MISC_OUTPUT register + M_Pages DB ? ; Maximum Possible # of pages + M_XSize DW ? ; X Size Displayed on screen + M_YSize DW ? ; Y Size Displayed on screen + M_XMax DW ? ; Maximum Possible X Size + M_YMax DW ? ; Maximum Possible Y Size + M_CRTC DW ? ; Table of CRTC register values +Mode_Data_Table ENDS + + ; ===== DGROUP STORAGE NEEDED (42 BYTES) ===== + + .DATA? + +SCREEN_WIDTH DW 0 ; Width of a line in Bytes +SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels + +LAST_PAGE DW 0 ; # of Display Pages +PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page + +PAGE_SIZE DW 0 ; Size of Page in Addr Bytes + +DISPLAY_PAGE DW 0 ; Page # currently displayed +ACTIVE_PAGE DW 0 ; Page # currently active + +CURRENT_PAGE DW 0 ; Offset of current Page +CURRENT_SEGMENT DW 0 ; Segment of VGA memory + +CURRENT_XOFFSET DW 0 ; Current Display X Offset +CURRENT_YOFFSET DW 0 ; Current Display Y Offset + +CURRENT_MOFFSET DW 0 ; Current Start Offset + +MAX_XOFFSET DW 0 ; Current Display X Offset +MAX_YOFFSET DW 0 ; Current Display Y Offset + +CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127 +CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255 + + .CODE + + ; ===== DATA TABLES ===== + + ; Data Tables, Put in Code Segment for Easy Access + ; (Like when all the other Segment Registers are in + ; use!!) and reduced DGROUP requirements... + + ; Bit Mask Tables for Left/Right/Character Masks + +Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H + +Right_Clip_Mask DB 01H, 03H, 07H, 0FH + + ; Bit Patterns for converting character fonts + +Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH + DB 01H,09H,05H,0DH,03H,0BH,07H,0FH + + ; CRTC Register Values for Various Configurations + +MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes + DW 04009H ; Cell Height (1 Scan Line) + DW 00014H ; Dword Mode off + DW 0E317H ; turn on Byte Mode + DW nil ; End of CRTC Data for 400/480 Line Mode + +MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes + DW 04109H ; Cell Height (2 Scan Lines) + DW 00014H ; Dword Mode off + DW 0E317H ; turn on Byte Mode + DW nil ; End of CRTC Data for 200/240 Line Mode + +MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels + DW 05F00H ; Horz total + DW 04F01H ; Horz Displayed + DW 05002H ; Start Horz Blanking + DW 08203H ; End Horz Blanking + DW 05404H ; Start H Sync + DW 08005H ; End H Sync + DW nil ; End of CRTC Data for 320 Horz pixels + +MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels + DW 06B00H ; Horz total + DW 05901H ; Horz Displayed + DW 05A02H ; Start Horz Blanking + DW 08E03H ; End Horz Blanking + DW 05E04H ; Start H Sync + DW 08A05H ; End H Sync + DW nil ; End of CRTC Data for 360 Horz pixels + +MODE_200_Tall: +MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes + DW 0BF06H ; Vertical Total + DW 01F07H ; Overflow + DW 09C10H ; V Sync Start + DW 08E11H ; V Sync End/Prot Cr0 Cr7 + DW 08F12H ; Vertical Displayed + DW 09615H ; V Blank Start + DW 0B916H ; V Blank End + DW nil ; End of CRTC Data for 200/400 Lines + +MODE_240_Tall: +MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes + DW 00D06H ; Vertical Total + DW 03E07H ; Overflow + DW 0EA10H ; V Sync Start + DW 08C11H ; V Sync End/Prot Cr0 Cr7 + DW 0DF12H ; Vertical Displayed + DW 0E715H ; V Blank Start + DW 00616H ; V Blank End + DW nil ; End of CRTC Data for 240/480 Lines + + ; Table of Display Mode Tables + +MODE_TABLE: + DW o MODE_320x200, o MODE_320x400 + DW o MODE_360x200, o MODE_360x400 + DW o MODE_320x240, o MODE_320x480 + DW o MODE_360x240, o MODE_360x480 + + ; Table of Display Mode Components + +MODE_320x200: ; Data for 320 by 200 Pixels + + DB 063h ; 400 scan Lines & 25 Mhz Clock + DB 4 ; Maximum of 4 Pages + DW 320, 200 ; Displayed Pixels (X,Y) + DW 1302, 816 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_200_Tall + DW o MODE_Double_Line, nil + +MODE_320x400: ; Data for 320 by 400 Pixels + + DB 063h ; 400 scan Lines & 25 Mhz Clock + DB 2 ; Maximum of 2 Pages + DW 320, 400 ; Displayed Pixels X,Y + DW 648, 816 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_400_Tall + DW o MODE_Single_Line, nil + +MODE_360x240: ; Data for 360 by 240 Pixels + + DB 0E7h ; 480 scan Lines & 28 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 360, 240 ; Displayed Pixels X,Y + DW 1092, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, o MODE_240_Tall + DW o MODE_Double_Line , nil + +MODE_360x480: ; Data for 360 by 480 Pixels + + DB 0E7h ; 480 scan Lines & 28 Mhz Clock + DB 1 ; Only 1 Page Possible + DW 360, 480 ; Displayed Pixels X,Y + DW 544, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, o MODE_480_Tall + DW o MODE_Single_Line , nil + +MODE_320x240: ; Data for 320 by 240 Pixels + + DB 0E3h ; 480 scan Lines & 25 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 320, 240 ; Displayed Pixels X,Y + DW 1088, 818 ; Max Possible X and Y Sizes + + DW o MODE_320_Wide, o MODE_240_Tall + DW o MODE_Double_Line, nil + +MODE_320x480: ; Data for 320 by 480 Pixels + + DB 0E3h ; 480 scan Lines & 25 Mhz Clock + DB 1 ; Only 1 Page Possible + DW 320, 480 ; Displayed Pixels X,Y + DW 540, 818 ; Max Possible X and Y Sizes + + DW o MODE_320_WIDE, o MODE_480_Tall + DW o MODE_Single_Line, nil + +MODE_360x200: ; Data for 360 by 200 Pixels + + DB 067h ; 400 scan Lines & 28 Mhz Clock + DB 3 ; Maximum of 3 Pages + DW 360, 200 ; Displayed Pixels (X,Y) + DW 1302, 728 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, MODE_200_Tall + DW o MODE_Double_Line, nil + +MODE_360x400: ; Data for 360 by 400 Pixels + + DB 067h ; 400 scan Lines & 28 Mhz Clock + DB 1 ; Maximum of 1 Pages + DW 360, 400 ; Displayed Pixels X,Y + DW 648, 816 ; Max Possible X and Y Sizes + + DW o MODE_360_Wide, MODE_400_Tall + DW o MODE_Single_Line, nil + + + ; ===== MODE X SETUP ROUTINES ===== + +;====================================================== +;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%) +;====================================================== +; +; Sets Up the specified version of Mode X. Allows for +; the setup of multiple video pages, and a virtual +; screen which can be larger than the displayed screen +; (which can then be scrolled a pixel at a time) +; +; ENTRY: ModeType = Desired Screen Resolution (0-7) +; +; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio +; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio +; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio +; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio +; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio +; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio +; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio +; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio +; +; MaxXpos = The Desired Virtual Screen Width +; MaxYpos = The Desired Virtual Screen Height +; Pages = The Desired # of Video Pages +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +SVM_STACK STRUC + SVM_Table DW ? ; Offset of Mode Info Table + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + SVM_Pages DW ? ; # of Screen Pages desired + SVM_Ysize DW ? ; Vertical Screen Size Desired + SVM_Xsize DW ? ; Horizontal Screen Size Desired + SVM_Mode DW ? ; Display Resolution Desired +SVM_STACK ENDS + + PUBLIC SET_VGA_MODEX + +SET_VGA_MODEX PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 2 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + ; Check Legality of Mode Request.... + + MOV BX, [BP].SVM_Mode ; Get Requested Mode # + CMP BX, NUM_MODES ; Is it 0..7? + JAE @SVM_BadModeSetup ; If Not, Error out + + SHL BX, 1 ; Scale BX + MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + MOV [BP].SVM_Table, SI ; Save ptr for later use + + ; Check # of Requested Display Pages + + MOV CX, [BP].SVM_Pages ; Get # of Requested Pages + CLR CH ; Set Hi Word = 0! + CMP CL, CS:[SI].M_Pages ; Check # Pages for mode + JA @SVM_BadModeSetup ; Report Error if too Many Pages + JCXZ @SVM_BadModeSetup ; Report Error if 0 Pages + + ; Check Validity of X Size + + AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0 + + MOV AX, [BP].SVM_XSize ; Get Logical Screen Width + CMP AX, CS:[SI].M_XSize ; Check against Displayed X + JB @SVM_BadModeSetup ; Report Error if too small + CMP AX, CS:[SI].M_XMax ; Check against Max X + JA @SVM_BadModeSetup ; Report Error if too big + + ; Check Validity of Y Size + + MOV BX, [BP].SVM_YSize ; Get Logical Screen Height + CMP BX, CS:[SI].M_YSize ; Check against Displayed Y + JB @SVM_BadModeSetup ; Report Error if too small + CMP BX, CS:[SI].M_YMax ; Check against Max Y + JA @SVM_BadModeSetup ; Report Error if too big + + ; Enough memory to Fit it all? + + SHR AX, 2 ; # of Bytes:Line = XSize/4 + MUL CX ; AX = Bytes/Line * Pages + MUL BX ; DX:AX = Total VGA mem needed + JNO @SVM_Continue ; Exit if Total Size > 256K + + DEC DX ; Was it Exactly 256K??? + OR DX, AX ; (DX = 1, AX = 0000) + JZ @SVM_Continue ; if so, it's valid... + +@SVM_BadModeSetup: + + CLR AX ; Return Value = False + JMP @SVM_Exit ; Normal Exit + +@SVM_Continue: + + MOV AX, 13H ; Start with Mode 13H + INT 10H ; Let BIOS Set Mode + + OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode + OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset + OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size + OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ... + + OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register + INC DX ; Point to Data + IN AL, DX ; Get Value, Bit 7 = Protect + AND AL, 7FH ; Mask out Write Protect + OUT DX, AL ; And send it back + + MOV DX, CRTC_INDEX ; Vga Crtc Registers + ADD SI, M_CRTC ; SI -> CRTC Parameter Data + + ; Load Tables of CRTC Parameters from List of Tables + +@SVM_Setup_Table: + + MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl + ADD SI, 2 ; Point to next Ptr Entry + OR DI, DI ; A nil Ptr means that we have + JZ @SVM_Set_Data ; finished CRTC programming + +@SVM_Setup_CRTC: + MOV AX, CS:[DI] ; Get CRTC Data from Table + ADD DI, 2 ; Advance Pointer + OR AX, AX ; At End of Data Table? + JZ @SVM_Setup_Table ; If so, Exit & get next Table + + OUT DX, AX ; Reprogram VGA CRTC reg + JMP s @SVM_Setup_CRTC ; Process Next Table Entry + + ; Initialize Page & Scroll info, DI = 0 + +@SVM_Set_Data: + MOV DISPLAY_PAGE, DI ; Display Page = 0 + MOV ACTIVE_PAGE, DI ; Active Page = 0 + MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0 + MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0 + MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0 + MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0 + + MOV AX, VGA_SEGMENT ; Segment for VGA memory + MOV CURRENT_SEGMENT, AX ; Save for Future LES's + + ; Set Logical Screen Width, X Scroll and Our Data + + MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info + MOV AX, [BP].SVM_Xsize ; Get Display Width + + MOV CX, AX ; CX = Logical Width + SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value + MOV MAX_XOFFSET, CX ; Set Maximum X Scroll + + SHR AX, 2 ; Bytes = Pixels / 4 + MOV SCREEN_WIDTH, AX ; Save Width in Pixels + + SHR AX, 1 ; Offset Value = Bytes / 2 + MOV AH, 13h ; CRTC Offset Register Index + XCHG AL, AH ; Switch format for OUT + OUT DX, AX ; Set VGA CRTC Offset Reg + + ; Setup Data table, Y Scroll, Misc for Other Routines + + MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height + + MOV CX, AX ; CX = Logical Height + SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value + MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll + + MOV SCREEN_HEIGHT, AX ; Save Height in Pixels + MUL SCREEN_WIDTH ; AX = Page Size in Bytes, + MOV PAGE_SIZE, AX ; Save Page Size + + MOV CX, [BP].SVM_Pages ; Get # of Pages + MOV LAST_PAGE, CX ; Save # of Pages + + CLR BX ; Page # = 0 + MOV DX, BX ; Page 0 Offset = 0 + +@SVM_Set_Pages: + + MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset + ADD BX, 2 ; Page#++ + ADD DX, AX ; Compute Addr of Next Page + LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set + + ; Clear VGA Memory + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + LES DI, d CURRENT_PAGE ; -> Start of VGA memory + + CLR AX ; AX = 0 + CLD ; Block Xfer Forwards + MOV CX, 8000H ; 32K * 4 * 2 = 256K + REP STOSW ; Clear dat memory! + + ; Setup Font Pointers + + MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127 + MOV AX, GET_CHAR_PTR ; Service to Get Pointer + INT 10h ; Call VGA BIOS + + MOV CHARSET_LOW, BP ; Save Char Set Offset + MOV CHARSET_LOW+2, ES ; Save Char Set Segment + + MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255 + MOV AX, GET_CHAR_PTR ; Service to Get Pointer + INT 10h ; Call VGA BIOS + + MOV CHARSET_HI, BP ; Save Char Set Offset + MOV CHARSET_HI+2, ES ; Save Char Set Segment + + MOV AX, True ; Return Success Code + +@SVM_EXIT: + ADD SP, 2 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 8 ; Exit & Clean Up Stack + +SET_VGA_MODEX ENDP + + +;================== +;SET_MODEX% (Mode%) +;================== +; +; Quickie Mode Set - Sets Up Mode X to Default Configuration +; +; ENTRY: ModeType = Desired Screen Resolution (0-7) +; (See SET_VGA_MODEX for list) +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +SM_STACK STRUC + DW ?,? ; BP, SI + DD ? ; Caller + SM_Mode DW ? ; Desired Screen Resolution +SM_STACK ENDS + + PUBLIC SET_MODEX + +SET_MODEX PROC FAR + + PUSHx BP, SI ; Preserve Important registers + MOV BP, SP ; Set up Stack Frame + + CLR AX ; Assume Failure + MOV BX, [BP].SM_Mode ; Get Desired Mode # + CMP BX, NUM_MODES ; Is it a Valid Mode #? + JAE @SMX_Exit ; If Not, don't Bother + + PUSH BX ; Push Mode Parameter + + SHL BX, 1 ; Scale BX to word Index + MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + + PUSH CS:[SI].M_XSize ; Push Default X Size + PUSH CS:[SI].M_Ysize ; Push Default Y size + MOV AL, CS:[SI].M_Pages ; Get Default # of Pages + CLR AH ; Hi Byte = 0 + PUSH AX ; Push # Pages + + CALL f SET_VGA_MODEX ; Set up Mode X! + +@SMX_Exit: + POPx SI, BP ; Restore Registers + RET 2 ; Exit & Clean Up Stack + +SET_MODEX ENDP + + + ; ===== BASIC GRAPHICS PRIMITIVES ===== + +;============================ +;CLEAR_VGA_SCREEN (ColorNum%) +;============================ +; +; Clears the active display page +; +; ENTRY: ColorNum = Color Value to fill the page with +; +; EXIT: No meaningful values returned +; + +CVS_STACK STRUC + DW ?,? ; DI, BP + DD ? ; Caller + CVS_COLOR DB ?,? ; Color to Set Screen to +CVS_STACK ENDS + + PUBLIC CLEAR_VGA_SCREEN + +CLEAR_VGA_SCREEN PROC FAR + + PUSHx BP, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AL, [BP].CVS_COLOR ; Get Color + MOV AH, AL ; Copy for Word Write + CLD ; Block fill Forwards + + MOV CX, PAGE_SIZE ; Get Size of Page + SHR CX, 1 ; Divide by 2 for Words + REP STOSW ; Block Fill VGA memory + + POPx DI, BP ; Restore Saved Registers + RET 2 ; Exit & Clean Up Stack + +CLEAR_VGA_SCREEN ENDP + + +;=================================== +;SET_POINT (Xpos%, Ypos%, ColorNum%) +;=================================== +; +; Plots a single Pixel on the active display page +; +; ENTRY: Xpos = X position to plot pixel at +; Ypos = Y position to plot pixel at +; ColorNum = Color to plot pixel with +; +; EXIT: No meaningful values returned +; + +SP_STACK STRUC + DW ?,? ; BP, DI + DD ? ; Caller + SETP_Color DB ?,? ; Color of Point to Plot + SETP_Ypos DW ? ; Y pos of Point to Plot + SETP_Xpos DW ? ; X pos of Point to Plot +SP_STACK ENDS + + PUBLIC SET_POINT + +SET_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel + MUL SCREEN_WIDTH ; Get Offset to Start of Line + + MOV BX, [BP].SETP_Xpos ; Get Xpos + MOV CX, BX ; Copy to extract Plane # from + SHR BX, 2 ; X offset (Bytes) = Xpos/4 + ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register + AND CL, PLANE_BITS ; Get Plane Bits + SHL AH, CL ; Get Plane Select Value + OUT_16 SC_Index, AX ; Select Plane + + MOV AL,[BP].SETP_Color ; Get Pixel Color + MOV ES:[DI+BX], AL ; Draw Pixel + + POPx DI, BP ; Restore Saved Registers + RET 6 ; Exit and Clean up Stack + +SET_POINT ENDP + + +;========================== +;READ_POINT% (Xpos%, Ypos%) +;========================== +; +; Read the color of a pixel from the Active Display Page +; +; ENTRY: Xpos = X position of pixel to read +; Ypos = Y position of pixel to read +; +; EXIT: AX = Color of Pixel at (Xpos, Ypos) +; + +RP_STACK STRUC + DW ?,? ; BP, DI + DD ? ; Caller + RP_Ypos DW ? ; Y pos of Point to Read + RP_Xpos DW ? ; X pos of Point to Read +RP_STACK ENDS + + PUBLIC READ_POINT + +READ_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].RP_Ypos ; Get Line # of Pixel + MUL SCREEN_WIDTH ; Get Offset to Start of Line + + MOV BX, [BP].RP_Xpos ; Get Xpos + MOV CX, BX + SHR BX, 2 ; X offset (Bytes) = Xpos/4 + ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + MOV AL, READ_MAP ; GC Read Mask Register + MOV AH, CL ; Get Xpos + AND AH, PLANE_BITS ; & mask out Plane # + OUT_16 GC_INDEX, AX ; Select Plane to read in + + CLR AH ; Clear Return Value Hi byte + MOV AL, ES:[DI+BX] ; Get Color of Pixel + + POPx DI, BP ; Restore Saved Registers + RET 4 ; Exit and Clean up Stack + +READ_POINT ENDP + + +;====================================================== +;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) +;====================================================== +; +; Fills a rectangular block on the active display Page +; +; ENTRY: Xpos1 = Left X position of area to fill +; Ypos1 = Top Y position of area to fill +; Xpos2 = Right X position of area to fill +; Ypos2 = Bottom Y position of area to fill +; ColorNum = Color to fill area with +; +; EXIT: No meaningful values returned +; + +FB_STACK STRUC + DW ?x4 ; DS, DI, SI, BP + DD ? ; Caller + FB_Color DB ?,? ; Fill Color + FB_Ypos2 DW ? ; Y pos of Lower Right Pixel + FB_Xpos2 DW ? ; X pos of Lower Right Pixel + FB_Ypos1 DW ? ; Y pos of Upper Left Pixel + FB_Xpos1 DW ? ; X pos of Upper Left Pixel +FB_STACK ENDS + + PUBLIC FILL_BLOCK + +FILL_BLOCK PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + + ; Validate Pixel Coordinates + ; If necessary, Swap so X1 <= X2, Y1 <= Y2 + + MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2? + MOV BX, [BP].FB_Ypos2 ; BX = Y2 + CMP AX, BX + JLE @FB_NOSWAP1 + + MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1 + XCHG AX, BX ; on stack for future use + +@FB_NOSWAP1: + SUB BX, AX ; Get Y width + INC BX ; Add 1 to avoid 0 value + MOV [BP].FB_Ypos2, BX ; Save in Ypos2 + + MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line + ADD DI, AX ; DI = Start of Line Y1 + + MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2 + MOV BX, [BP].FB_Xpos2 ; + CMP AX, BX + JLE @FB_NOSWAP2 ; Skip Ahead if Ok + + MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2 + XCHG AX, BX ; on stack for future use + + ; All our Input Values are in order, Now determine + ; How many full "bands" 4 pixels wide (aligned) there + ; are, and if there are partial bands (<4 pixels) on + ; the left and right edges. + +@FB_NOSWAP2: + MOV DX, AX ; DX = X1 (Pixel Position) + SHR DX, 2 ; DX/4 = Bytes into Line + ADD DI, DX ; DI = Addr of Upper-Left Corner + + MOV CX, BX ; CX = X2 (Pixel Position) + SHR CX, 2 ; CX/4 = Bytes into Line + + CMP DX, CX ; Start and end in same band? + JNE @FB_NORMAL ; if not, check for l & r edges + JMP @FB_ONE_BAND_ONLY ; if so, then special processing + +@FB_NORMAL: + SUB CX, DX ; CX = # bands -1 + MOV SI, AX ; SI = PLANE#(X1) + AND SI, PLANE_BITS ; if Left edge is aligned then + JZ @FB_L_PLANE_FLUSH ; no special processing.. + + ; Draw "Left Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask + + MOV SI, DI ; SI = Copy of Start Addr (UL) + + MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_LEFT_LOOP: + MOV ES:[SI], AL ; Fill in Left Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn + + MOV ES:[SI], AL ; Fill in Left Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn + +@FB_LEFT_CONT: + + INC DI ; Point to Middle (or Right) Block + DEC CX ; Reset CX instead of JMP @FB_RIGHT + +@FB_L_PLANE_FLUSH: + INC CX ; Add in Left band to middle block + + ; DI = Addr of 1st middle Pixel (band) to fill + ; CX = # of Bands to fill -1 + +@FB_RIGHT: + MOV SI, [BP].FB_Xpos2 ; Get Xpos2 + AND SI, PLANE_BITS ; Get Plane values + CMP SI, 0003 ; Plane = 3? + JE @FB_R_EDGE_FLUSH ; Hey, add to middle + + ; Draw "Right Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask + + MOV SI, DI ; Get Addr of Left Edge + ADD SI, CX ; Add Width-1 (Bands) + DEC SI ; To point to top of Right Edge + + MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_RIGHT_LOOP: + MOV ES:[SI], AL ; Fill in Right Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn + + MOV ES:[SI], AL ; Fill in Right Edge Pixels + ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn + +@FB_RIGHT_CONT: + + DEC CX ; Minus 1 for Middle bands + JZ @FB_EXIT ; Uh.. no Middle bands... + +@FB_R_EDGE_FLUSH: + + ; DI = Addr of Upper Left block to fill + ; CX = # of Bands to fill in (width) + + OUT_8 SC_Data, ALL_PLANES ; Write to All Planes + + MOV DX, SCREEN_WIDTH ; DX = DI Increment + SUB DX, CX ; = Screen_Width-# Planes Filled + + MOV BX, CX ; BX = Quick Refill for CX + MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill + MOV AL, [BP].FB_Color ; Get Fill Color + +@FB_MIDDLE_LOOP: + REP STOSB ; Fill in entire line + + MOV CX, BX ; Recharge CX (Line Width) + ADD DI, DX ; Point to start of Next Line + LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn + + JMP s @FB_EXIT ; Outa here + +@FB_ONE_BAND_ONLY: + MOV SI, AX ; Get Left Clip Mask, Save X1 + AND SI, PLANE_BITS ; Mask out Row # + MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask + MOV SI, BX ; Get Right Clip Mask, Save X2 + AND SI, PLANE_BITS ; Mask out Row # + AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + + MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw + MOV AL, [BP].FB_Color ; Get Fill Color + MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + +@FB_ONE_LOOP: + MOV ES:[DI], AL ; Fill in Pixels + ADD DI, BX ; Point to Next Line (Below) + LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn + + MOV ES:[DI], AL ; Fill in Pixels + ADD DI, BX ; Point to Next Line (Below) + LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn + +@FB_EXIT: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +FILL_BLOCK ENDP + + +;===================================================== +;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) +;===================================================== +; +; Draws a Line on the active display page +; +; ENTRY: Xpos1 = X position of first point on line +; Ypos1 = Y position of first point on line +; Xpos2 = X position of last point on line +; Ypos2 = Y position of last point on line +; ColorNum = Color to draw line with +; +; EXIT: No meaningful values returned +; + +DL_STACK STRUC + DW ?x3 ; DI, SI, BP + DD ? ; Caller + DL_ColorF DB ?,? ; Line Draw Color + DL_Ypos2 DW ? ; Y pos of last point + DL_Xpos2 DW ? ; X pos of last point + DL_Ypos1 DW ? ; Y pos of first point + DL_Xpos1 DW ? ; X pos of first point +DL_STACK ENDS + + PUBLIC DRAW_LINE + +DRAW_LINE PROC FAR + + PUSHx BP, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + MOV CH, [BP].DL_ColorF ; Save Line Color in CH + + ; Check Line Type + + MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2? + MOV DI, [BP].DL_Xpos2 ; DX = X2 + CMP SI, DI ; Is X1 < X2 + JE @DL_VLINE ; If X1=X2, Draw Vertical Line + JL @DL_NOSWAP1 ; If X1 < X2, don't swap + + XCHG SI, DI ; X2 IS > X1, SO SWAP THEM + +@DL_NOSWAP1: + + ; SI = X1, DI = X2 + + MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2? + CMP AX, [BP].DL_Ypos2 ; Y1 = Y2? + JE @DL_HORZ ; If so, Draw a Horizontal Line + + JMP @DL_BREZHAM ; Diagonal line... go do it... + + ; This Code draws a Horizontal Line in Mode X where: + ; SI = X1, DI = X2, and AX = Y1/Y2 + +@DL_HORZ: + + MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width + MOV DX, AX ; CX = Line offset into Page + + MOV AX, SI ; Get Left edge, Save X1 + AND SI, PLANE_BITS ; Mask out Row # + MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask + MOV CX, DI ; Get Right edge, Save X2 + AND DI, PLANE_BITS ; Mask out Row # + MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte + + SHR AX, 2 ; Get X1 Byte # (=X1/4) + SHR CX, 2 ; Get X2 Byte # (=X2/4) + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + ADD DI, DX ; Point to Start of Line + ADD DI, AX ; Point to Pixel X1 + + SUB CX, AX ; CX = # Of Bands (-1) to set + JNZ @DL_LONGLN ; jump if longer than one segment + + AND BL, BH ; otherwise, merge clip masks + +@DL_LONGLN: + + OUT_8 SC_Data, BL ; Set the Left Clip Mask + + MOV AL, [BP].DL_ColorF ; Get Line Color + MOV BL, AL ; BL = Copy of Line Color + STOSB ; Set Left (1-4) Pixels + + JCXZ @DL_EXIT ; Done if only one Line Segment + + DEC CX ; CX = # of Middle Segments + JZ @DL_XRSEG ; If no middle segments.... + + ; Draw Middle Segments + + OUT_8 DX, ALL_PLANES ; Write to ALL Planes + + MOV AL, BL ; Get Color from BL + REP STOSB ; Draw Middle (4 Pixel) Segments + +@DL_XRSEG: + OUT_8 DX, BH ; Select Planes for Right Clip Mask + MOV AL, BL ; Get Color Value + STOSB ; Draw Right (1-4) Pixels + + JMP s @DL_EXIT ; We Are Done... + + + ; This Code Draws A Vertical Line. On entry: + ; CH = Line Color, SI & DI = X1 + +@DL_VLINE: + + MOV AX, [BP].DL_Ypos1 ; AX = Y1 + MOV SI, [BP].DL_Ypos2 ; SI = Y2 + CMP AX, SI ; Is Y1 < Y2? + JLE @DL_NOSWAP2 ; if so, Don't Swap them + + XCHG AX, SI ; Ok, NOW Y1 < Y2 + +@DL_NOSWAP2: + + SUB SI, AX ; SI = Line Height (Y2-Y1+1) + INC SI + + ; AX = Y1, DI = X1, Get offset into Page into AX + + MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width + MOV DX, DI ; Copy Xpos into DX + SHR DI, 2 ; DI = Xpos/4 + ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1 + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + ADD DI, AX ; Point to Pixel X1, Y1 + + ;Select Plane + + MOV CL, DL ; CL = Save X1 + AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #) + MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1 + SHL AH, CL ; Change to Correct Plane # + OUT_16 SC_Index, AX ; Select Plane + + MOV AL, CH ; Get Saved Color + MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By + +@DL_VLoop: + MOV ES:[DI], AL ; Draw Single Pixel + ADD DI, BX ; Point to Next Line + LOOPjz SI, @DL_EXIT ; Lines--, Exit if done + + MOV ES:[DI], AL ; Draw Single Pixel + ADD DI, BX ; Point to Next Line + LOOPx SI, @DL_VLoop ; Lines--, Loop until Done + +@DL_EXIT: + + JMP @DL_EXIT2 ; Done! + + ; This code Draws a diagonal line in Mode X + +@DL_BREZHAM: + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, [BP].DL_Ypos1 ; get Y1 value + MOV BX, [BP].DL_Ypos2 ; get Y2 value + MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos + + CMP BX, AX ; Y2-Y1 is? + JNC @DL_DeltaYOK ; if Y2>=Y1 then goto... + + XCHG BX, AX ; Swap em... + MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos + +@DL_DeltaYOK: + MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1 + + ADD DI, AX ; DI -> Start of Line Y1 on Page + MOV AX, CX ; AX = Xpos (X1) + SHR AX, 2 ; /4 = Byte Offset into Line + ADD DI, AX ; DI = Starting pos (X1,Y1) + + MOV AL, 11h ; Staring Mask + AND CL, PLANE_BITS ; Get Plane # + SHL AL, CL ; and shift into place + MOV AH, [BP].DL_ColorF ; Color in Hi Bytes + + PUSH AX ; Save Mask,Color... + + MOV AH, AL ; Plane # in AH + MOV AL, MAP_MASK ; Select Plane Register + OUT_16 SC_Index, AX ; Select initial plane + + MOV AX, [BP].DL_Xpos1 ; get X1 value + MOV BX, [BP].DL_Ypos1 ; get Y1 value + MOV CX, [BP].DL_Xpos2 ; get X2 value + MOV DX, [BP].DL_Ypos2 ; get Y2 value + + MOV BP, SCREEN_WIDTH ; Use BP for Line width to + ; to avoid extra memory access + + SUB DX, BX ; figure Delta_Y + JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1 + + ADD BX, DX ; put Y2 into Y1 + NEG DX ; abs(Delta_Y) + XCHG AX, CX ; and exchange X1 and X2 + +@DL_DeltaYOK2: + MOV BX, 08000H ; seed for fraction accumulator + + SUB CX, AX ; figure Delta_X + JC @DL_DrawLeft ; if negative, go left + + JMP @DL_DrawRight ; Draw Line that slopes right + +@DL_DrawLeft: + + NEG CX ; abs(Delta_X) + + CMP CX, DX ; is Delta_X < Delta_Y? + JB @DL_SteepLeft ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the left in Mode X + +@DL_ShallowLeft: + CLR AX ; zero low word of Delta_Y * 10000h + SUB AX, DX ; DX:AX <- DX * 0FFFFh + SBB DX, 0 ; include carry + DIV CX ; divide by Delta_X + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down... + +@DL_SLLLoop: + MOV ES:[DI], AH ; set first pixel, plane data set up + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLLL2nc ; move down on carry + + ADD DI, BP ; Move Down one line... + +@DL_SLLL2nc: + DEC DI ; Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + + ADD SI, BX ; add numerator to accumulator, + JNC @DL_SLLL3nc ; move down on carry + + ADD DI, BP ; Move Down one line... + +@DL_SLLL3nc: ; Now move left a pixel... + DEC DI ; Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + JMP s @DL_SLLLoop ; loop until done + +@DL_SLLExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a steep line to the left in Mode X + +@DL_SteepLeft: + CLR AX ; zero low word of Delta_Y * 10000h + XCHG DX, CX ; Delta_Y switched with Delta_X + DIV CX ; divide by Delta_Y + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe left + +@DL_STLLoop: + + MOV ES:[DI], AH ; set first pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_STLnc2 ; No carry, just move down! + + DEC DI ; Move Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@DL_STLnc2: + ADD DI, BP ; advance to next line. + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + + ADD SI, BX ; add numerator to accumulator + JNC @DL_STLnc3 ; No carry, just move down! + + DEC DI ; Move Left one addr + ROR AL, 1 ; Move Left one plane, back on 0 1 2 + CMP AL, 87h ; Wrap?, if AL <88 then Carry set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@DL_STLnc3: + ADD DI, BP ; advance to next line. + JMP s @DL_STLLoop ; Loop until done + +@DL_STLExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a line that goes to the Right... + +@DL_DrawRight: + CMP CX, DX ; is Delta_X < Delta_Y? + JB @DL_SteepRight ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the Right in Mode X + +@DL_ShallowRight: + CLR AX ; zero low word of Delta_Y * 10000h + SUB AX, DX ; DX:AX <- DX * 0FFFFh + SBB DX, 0 ; include carry + DIV CX ; divide by Delta_X + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down... + +@DL_SLRLoop: + MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLR2nc ; don't move down if carry not set + + ADD DI, BP ; Move Down one line... + +@DL_SLR2nc: ; Now move right a pixel... + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + + ADD SI, BX ; add numerator to accumulator + JNC @DL_SLR3nc ; don't move down if carry not set + + ADD DI, BP ; Move Down one line... + +@DL_SLR3nc: + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + JMP s @DL_SLRLoop ; loop till done + +@DL_SLRExit: + JMP @DL_EXIT2 ; and exit + + ; Draw a Steep line to the Right in Mode X + +@DL_SteepRight: + CLR AX ; zero low word of Delta_Y * 10000h + XCHG DX, CX ; Delta_Y switched with Delta_X + DIV CX ; divide by Delta_Y + + MOV SI, BX ; SI = Accumulator + MOV BX, AX ; BX = Add Fraction + POP AX ; Get Color, Bit mask + MOV DX, SC_Data ; Sequence controller data register + INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right + +@STRLoop: + MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + + ADD SI, BX ; add numerator to accumulator + JNC @STRnc2 ; if no carry then just go down... + + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@STRnc2: + ADD DI, BP ; advance to next line. + + MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + + ADD SI, BX ; add numerator to accumulator + JNC @STRnc3 ; if no carry then just go down... + + ROL AL, 1 ; Move Right one addr if Plane = 0 + CMP AL, 12h ; Wrap? if AL >12 then Carry not set + ADC DI, 0 ; Adjust Address: DI = DI + Carry + OUT DX, AL ; Set up New Bit Plane mask + +@STRnc3: + ADD DI, BP ; advance to next line. + JMP s @STRLoop ; loop till done + +@DL_EXIT2: + POPx DI, SI, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +DRAW_LINE ENDP + + + ; ===== DAC COLOR REGISTER ROUTINES ===== + +;================================================= +;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%) +;================================================= +; +; Sets a single (RGB) Vga Palette Register +; +; ENTRY: Register = The DAC # to modify (0-255) +; Red = The new Red Intensity (0-63) +; Green = The new Green Intensity (0-63) +; Blue = The new Blue Intensity (0-63) +; +; EXIT: No meaningful values returned +; + +SDR_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDR_Blue DB ?,? ; Blue Data Value + SDR_Green DB ?,? ; Green Data Value + SDR_Red DB ?,? ; Red Data Value + SDR_Register DB ?,? ; Palette Register # +SDR_STACK ENDS + + PUBLIC SET_DAC_REGISTER + +SET_DAC_REGISTER PROC FAR + + PUSH BP ; Save BP + MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to modify + + OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register + + MOV DX, PEL_DATA_REG ; Dac Data Register + OUT_8 DX, [BP].SDR_Red ; Set Red Intensity + OUT_8 DX, [BP].SDR_Green ; Set Green Intensity + OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity + + POP BP ; Restore Registers + RET 8 ; Exit & Clean Up Stack + +SET_DAC_REGISTER ENDP + +;==================================================== +;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%) +;==================================================== +; +; Reads the RGB Values of a single Vga Palette Register +; +; ENTRY: Register = The DAC # to read (0-255) +; Red = Offset to Red Variable in DS +; Green = Offset to Green Variable in DS +; Blue = Offset to Blue Variable in DS +; +; EXIT: The values of the integer variables Red, +; Green, and Blue are set to the values +; taken from the specified DAC register. +; + +GDR_STACK STRUC + DW ? ; BP + DD ? ; Caller + GDR_Blue DW ? ; Addr of Blue Data Value in DS + GDR_Green DW ? ; Addr of Green Data Value in DS + GDR_Red DW ? ; Addr of Red Data Value in DS + GDR_Register DB ?,? ; Palette Register # +GDR_STACK ENDS + + PUBLIC GET_DAC_REGISTER + +GET_DAC_REGISTER PROC FAR + + PUSH BP ; Save BP + MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to read in + + OUT_8 DAC_READ_ADDR, [BP].GDR_Register + + MOV DX, PEL_DATA_REG ; Dac Data Register + CLR AX ; Clear AX + + IN AL, DX ; Read Red Value + MOV BX, [BP].GDR_Red ; Get Address of Red% + MOV [BX], AX ; *Red% = AX + + IN AL, DX ; Read Green Value + MOV BX, [BP].GDR_Green ; Get Address of Green% + MOV [BX], AX ; *Green% = AX + + IN AL, DX ; Read Blue Value + MOV BX, [BP].GDR_Blue ; Get Address of Blue% + MOV [BX], AX ; *Blue% = AX + + POP BP ; Restore Registers + RET 8 ; Exit & Clean Up Stack + +GET_DAC_REGISTER ENDP + + +;=========================================================== +;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%) +;=========================================================== +; +; Sets a Block of Vga Palette Registers +; +; ENTRY: PalData = Far Pointer to Block of palette data +; StartReg = First Register # in range to set (0-255) +; EndReg = Last Register # in Range to set (0-255) +; Sync = Wait for Vertical Retrace Flag (Boolean) +; +; EXIT: No meaningful values returned +; +; NOTES: PalData is a linear array of 3 byte Palette values +; in the order: Red (0-63), Green (0-63), Blue (0-63) +; + +LDR_STACK STRUC + DW ?x3 ; BP, DS, SI + DD ? ; Caller + LDR_Sync DW ? ; Vertical Sync Flag + LDR_EndReg DB ?,? ; Last Register # + LDR_StartReg DB ?,? ; First Register # + LDR_PalData DD ? ; Far Ptr to Palette Data +LDR_STACK ENDS + + PUBLIC LOAD_DAC_REGISTERS + +LOAD_DAC_REGISTERS PROC FAR + + PUSHx BP, DS, SI ; Save Registers + mov BP, SP ; Set up Stack Frame + + mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag + or AX, AX ; is Sync Flag = 0? + jz @LDR_Load ; if so, skip call + + call f SYNC_DISPLAY ; wait for vsync + + ; Determine register #'s, size to copy, etc + +@LDR_Load: + + lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data + mov DX, DAC_WRITE_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + mov AL, [BP].LDR_StartReg ; Get Start Register + mov BL, [BP].LDR_EndReg ; Get End Register + + sub BX, AX ; BX = # of DAC registers -1 + inc BX ; BX = # of DAC registers + mov CX, BX ; CX = # of DAC registers + add CX, BX ; CX = " " * 2 + add CX, BX ; CX = " " * 3 + cld ; Block OUTs forward + out DX, AL ; set up correct register # + + ; Load a block of DAC Registers + + mov DX, PEL_DATA_REG ; Dac Data Register + + rep outsb ; block set DAC registers + + POPx SI, DS, BP ; Restore Registers + ret 10 ; Exit & Clean Up Stack + +LOAD_DAC_REGISTERS ENDP + + +;==================================================== +;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%) +;==================================================== +; +; Reads a Block of Vga Palette Registers +; +; ENTRY: PalData = Far Pointer to block to store palette data +; StartReg = First Register # in range to read (0-255) +; EndReg = Last Register # in Range to read (0-255) +; +; EXIT: No meaningful values returned +; +; NOTES: PalData is a linear array of 3 byte Palette values +; in the order: Red (0-63), Green (0-63), Blue (0-63) +; + +RDR_STACK STRUC + DW ?x3 ; BP, ES, DI + DD ? ; Caller + RDR_EndReg DB ?,? ; Last Register # + RDR_StartReg DB ?,? ; First Register # + RDR_PalData DD ? ; Far Ptr to Palette Data +RDR_STACK ENDS + + PUBLIC READ_DAC_REGISTERS + +READ_DAC_REGISTERS PROC FAR + + PUSHx BP, ES, DI ; Save Registers + mov BP, SP ; Set up Stack Frame + + ; Determine register #'s, size to copy, etc + + les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer + mov DX, DAC_READ_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + mov AL, [BP].RDR_StartReg ; Get Start Register + mov BL, [BP].RDR_EndReg ; Get End Register + + sub BX, AX ; BX = # of DAC registers -1 + inc BX ; BX = # of DAC registers + mov CX, BX ; CX = # of DAC registers + add CX, BX ; CX = " " * 2 + add CX, BX ; CX = " " * 3 + cld ; Block INs forward + + ; Read a block of DAC Registers + + out DX, AL ; set up correct register # + mov DX, PEL_DATA_REG ; Dac Data Register + + rep insb ; block read DAC registers + + POPx DI, ES, BP ; Restore Registers + ret 8 ; Exit & Clean Up Stack + +READ_DAC_REGISTERS ENDP + + + ; ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +;========================= +;SET_ACTIVE_PAGE (PageNo%) +;========================= +; +; Sets the active display Page to be used for future drawing +; +; ENTRY: PageNo = Display Page to make active +; (values: 0 to Number of Pages - 1) +; +; EXIT: No meaningful values returned +; + +SAP_STACK STRUC + DW ? ; BP + DD ? ; Caller + SAP_Page DW ? ; Page # for Drawing +SAP_STACK ENDS + + PUBLIC SET_ACTIVE_PAGE + +SET_ACTIVE_PAGE PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + MOV BX, [BP].SAP_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SAP_Exit ; IF Not, Do Nothing + + MOV ACTIVE_PAGE, BX ; Set Active Page # + + SHL BX, 1 ; Scale Page # to Word + MOV AX, PAGE_ADDR[BX] ; Get offset to Page + + MOV CURRENT_PAGE, AX ; And set for future LES's + +@SAP_Exit: + POP BP ; Restore Registers + RET 2 ; Exit and Clean up Stack + +SET_ACTIVE_PAGE ENDP + + +;================ +;GET_ACTIVE_PAGE% +;================ +; +; Returns the Video Page # currently used for Drawing +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Video Page used for Drawing +; + + PUBLIC GET_ACTIVE_PAGE + +GET_ACTIVE_PAGE PROC FAR + + MOV AX, ACTIVE_PAGE ; Get Active Page # + RET ; Exit and Clean up Stack + +GET_ACTIVE_PAGE ENDP + + +;=============================== +;SET_DISPLAY_PAGE (DisplayPage%) +;=============================== +; +; Sets the currently visible display page. +; When called this routine syncronizes the display +; to the vertical blank. +; +; ENTRY: PageNo = Display Page to show on the screen +; (values: 0 to Number of Pages - 1) +; +; EXIT: No meaningful values returned +; + +SDP_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDP_Page DW ? ; Page # to Display... +SDP_STACK ENDS + + PUBLIC SET_DISPLAY_PAGE + +SET_DISPLAY_PAGE PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + MOV BX, [BP].SDP_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SDP_Exit ; IF Not, Do Nothing + + MOV DISPLAY_PAGE, BX ; Set Display Page # + + SHL BX, 1 ; Scale Page # to Word + MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page + ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling + + ; Wait if we are currently in a Vertical Retrace + + MOV DX, INPUT_1 ; Input Status #1 Register + +@DP_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @DP_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new page + + MOV DX, CRTC_Index ; We Change the VGA Sequencer + + MOV AL, START_DISP_LO ; Display Start Low Register + MOV AH, CL ; Low 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr Low + + MOV AL, START_DISP_HI ; Display Start High Register + MOV AH, CH ; High 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + MOV DX, INPUT_1 ; Input Status #1 Register + +@DP_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @DP_WAIT1 ; If Not, wait for it + + ; Now Set Display Starting Address + + +@SDP_Exit: + POP BP ; Restore Registers + RET 2 ; Exit and Clean up Stack + +SET_DISPLAY_PAGE ENDP + + +;================= +;GET_DISPLAY_PAGE% +;================= +; +; Returns the Video Page # currently displayed +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Video Page being displayed +; + + PUBLIC GET_DISPLAY_PAGE + +GET_DISPLAY_PAGE PROC FAR + + MOV AX, DISPLAY_PAGE ; Get Display Page # + RET ; Exit & Clean Up Stack + +GET_DISPLAY_PAGE ENDP + + +;======================================= +;SET_WINDOW (DisplayPage%, Xpos%, Ypos%) +;======================================= +; +; Since a Logical Screen can be larger than the Physical +; Screen, Scrolling is possible. This routine sets the +; Upper Left Corner of the Screen to the specified Pixel. +; Also Sets the Display page to simplify combined page +; flipping and scrolling. When called this routine +; syncronizes the display to the vertical blank. +; +; ENTRY: DisplayPage = Display Page to show on the screen +; Xpos = # of pixels to shift screen right +; Ypos = # of lines to shift screen down +; +; EXIT: No meaningful values returned +; + +SW_STACK STRUC + DW ? ; BP + DD ? ; Caller + SW_Ypos DW ? ; Y pos of UL Screen Corner + SW_Xpos DW ? ; X pos of UL Screen Corner + SW_Page DW ? ; (new) Display Page +SW_STACK ENDS + + PUBLIC SET_WINDOW + +SET_WINDOW PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + ; Check if our Scroll Offsets are Valid + + MOV BX, [BP].SW_Page ; Get Desired Page # + CMP BX, LAST_PAGE ; Is Page # Valid? + JAE @SW_Exit ; IF Not, Do Nothing + + MOV AX, [BP].SW_Ypos ; Get Desired Y Offset + CMP AX, MAX_YOFFSET ; Is it Within Limits? + JA @SW_Exit ; if not, exit + + MOV CX, [BP].SW_Xpos ; Get Desired X Offset + CMP CX, MAX_XOFFSET ; Is it Within Limits? + JA @SW_Exit ; if not, exit + + ; Compute proper Display start address to use + + MUL SCREEN_WIDTH ; AX = YOffset * Line Width + SHR CX, 2 ; CX / 4 = Bytes into Line + ADD AX, CX ; AX = Offset of Upper Left Pixel + + MOV CURRENT_MOFFSET, AX ; Save Offset Info + + MOV DISPLAY_PAGE, BX ; Set Current Page # + SHL BX, 1 ; Scale Page # to Word + ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page + MOV BX, AX ; BX = Desired Display Start + + MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait if we are currently in a Vertical Retrace + +@SW_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @SW_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new window + + MOV DX, CRTC_Index ; We Change the VGA Sequencer + MOV AL, START_DISP_LO ; Display Start Low Register + MOV AH, BL ; Low 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr Low + + MOV AL, START_DISP_HI ; Display Start High Register + MOV AH, BH ; High 8 Bits of Start Addr + OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + MOV DX, INPUT_1 ; Input Status #1 Register + +@SW_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @SW_WAIT1 ; If Not, wait for it + + ; Now Set the Horizontal Pixel Pan values + + OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register + + MOV AX, [BP].SW_Xpos ; Get Desired X Offset + AND AL, 03 ; Get # of Pixels to Pan (0-3) + SHL AL, 1 ; Shift for 256 Color Mode + OUT DX, AL ; Fine tune the display! + +@SW_Exit: + POP BP ; Restore Saved Registers + RET 6 ; Exit and Clean up Stack + +SET_WINDOW ENDP + + +;============= +;GET_X_OFFSET% +;============= +; +; Returns the X coordinate of the Pixel currently display +; in the upper left corner of the display +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Horizontal Scroll Offset +; + + PUBLIC GET_X_OFFSET + +GET_X_OFFSET PROC FAR + + MOV AX, CURRENT_XOFFSET ; Get current horz offset + RET ; Exit & Clean Up Stack + +GET_X_OFFSET ENDP + + +;============= +;GET_Y_OFFSET% +;============= +; +; Returns the Y coordinate of the Pixel currently display +; in the upper left corner of the display +; +; ENTRY: No Parameters are passed +; +; EXIT: AX = Current Vertical Scroll Offset +; + + PUBLIC GET_Y_OFFSET + +GET_Y_OFFSET PROC FAR + + MOV AX, CURRENT_YOFFSET ; Get current vertical offset + RET ; Exit & Clean Up Stack + +GET_Y_OFFSET ENDP + + +;============ +;SYNC_DISPLAY +;============ +; +; Pauses the computer until the next Vertical Retrace starts +; +; ENTRY: No Parameters are passed +; +; EXIT: No meaningful values returned +; + + PUBLIC SYNC_DISPLAY + +SYNC_DISPLAY PROC FAR + + MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait for any current retrace to end + +@SD_WAIT0: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; In Display mode yet? + JNZ @SD_WAIT0 ; If Not, wait for it + + ; Wait for the start of the next vertical retrace + +@SD_WAIT1: + IN AL, DX ; Get VGA status + AND AL, VERT_RETRACE ; Vertical Retrace Start? + JZ @SD_WAIT1 ; If Not, wait for it + + RET ; Exit & Clean Up Stack + +SYNC_DISPLAY ENDP + + + ; ===== TEXT DISPLAY ROUTINES ===== + +;================================================== +;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%) +;================================================== +; +; Draws an ASCII Text Character using the currently selected +; 8x8 font on the active display page. It would be a simple +; exercise to make this routine process variable height fonts. +; +; ENTRY: CharNum = ASCII character # to draw +; Xpos = X position to draw Character at +; Ypos = Y position of to draw Character at +; ColorF = Color to draw text character in +; ColorB = Color to set background to +; +; EXIT: No meaningful values returned +; + +GPC_STACK STRUC + GPC_Width DW ? ; Screen Width-1 + GPC_Lines DB ?,? ; Scan lines to Decode + GPC_T_SETS DW ? ; Saved Charset Segment + GPC_T_SETO DW ? ; Saved Charset Offset + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + GPC_ColorB DB ?,? ; Background Color + GPC_ColorF DB ?,? ; Text Color + GPC_Ypos DW ? ; Y Position to Print at + GPC_Xpos DW ? ; X position to Print at + GPC_Char DB ?,? ; Character to Print +GPC_STACK ENDS + + PUBLIC GPRINTC + +GPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 8 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, SCREEN_WIDTH ; Get Logical Line Width + MOV BX, AX ; BX = Screen Width + DEC BX ; = Screen Width-1 + MOV [BP].GPC_Width, BX ; Save for later use + + MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width + ADD DI, AX ; DI -> Start of Line Ypos + + MOV AX, [BP].GPC_Xpos ; Get Xpos of Character + MOV CX, AX ; Save Copy of Xpos + SHR AX, 2 ; Bytes into Line = Xpos/4 + ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + MOV AL, [BP].GPC_Char ; Get Character # + TEST AL, 080h ; Is Hi Bit Set? + JZ @GPC_LowChar ; Nope, use low char set ptr + + AND AL, 07Fh ; Mask Out Hi Bit + MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + JMP s @GPC_Set_Char ; Go Setup Character Ptr + +@GPC_LowChar: + + MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + +@GPC_Set_Char: + MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack + + MOV AH, 0 ; Valid #'s are 0..127 + SHL AX, 3 ; * 8 Bytes Per Bitmap + ADD BX, AX ; BX = Offset of Selected char + MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack + + AND CX, PLANE_BITS ; Get Plane # + MOV CH, ALL_PLANES ; Get Initial Plane mask + SHL CH, CL ; And shift into position + AND CH, ALL_PLANES ; And mask to lower nibble + + MOV AL, 04 ; 4-Plane # = # of initial + SUB AL, CL ; shifts to align bit mask + MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + INC DX ; DX -> SC_Data + + MOV AL, 08 ; 8 Lines to Process + MOV [BP].GPC_Lines, AL ; Save on Stack + + MOV DS, [BP].GPC_T_SETS ; Point to character set + +@GPC_DECODE_CHAR_BYTE: + + MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String + + MOV BH, [SI] ; Get Bit Map + INC SI ; Point to Next Line + MOV [BP].GPC_T_SETO, SI ; And save new Pointer... + + CLR AX ; Clear AX + + CLR BL ; Clear BL + ROL BX, CL ; BL holds left edge bits + MOV SI, BX ; Use as Table Index + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_LEFT1BITS: + XOR AL, CH ; Invert mask for Background + JZ @GPC_NO_LEFT0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + +@GPC_NO_LEFT0BITS: + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_MIDDLE1BITS: + XOR AL, ALL_PLANES ; Invert mask for Background + JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_MIDDLE0BITS: + XOR CH, ALL_PLANES ; Invert Clip Mask + CMP CL, 4 ; Aligned by 4? + JZ @GPC_NEXT_LINE ; If so, Exit now.. + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set + + MOV AH, [BP].GPC_ColorF ; Get Foreground Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_RIGHT1BITS: + + XOR AL, CH ; Invert mask for Background + JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this + + MOV AH, [BP].GPC_ColorB ; Get background Color + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@GPC_NO_RIGHT0BITS: + DEC DI ; Adjust for Next Line Advance + +@GPC_NEXT_LINE: + ADD DI, [BP].GPC_Width ; Point to Next Line + XOR CH, CHAR_BITS ; Flip the Clip mask back + + DEC [BP].GPC_Lines ; Count Down Lines + JZ @GPC_EXIT ; Ok... Done! + + JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey! + +@GPC_EXIT: + ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 10 ; Exit and Clean up Stack + +GPRINTC ENDP + + +;========================================== +;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%) +;========================================== +; +; Transparently draws an ASCII Text Character using the +; currently selected 8x8 font on the active display page. +; +; ENTRY: CharNum = ASCII character # to draw +; Xpos = X position to draw Character at +; Ypos = Y position of to draw Character at +; ColorF = Color to draw text character in +; +; EXIT: No meaningful values returned +; + +TGP_STACK STRUC + TGP_Width DW ? ; Screen Width-1 + TGP_Lines DB ?,? ; Scan lines to Decode + TGP_T_SETS DW ? ; Saved Charset Segment + TGP_T_SETO DW ? ; Saved Charset Offset + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TGP_ColorF DB ?,? ; Text Color + TGP_Ypos DW ? ; Y Position to Print at + TGP_Xpos DW ? ; X position to Print at + TGP_Char DB ?,? ; Character to Print +TGP_STACK ENDS + + PUBLIC TGPRINTC + +TGPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 8 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + MOV AX, SCREEN_WIDTH ; Get Logical Line Width + MOV BX, AX ; BX = Screen Width + DEC BX ; = Screen Width-1 + MOV [BP].TGP_Width, BX ; Save for later use + + MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width + ADD DI, AX ; DI -> Start of Line Ypos + + MOV AX, [BP].TGP_Xpos ; Get Xpos of Character + MOV CX, AX ; Save Copy of Xpos + SHR AX, 2 ; Bytes into Line = Xpos/4 + ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + MOV AL, [BP].TGP_Char ; Get Character # + TEST AL, 080h ; Is Hi Bit Set? + JZ @TGP_LowChar ; Nope, use low char set ptr + + AND AL, 07Fh ; Mask Out Hi Bit + MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + JMP s @TGP_Set_Char ; Go Setup Character Ptr + +@TGP_LowChar: + + MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + +@TGP_Set_Char: + MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack + + MOV AH, 0 ; Valid #'s are 0..127 + SHL AX, 3 ; * 8 Bytes Per Bitmap + ADD BX, AX ; BX = Offset of Selected char + MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack + + AND CX, PLANE_BITS ; Get Plane # + MOV CH, ALL_PLANES ; Get Initial Plane mask + SHL CH, CL ; And shift into position + AND CH, ALL_PLANES ; And mask to lower nibble + + MOV AL, 04 ; 4-Plane # = # of initial + SUB AL, CL ; shifts to align bit mask + MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + INC DX ; DX -> SC_Data + + MOV AL, 08 ; 8 Lines to Process + MOV [BP].TGP_Lines, AL ; Save on Stack + + MOV DS, [BP].TGP_T_SETS ; Point to character set + +@TGP_DECODE_CHAR_BYTE: + + MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String + + MOV BH, [SI] ; Get Bit Map + INC SI ; Point to Next Line + MOV [BP].TGP_T_SETO, SI ; And save new Pointer... + + MOV AH, [BP].TGP_ColorF ; Get Foreground Color + + CLR BL ; Clear BL + ROL BX, CL ; BL holds left edge bits + MOV SI, BX ; Use as Table Index + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + +@TGP_NO_LEFT1BITS: + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@TGP_NO_MIDDLE1BITS: + XOR CH, ALL_PLANES ; Invert Clip Mask + CMP CL, 4 ; Aligned by 4? + JZ @TGP_NEXT_LINE ; If so, Exit now.. + + INC DI ; Point to next Byte + ROL BX, 4 ; Shift 4 bits + + MOV SI, BX ; Make Lookup Pointer + AND SI, CHAR_BITS ; Get Low Bits + MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set + + OUT DX, AL ; Set up Screen Mask + MOV ES:[DI], AH ; Write Foreground color + +@TGP_NO_RIGHT1BITS: + + DEC DI ; Adjust for Next Line Advance + +@TGP_NEXT_LINE: + ADD DI, [BP].TGP_Width ; Point to Next Line + XOR CH, CHAR_BITS ; Flip the Clip mask back + + DEC [BP].TGP_Lines ; Count Down Lines + JZ @TGP_EXIT ; Ok... Done! + + JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey! + +@TGP_EXIT: + ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 8 ; Exit and Clean up Stack + +TGPRINTC ENDP + + +;=============================================================== +;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) +;=============================================================== +; +; Routine to quickly Print a null terminated ASCII string on the +; active display page up to a maximum length. +; +; ENTRY: String = Far Pointer to ASCII string to print +; MaxLen = # of characters to print if no null found +; Xpos = X position to draw Text at +; Ypos = Y position of to draw Text at +; ColorF = Color to draw text in +; ColorB = Color to set background to +; +; EXIT: No meaningful values returned +; + +PS_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + PS_ColorB DW ? ; Background Color + PS_ColorF DW ? ; Text Color + PS_Ypos DW ? ; Y Position to Print at + PS_Xpos DW ? ; X position to Print at + PS_Len DW ? ; Maximum Length of string to print + PS_Text DW ?,? ; Far Ptr to Text String +PS_STACK ENDS + + PUBLIC PRINT_STR + +PRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + +@PS_Print_It: + + MOV CX, [BP].PS_Len ; Get Remaining text Length + JCXZ @PS_Exit ; Exit when out of text + + LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text + MOV AL, ES:[DI] ; AL = Text Character + AND AX, 00FFh ; Clear High Word + JZ @PS_Exit ; Exit if null character + + DEC [BP].PS_Len ; Remaining Text length-- + INC [BP].PS_Text ; Point to Next text char + + ; Set up Call to GPRINTC + + PUSH AX ; Set Character Parameter + MOV BX, [BP].PS_Xpos ; Get Xpos + PUSH BX ; Set Xpos Parameter + ADD BX, 8 ; Advance 1 Char to Right + MOV [BP].PS_Xpos, BX ; Save for next time through + + MOV BX, [BP].PS_Ypos ; Get Ypos + PUSH BX ; Set Ypos Parameter + + MOV BX, [BP].PS_ColorF ; Get Text Color + PUSH BX ; Set ColorF Parameter + + MOV BX, [BP].PS_ColorB ; Get Background Color + PUSH BX ; Set ColorB Parameter + + CALL f GPRINTC ; Print Character! + JMP s @PS_Print_It ; Process next character + +@PS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 14 ; Exit and Clean up Stack + +PRINT_STR ENDP + + +;================================================================ +;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) +;================================================================ +; +; Routine to quickly transparently Print a null terminated ASCII +; string on the active display page up to a maximum length. +; +; ENTRY: String = Far Pointer to ASCII string to print +; MaxLen = # of characters to print if no null found +; Xpos = X position to draw Text at +; Ypos = Y position of to draw Text at +; ColorF = Color to draw text in +; +; EXIT: No meaningful values returned +; + +TPS_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TPS_ColorF DW ? ; Text Color + TPS_Ypos DW ? ; Y Position to Print at + TPS_Xpos DW ? ; X position to Print at + TPS_Len DW ? ; Maximum Length of string to print + TPS_Text DW ?,? ; Far Ptr to Text String +TPS_STACK ENDS + + PUBLIC TPRINT_STR + +TPRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + +@TPS_Print_It: + + MOV CX, [BP].TPS_Len ; Get Remaining text Length + JCXZ @TPS_Exit ; Exit when out of text + + LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text + MOV AL, ES:[DI] ; AL = Text Character + AND AX, 00FFh ; Clear High Word + JZ @TPS_Exit ; Exit if null character + + DEC [BP].TPS_Len ; Remaining Text length-- + INC [BP].TPS_Text ; Point to Next text char + + ; Set up Call to TGPRINTC + + PUSH AX ; Set Character Parameter + MOV BX, [BP].TPS_Xpos ; Get Xpos + PUSH BX ; Set Xpos Parameter + ADD BX, 8 ; Advance 1 Char to Right + MOV [BP].TPS_Xpos, BX ; Save for next time through + + MOV BX, [BP].TPS_Ypos ; Get Ypos + PUSH BX ; Set Ypos Parameter + + MOV BX, [BP].TPS_ColorF ; Get Text Color + PUSH BX ; Set ColorF Parameter + + CALL f TGPRINTC ; Print Character! + JMP s @TPS_Print_It ; Process next character + +@TPS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +TPRINT_STR ENDP + + +;=========================================== +;SET_DISPLAY_FONT(SEG FontData, FontNumber%) +;=========================================== +; +; Allows the user to specify their own font data for +; wither the lower or upper 128 characters. +; +; ENTRY: FontData = Far Pointer to Font Bitmaps +; FontNumber = Which half of set this is +; = 0, Lower 128 characters +; = 1, Upper 128 characters +; +; EXIT: No meaningful values returned +; + +SDF_STACK STRUC + DW ? ; BP + DD ? ; Caller + SDF_Which DW ? ; Hi Table/Low Table Flag + SDF_Font DD ? ; Far Ptr to Font Table +SDF_STACK ENDS + + PUBLIC SET_DISPLAY_FONT + +SET_DISPLAY_FONT PROC FAR + + PUSH BP ; Preserve Registers + MOV BP, SP ; Set up Stack Frame + + LES DI, [BP].SDF_Font ; Get Far Ptr to Font + + MOV SI, o CHARSET_LOW ; Assume Lower 128 chars + TEST [BP].SDF_Which, 1 ; Font #1 selected? + JZ @SDF_Set_Font ; If not, skip ahead + + MOV SI, o CHARSET_HI ; Ah, really it's 128-255 + +@SDF_Set_Font: + MOV [SI], DI ; Set Font Pointer Offset + MOV [SI+2], ES ; Set Font Pointer Segment + + POP BP ; Restore Registers + RET 6 ; We are Done.. Outa here + +SET_DISPLAY_FONT ENDP + + + ; ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +;====================================================== +;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) +;====================================================== +; +; Draws a variable sized Graphics Bitmap such as a +; picture or an Icon on the current Display Page in +; Mode X. The Bitmap is stored in a linear byte array +; corresponding to (0,0) (1,0), (2,0) .. (Width, Height) +; This is the same linear manner as mode 13h graphics. +; +; ENTRY: Image = Far Pointer to Bitmap Data +; Xpos = X position to Place Upper Left pixel at +; Ypos = Y position to Place Upper Left pixel at +; Width = Width of the Bitmap in Pixels +; Height = Height of the Bitmap in Pixels +; +; EXIT: No meaningful values returned +; + +DB_STACK STRUC + DB_LineO DW ? ; Offset to Next Line + DB_PixCount DW ? ; (Minimum) # of Pixels/Line + DB_Start DW ? ; Addr of Upper Left Pixel + DB_PixSkew DW ? ; # of bytes to Adjust EOL + DB_SkewFlag DW ? ; Extra Pix on Plane Flag + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + DB_Height DW ? ; Height of Bitmap in Pixels + DB_Width DW ? ; Width of Bitmap in Pixels + DB_Ypos DW ? ; Y position to Draw Bitmap at + DB_Xpos DW ? ; X position to Draw Bitmap at + DB_Image DD ? ; Far Pointer to Graphics Bitmap +DB_STACK ENDS + + PUBLIC DRAW_BITMAP + +DRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 10 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos + MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos + MOV CL, BL ; Save Plane # in CL + SHR BX, 2 ; Xpos/4 = Offset Into Line + + ADD DI, AX ; ES:DI -> Start of Line + ADD DI, BX ; ES:DI -> Upper Left Pixel + MOV [BP].DB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + MOV BX, [BP].DB_Width ; Get Width of Image + MOV DX, BX ; Save Copy in DX + SHR BX, 2 ; /4 = width in bands + MOV AX, SCREEN_WIDTH ; Get Screen Width + SUB AX, BX ; - (Bitmap Width/4) + + MOV [BP].DB_LineO, AX ; Save Line Width offset + MOV [BP].DB_PixCount, BX ; Minimum # pix to copy + + AND DX, PLANE_BITS ; Get "partial band" size (0-3) + MOV [BP].DB_PixSkew, DX ; Also End of Line Skew + MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count + + AND CX, PLANE_BITS ; CL = Starting Plane # + MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + MOV BH, AH ; BH = Saved Plane Mask + MOV BL, 4 ; BL = Planes to Copy + +@DB_COPY_PLANE: + + LDS SI, [BP].DB_Image ; DS:SI-> Source Image + MOV DX, [BP].DB_Height ; # of Lines to Copy + MOV DI, [BP].DB_Start ; ES:DI-> Dest pos + +@DB_COPY_LINE: + MOV CX, [BP].DB_PixCount ; Min # to copy + + TEST CL, 0FCh ; 16+PixWide? + JZ @DB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + +@DB_COPY_LOOP: + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + MOVSB ; Copy Bitmap Pixel + ADD SI, 3 ; Skip to Next Byte in same plane + + SUB CL, 4 ; Pixels to Copy=-4 + TEST CL, 0FCh ; 4+ Pixels Left? + JNZ @DB_COPY_LOOP ; if so, do another block + +@DB_COPY_REMAINDER: + JCXZ @DB_NEXT_LINE ; Any Pixels left on line + +@DB_COPY2: + MOVSB ; Copy Bitmap Pixel + ADD SI,3 ; Skip to Next Byte in same plane + LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done + +@DB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + OR CX, [BP].DB_SkewFlag ; Get Skew Count + JZ @DB_NEXT2 ; if no partial pixels + + MOVSB ; Copy Bitmap Pixel + DEC DI ; Back up to align + DEC SI ; Back up to align + +@DB_NEXT2: + ADD SI, [BP].DB_PixSkew ; Adjust Skew + ADD DI, [BP].DB_LineO ; Set to Next Display Line + LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more + + ; Copy Next Plane.... + + DEC BL ; Planes to Go-- + JZ @DB_Exit ; Hey! We are done + + ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + + CMP AL, 12h ; Carry Set if AL=11h + ADC [BP].DB_Start, 0 ; Screen Addr =+Carry + INC w [BP].DB_Image ; Start @ Next Byte + + SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew + ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1 + + JMP s @DB_COPY_PLANE ; Go Copy the Next Plane + +@DB_Exit: + ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +DRAW_BITMAP ENDP + + +;======================================================= +;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) +;======================================================= +; +; Transparently Draws a variable sized Graphics Bitmap +; such as a picture or an Icon on the current Display Page +; in Mode X. Pixels with a value of 0 are not drawn, +; leaving the previous "background" contents intact. +; +; The Bitmap format is the same as for the DRAW_BITMAP function. +; +; ENTRY: Image = Far Pointer to Bitmap Data +; Xpos = X position to Place Upper Left pixel at +; Ypos = Y position to Place Upper Left pixel at +; Width = Width of the Bitmap in Pixels +; Height = Height of the Bitmap in Pixels +; +; EXIT: No meaningful values returned +; + +TB_STACK STRUC + TB_LineO DW ? ; Offset to Next Line + TB_PixCount DW ? ; (Minimum) # of Pixels/Line + TB_Start DW ? ; Addr of Upper Left Pixel + TB_PixSkew DW ? ; # of bytes to Adjust EOL + TB_SkewFlag DW ? ; Extra Pix on Plane Flag + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + TB_Height DW ? ; Height of Bitmap in Pixels + TB_Width DW ? ; Width of Bitmap in Pixels + TB_Ypos DW ? ; Y position to Draw Bitmap at + TB_Xpos DW ? ; X position to Draw Bitmap at + TB_Image DD ? ; Far Pointer to Graphics Bitmap +TB_STACK ENDS + + PUBLIC TDRAW_BITMAP + +TDRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 10 ; Allocate workspace + MOV BP, SP ; Set up Stack Frame + + LES DI, d CURRENT_PAGE ; Point to Active VGA Page + CLD ; Direction Flag = Forward + + MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos + MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos + MOV CL, BL ; Save Plane # in CL + SHR BX, 2 ; Xpos/4 = Offset Into Line + + ADD DI, AX ; ES:DI -> Start of Line + ADD DI, BX ; ES:DI -> Upper Left Pixel + MOV [BP].TB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + MOV BX, [BP].TB_Width ; Get Width of Image + MOV DX, BX ; Save Copy in DX + SHR BX, 2 ; /4 = width in bands + MOV AX, SCREEN_WIDTH ; Get Screen Width + SUB AX, BX ; - (Bitmap Width/4) + + MOV [BP].TB_LineO, AX ; Save Line Width offset + MOV [BP].TB_PixCount, BX ; Minimum # pix to copy + + AND DX, PLANE_BITS ; Get "partial band" size (0-3) + MOV [BP].TB_PixSkew, DX ; Also End of Line Skew + MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count + + AND CX, PLANE_BITS ; CL = Starting Plane # + MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + MOV BH, AH ; BH = Saved Plane Mask + MOV BL, 4 ; BL = Planes to Copy + +@TB_COPY_PLANE: + + LDS SI, [BP].TB_Image ; DS:SI-> Source Image + MOV DX, [BP].TB_Height ; # of Lines to Copy + MOV DI, [BP].TB_Start ; ES:DI-> Dest pos + + ; Here AH is set with the value to be considered + ; "Transparent". It can be changed! + + MOV AH, 0 ; Value to Detect 0 + +@TB_COPY_LINE: + MOV CX, [BP].TB_PixCount ; Min # to copy + + TEST CL, 0FCh ; 16+PixWide? + JZ @TB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + +@TB_COPY_LOOP: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_01 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_SKIP_01: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_02 ; Skip ahead if so + MOV ES:[DI+1], AL ; Copy Pixel to VGA screen + +@TB_SKIP_02: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_03 ; Skip ahead if so + MOV ES:[DI+2], AL ; Copy Pixel to VGA screen + +@TB_SKIP_03: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_04 ; Skip ahead if so + MOV ES:[DI+3], AL ; Copy Pixel to VGA screen + +@TB_SKIP_04: + ADD DI, 4 ; Adjust Pixel Write Location + SUB CL, 4 ; Pixels to Copy=-4 + TEST CL, 0FCh ; 4+ Pixels Left? + JNZ @TB_COPY_LOOP ; if so, do another block + +@TB_COPY_REMAINDER: + JCXZ @TB_NEXT_LINE ; Any Pixels left on line + +@TB_COPY2: + LODSB ; Get Pixel Value in AL + ADD SI, 3 ; Skip to Next Byte in same plane + CMP AL, AH ; It is "Transparent"? + JE @TB_SKIP_05 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_SKIP_05: + INC DI ; Advance Dest Addr + LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done + +@TB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + OR CX, [BP].TB_SkewFlag ; Get Skew Count + JZ @TB_NEXT2 ; if no partial pixels + + LODSB ; Get Pixel Value in AL + DEC SI ; Backup to Align + CMP AL, AH ; It is "Transparent"? + JE @TB_NEXT2 ; Skip ahead if so + MOV ES:[DI], AL ; Copy Pixel to VGA screen + +@TB_NEXT2: + ADD SI, [BP].TB_PixSkew ; Adjust Skew + ADD DI, [BP].TB_LineO ; Set to Next Display Line + LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More + + ;Copy Next Plane.... + + DEC BL ; Planes to Go-- + JZ @TB_Exit ; Hey! We are done + + ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + + CMP AL, 12h ; Carry Set if AL=11h + ADC [BP].TB_Start, 0 ; Screen Addr =+Carry + INC w [BP].TB_Image ; Start @ Next Byte + + SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew + ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1 + + JMP @TB_COPY_PLANE ; Go Copy the next Plane + +@TB_Exit: + ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 12 ; Exit and Clean up Stack + +TDRAW_BITMAP ENDP + + + ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +;================================== +;COPY_PAGE (SourcePage%, DestPage%) +;================================== +; +; Duplicate on display page onto another +; +; ENTRY: SourcePage = Display Page # to Duplicate +; DestPage = Display Page # to hold copy +; +; EXIT: No meaningful values returned +; + +CP_STACK STRUC + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + CP_DestP DW ? ; Page to hold copied image + CP_SourceP DW ? ; Page to Make copy from +CP_STACK ENDS + + PUBLIC COPY_PAGE + +COPY_PAGE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + MOV BP, SP ; Set up Stack Frame + CLD ; Block Xfer Forwards + + ; Make sure Page #'s are valid + + MOV AX, [BP].CP_SourceP ; Get Source Page # + CMP AX, LAST_PAGE ; is it > Max Page #? + JAE @CP_Exit ; if so, abort + + MOV BX, [BP].CP_DestP ; Get Destination Page # + CMP BX, LAST_PAGE ; is it > Max Page #? + JAE @CP_Exit ; if so, abort + + CMP AX, BX ; Pages #'s the same? + JE @CP_Exit ; if so, abort + + ; Setup DS:SI and ES:DI to Video Pages + + SHL BX, 1 ; Scale index to Word + MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page + + MOV BX, AX ; Index to Source page + SHL BX, 1 ; Scale index to Word + MOV SI, PAGE_ADDR[BX] ; Offset to Source Page + + MOV CX, PAGE_SIZE ; Get size of Page + MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment + MOV ES, AX ; ES:DI -> Dest Page + MOV DS, AX ; DS:SI -> Source Page + + ; Setup VGA registers for Mem to Mem copy + + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes + + ; Note.. Do *NOT* use MOVSW or MOVSD - they will + ; Screw with the latches which are 8 bits x 4 + + REP MOVSB ; Copy entire Page! + + ; Reset VGA for normal memory access + + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off + +@CP_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 4 ; Exit and Clean up Stack + +COPY_PAGE ENDP + + +;========================================================================== +;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%) +;========================================================================== +; +; Copies a Bitmap Image from one Display Page to Another +; This Routine is Limited to copying Images with the same +; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4) +; Copying an Image to the Same Page is supported, but results +; may be defined when the when the rectangular areas +; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) - +; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap... +; No Paramter checking to done to insure that +; X2 >= X1 and Y2 >= Y1. Be Careful... +; +; ENTRY: SourcePage = Display Page # with Source Image +; X1 = Upper Left Xpos of Source Image +; Y1 = Upper Left Ypos of Source Image +; X2 = Lower Right Xpos of Source Image +; Y2 = Lower Right Ypos of Source Image +; DestPage = Display Page # to copy Image to +; DestX1 = Xpos to Copy UL Corner of Image to +; DestY1 = Ypos to Copy UL Corner of Image to +; +; EXIT: AX = Success Flag: 0 = Failure / -1= Success +; + +CB_STACK STRUC + CB_Height DW ? ; Height of Image in Lines + CB_Width DW ? ; Width of Image in "bands" + DW ?x4 ; DI, SI, DS, BP + DD ? ; Caller + CB_DestY1 DW ? ; Destination Ypos + CB_DestX1 DW ? ; Destination Xpos + CB_DestP DW ? ; Page to Copy Bitmap To + CB_Y2 DW ? ; LR Ypos of Image + CB_X2 DW ? ; LR Xpos of Image + CB_Y1 DW ? ; UL Ypos of Image + CB_X1 DW ? ; UL Xpos of Image + CB_SourceP DW ? ; Page containing Source Bitmap +CB_STACK ENDS + + PUBLIC COPY_BITMAP + +COPY_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + SUB SP, 4 ; Allocate WorkSpace on Stack + MOV BP, SP ; Set up Stack Frame + + ; Prep Registers (and keep jumps short!) + + MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram + CLD ; Block Xfer Forwards + + ; Make sure Parameters are valid + + MOV BX, [BP].CB_SourceP ; Get Source Page # + CMP BX, LAST_PAGE ; is it > Max Page #? + JAE @CB_Abort ; if so, abort + + MOV CX, [BP].CB_DestP ; Get Destination Page # + CMP CX, LAST_PAGE ; is it > Max Page #? + JAE @CB_Abort ; if so, abort + + MOV AX, [BP].CB_X1 ; Get Source X1 + XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1 + AND AX, PLANE_BITS ; Check Plane Bits + JNZ @CB_Abort ; They should cancel out + + ; Setup for Copy processing + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + + ; Compute Info About Images, Setup ES:SI & ES:DI + + MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines + SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1 + INC AX ; (add 1 since were not 0 based) + MOV [BP].CB_Height, AX ; Save on Stack for later use + + MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels + MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1 + SHR AX, 2 ; Get X2 Band (X2 / 4) + SHR DX, 2 ; Get X1 Band (X1 / 4) + SUB AX, DX ; AX = # of Bands - 1 + INC AX ; AX = # of Bands + MOV [BP].CB_Width, AX ; Save on Stack for later use + + SHL BX, 1 ; Scale Source Page to Word + MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page + MOV AX, [BP].CB_Y1 ; Get Source Y1 Line + MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + ADD SI, AX ; SI = Offset to Line Y1 + MOV AX, [BP].CB_X1 ; Get Source X1 + SHR AX, 2 ; X1 / 4 = Byte offset + ADD SI, AX ; SI = Byte Offset to (X1,Y1) + + MOV BX, CX ; Dest Page Index to BX + SHL BX, 1 ; Scale Source Page to Word + MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page + MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line + MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + ADD DI, AX ; DI = Offset to Line Y1 + MOV AX, [BP].CB_DestX1 ; Get Dest X1 + SHR AX, 2 ; X1 / 4 = Byte offset + ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1) + + MOV CX, [BP].CB_Width ; CX = Width of Image (Bands) + DEC CX ; CX = 1? + JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band + + MOV BX, [BP].CB_X1 ; Get Source X1 + AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?) + JZ @CB_Check_Right ; if so, check right alignment + JNZ @CB_Left_Band ; not aligned? well.. + +@CB_Abort: + CLR AX ; Return False (Failure) + JMP @CB_Exit ; and Finish Up + + ; Copy when Left & Right Clip Masks overlap... + +@CB_Only_One_Band: + MOV BX, [BP].CB_X1 ; Get Left Clip Mask + AND BX, PLANE_BITS ; Mask out Row # + MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask + MOV BX, [BP].CB_X2 ; Get Right Clip Mask + AND BX, PLANE_BITS ; Mask out Row # + AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + +@CB_One_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_One_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_One_Loop ; Loop until Finished + +@CB_One_Done: + JMP @CB_Finish ; Outa Here! + + ; Copy Left Edge of Bitmap + +@CB_Left_Band: + + OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask + + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + +@CB_Left_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Left_Loop ; Loop until Finished + +@CB_Left_Done: + INC DI ; Move Dest Over 1 band + INC SI ; Move Source Over 1 band + DEC [BP].CB_Width ; Band Width-- + + ; Determine if Right Edge of Bitmap needs special copy + +@CB_Check_Right: + MOV BX, [BP].CB_X2 ; Get Source X2 + AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?) + CMP BL, 03h ; Plane = 3? + JE @CB_Copy_Middle ; Copy the Middle then! + + ; Copy Right Edge of Bitmap + +@CB_Right_Band: + + OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask + + DEC [BP].CB_Width ; Band Width-- + MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + MOV DX, SCREEN_WIDTH ; DX = Width of Screen + MOV BX, [BP].CB_Width ; BX = Offset to Right Edge + +@CB_Right_Loop: + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished + + MOV AL, ES:[SI+BX] ; Load Latches + MOV ES:[DI+BX], AL ; Unload Latches + ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Right_Loop ; Loop until Finished + +@CB_Right_Done: + + ; Copy the Main Block of the Bitmap + +@CB_Copy_Middle: + + MOV CX, [BP].CB_Width ; Get Width Remaining + JCXZ @CB_Finish ; Exit if Done + + OUT_8 SC_Data, ALL_PLANES ; Copy all Planes + + MOV DX, SCREEN_WIDTH ; Get Width of Screen minus + SUB DX, CX ; Image width (for Adjustment) + MOV AX, [BP].CB_Height ; AX = # of Lines to Copy + MOV BX, CX ; BX = Quick REP reload count + MOV CX, ES ; Move VGA Segment + MOV DS, CX ; Into DS + + ; Actual Copy Loop. REP MOVSB does the work + +@CB_Middle_Copy: + MOV CX, BX ; Recharge Rep Count + REP MOVSB ; Move Bands + LOOPjz AX, @CB_Finish ; Exit Loop if Finished + + ADD SI, DX ; Adjust DS:SI to Next Line + ADD DI, DX ; Adjust ES:DI to Next Line + + MOV CX, BX ; Recharge Rep Count + REP MOVSB ; Move Bands + + ADD SI, DX ; Adjust DS:SI to Next Line + ADD DI, DX ; Adjust ES:DI to Next Line + LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done + +@CB_Finish: + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on + +@CB_Exit: + ADD SP, 04 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + RET 16 ; Exit and Clean up Stack + +COPY_BITMAP ENDP + + END ; End of Code Segment diff --git a/16/lib/modex105/MODEX.BI b/16/lib/modex105/MODEX.BI new file mode 100644 index 00000000..6b1d7afe --- /dev/null +++ b/16/lib/modex105/MODEX.BI @@ -0,0 +1,63 @@ + + ' ===== SCREEN RESOLUTIONS ===== + +CONST Mode320x200 = 0, Mode320x400 = 1 +CONST Mode360x200 = 2, Mode360x400 = 3 +CONST Mode320x240 = 4, Mode320x480 = 5 +CONST Mode360x240 = 6, Mode360x480 = 7 + + ' ===== MODE X SETUP ROUTINES ===== + +DECLARE FUNCTION SET.VGA.MODEX% ALIAS "SET_VGA_MODEX" (BYVAL ModeType%, BYVAL MaxXpos%, BYVAL MaxYpos%, BYVAL Pages%) +DECLARE FUNCTION SET.MODEX% ALIAS "SET_MODEX" (BYVAL Mode%) + + ' ===== BASIC GRAPHICS PRIMITIVES ===== + +DECLARE SUB CLEAR.VGA.SCREEN ALIAS "CLEAR_VGA_SCREEN" (BYVAL ColorNum%) +DECLARE SUB SET.POINT ALIAS "SET_POINT" (BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorNum%) +DECLARE FUNCTION READ.POINT% ALIAS "READ_POINT" (BYVAL Xpos%, BYVAL Ypos%) +DECLARE SUB FILL.BLOCK ALIAS "FILL_BLOCK" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) +DECLARE SUB DRAW.LINE ALIAS "DRAW_LINE" (BYVAL Xpos1%, BYVAL Ypos1%, BYVAL Xpos2%, BYVAL Ypos2%, BYVAL ColorNum%) + + ' ===== DAC COLOR REGISTER ROUTINES ===== + +DECLARE SUB SET.DAC.REGISTER ALIAS "SET_DAC_REGISTER" (BYVAL RegNo%, BYVAL Red%, BYVAL Green%, BYVAL Blue%) +DECLARE SUB GET.DAC.REGISTER ALIAS "GET_DAC_REGISTER" (BYVAL RegNo%, Red%, Green%, Blue%) +DECLARE SUB LOAD.DAC.REGISTERS ALIAS "LOAD_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%, BYVAL VSync%) +DECLARE SUB READ.DAC.REGISTERS ALIAS "READ_DAC_REGISTERS" (SEG PalData AS ANY, BYVAL StartReg%, BYVAL EndReg%) + + + ' ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + +DECLARE SUB SET.ACTIVE.PAGE ALIAS "SET_ACTIVE_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.ACTIVE.PAGE% ALIAS "GET_ACTIVE_PAGE" +DECLARE SUB SET.DISPLAY.PAGE ALIAS "SET_DISPLAY_PAGE" (BYVAL PageNo%) +DECLARE FUNCTION GET.DISPLAY.PAGE% ALIAS "GET_DISPLAY_PAGE" +DECLARE SUB SET.WINDOW ALIAS "SET_WINDOW" (BYVAL DisplayPage%, BYVAL XOffset%, BYVAL YOffset%) +DECLARE FUNCTION GET.X.OFFSET% ALIAS "GET_X_OFFSET" () +DECLARE FUNCTION GET.Y.OFFSET% ALIAS "GET_Y_OFFSET" () +DECLARE SUB SYNC.DISPLAY ALIAS "SYNC_DISPLAY" + + ' ===== TEXT DISPLAY ROUTINES ===== + +DECLARE SUB GPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TGPRINTC (BYVAL CharacterNum%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB PRINT.STR ALIAS "PRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%, BYVAL ColorB%) +DECLARE SUB TPRINT.STR ALIAS "TPRINT_STR" (BYVAL StrSeg%, BYVAL StrOfs%, BYVAL MaxLen%, BYVAL Xpos%, BYVAL Ypos%, BYVAL ColorF%) +DECLARE SUB SET.DISPLAY.FONT ALIAS "SET_DISPLAY_FONT" (SEG FontData AS ANY, BYVAL FontNumber%) + + ' ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + +DECLARE SUB DRAW.BITMAP ALIAS "DRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) +DECLARE SUB TDRAW.BITMAP ALIAS "TDRAW_BITMAP" (SEG Image AS ANY, BYVAL Xpos%, BYVAL Ypos%, BYVAL xWidth%, BYVAL Height%) + + ' ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + +DECLARE SUB COPY.PAGE ALIAS "COPY_PAGE" (BYVAL SourcePage%, BYVAL DestPage%) +DECLARE SUB COPY.BITMAP ALIAS "COPY_BITMAP" (BYVAL SourcePage%, BYVAL X1%, BYVAL Y1%, BYVAL X2%, BYVAL Y2%, BYVAL DestPage%, BYVAL DestX1%, BYVAL DestY1%) + + + + + + diff --git a/16/lib/modex105/MODEX.COM b/16/lib/modex105/MODEX.COM new file mode 100644 index 00000000..e69de29b diff --git a/16/lib/modex105/MODEX.H b/16/lib/modex105/MODEX.H new file mode 100644 index 00000000..7de25a63 --- /dev/null +++ b/16/lib/modex105/MODEX.H @@ -0,0 +1,76 @@ + +#ifndef __MODEX_H +#define __MODEX_H + + /* ===== SCREEN RESOLUTIONS ===== */ + +#define Mode_320x200 0 +#define Mode_320x400 1 +#define Mode_360x200 2 +#define Mode_360x400 3 +#define Mode_320x240 4 +#define Mode_320x480 5 +#define Mode_360x240 6 +#define Mode_360x480 7 + + /* ===== MODE X SETUP ROUTINES ===== */ + +int far pascal set_vga_modex (int Mode, int MaxXpos, int MaxYpos, int Pages); +int far pascal set_modex (int Mode); + + /* ===== BASIC GRAPHICS PRIMITIVES ===== */ + +void far pascal clear_vga_screen (int Color); +void far pascal set_point (int Xpos, int Ypos, int Color); +int far pascal read_point (int Xpos, int Ypos); +void far pascal fill_block (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); +void far pascal draw_line (int Xpos1, int Ypos1, int Xpos2, int Ypos2, + int Color); + + /* ===== DAC COLOR REGISTER ROUTINES ===== */ + +void far pascal set_dac_register (int RegNo, int Red, int Green, int Blue); +void far pascal get_dac_register (int RegNo, int* Red, int* Green, int* Blue); +void far pascal load_dac_registers (char far *PalData, int StartReg, + int EndReg, int VSync); +void far pascal readd_dac_registers (char far *PalData, int StartReg, + int EndReg); + + /* ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== */ + +void far pascal set_active_page (int PageNo); +int far pascal get_active_page (void); +void far pascal set_display_page (int PageNo); +int far pascal get_display_page (void); +void far pascal set_window (int DisplayPage, int XOffset, int YOffset); +int far pascal get_x_offset (void); +int far pascal get_y_offset (void); +void far pascal sync_display (void); + + /* ===== TEXT DISPLAY ROUTINES ===== */ + +void far pascal gprintc (int CharNum, int Xpos, int Ypos, int ColorF, + int ColorB); +void far pascal tgprintc (int CharNum, int Xpos, int Ypos, int ColorF); +void far pascal print_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF, int ColorB); +void far pascal tprint_str (char far *Text, int MaxLen, int Xpos, int Ypos, + int ColorF); +void far pascal set_display_font (char far *FontData, int FontNumber); + + /* ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== */ + +void far pascal draw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); +void far pascal tdraw_bitmap (char far *Image, int Xpos, int Ypos, + int Width, int Height); + + /* ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== */ + +void far pascal copy_page (int SourcePage, int DestPage); +void far pascal copy_bitmap (int SourcePage, int X1, int Y1, int X2, int Y2, + int DestPage, int DestX1, int DestY1); + + +#endif diff --git a/16/lib/modex105/MODEX.LST b/16/lib/modex105/MODEX.LST new file mode 100644 index 00000000..b578d08c --- /dev/null +++ b/16/lib/modex105/MODEX.LST @@ -0,0 +1,4122 @@ +Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 1 - 1 + + + ;======================================================== + ; MODEX.ASM - A Complete Mode X Library + ; + ; Version 1.04 Release, 3 May 1993, By Matt Pritchard + ; With considerable input from Michael Abrash + ; + ; The following information is donated to the public domain in + ; the hopes that save other programmers much frustration. + ; + ; If you do use this code in a product, it would be nice if + ; you include a line like "Mode X routines by Matt Pritchard" + ; in the credits. + ; + ; ========================================================= + ; + ; All of this code is designed to be assembled with MASM 5.10a + ; but TASM 3.0 could be used as well. + ; + ; The routines contained are designed for use in a MEDIUM model + ; program. All Routines are FAR, and is assumed that a DGROUP + ; data segment exists and that DS will point to it on entry. + ; + ; For all routines, the AX, BX, CX, DX, ES and FLAGS registers + ; will not be preserved, while the DS, BP, SI and DI registers + ; will be preserved. + ; + ; Unless specifically noted, All Parameters are assumed to be + ; "PASSED BY VALUE". That is, the actual value is placed on + ; the stack. When a reference is passed it is assumed to be + ; a near pointer to a variable in the DGROUP segment. + ; + ; Routines that return a single 16-Bit integer value will + ; return that value in the AX register. + ; + ; This code will *NOT* run on an 8086/8088 because 80286+ + ; specific instructions are used. If you have an 8088/86 + ; and VGA, you can buy an 80386-40 motherboard for about + ; $160 and move into the 90's. + ; + ; This code is reasonably optimized: Most drawing loops have + ; been unrolled once and memory references are minimized by + ; keeping stuff in registers when possible. + ; + ; Error Trapping varies by Routine. No Clipping is performed + ; so the caller should verify that all coordinates are valid. + ; + ; Several Macros are used to simplify common 2 or 3 instruction + ; sequences. Several Single letter Text Constants also + ; simplify common assembler expressions like "WORD PTR". + ; + ; ------------------ Mode X Variations ------------------ + ; + ; Mode # Screen Size Max Pages Aspect Ratio (X:Y) + ; + ; 0 320 x 200 4 Pages 1.2:1 + ; 1 320 x 400 2 Pages 2.4:1 + ; 2 360 x 200 3 Pages 1.35:1 + ; 3 360 x 400 1 Page 2.7:1 + ; 4 320 x 240 3 Pages 1:1 + ; 5 320 x 480 1 Page 2:1 + ; 6 360 x 240 3 Pages 1.125:1 + ; 7 360 x 480 1 Page 2.25:1 + ; + ; -------------------- The Legal Stuff ------------------ + ; + ; No warranty, either written or implied, is made as to + ; the accuracy and usability of this code product. Use + ; at your own risk. Batteries not included. Pepperoni + ; and extra cheese available for an additional charge. + ; + ; ----------------------- The Author -------------------- + ; + ; Matt Pritchard is a paid programmer who'd rather be + ; writing games. He can be reached at: P.O. Box 140264, + ; Irving, TX 75014 USA. Michael Abrash is a living + ; god, who now works for Bill Gates (Microsoft). + ; + ; -------------------- Revision History ----------------- + ; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI + ; SET_MODEX now saves SI + ; 5-3-93: v1.04 - added LOAD_DAC_REGISTERS and + ; READ_DAC_REGISTERS. Expanded CLR Macro + ; to handle multiple registers + ; + + PAGE 255, 132 + + .MODEL Medium + .286 + + ; ===== MACROS ===== + + ; Macro to OUT a 16 bit value to an I/O port + + OUT_16 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AX not setup + MOV AX, Value ; then Get Data Value + ENDIF + OUT DX, AX ; Set I/O Register(s) + ENDM + + ; Macro to OUT a 8 bit value to an I/O Port + + OUT_8 MACRO Register, Value + IFDIFI , ; If DX not setup + MOV DX, Register ; then Select Register + ENDIF + IFDIFI , ; If AL not Setup + MOV AL, Value ; then Get Data Value + ENDIF + OUT DX, AL ; Set I/O Register + ENDM + + ; macros to PUSH and POP multiple registers + + PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + PUSH R1 ; Save R1 + PUSHx R2, R3, R4, R5, R6, R7, R8 + ENDIF + ENDM + + POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8 + IFNB + POP R1 ; Restore R1 + POPx R2, R3, R4, R5, R6, R7, R8 + ENDIF + ENDM + + ; Macro to Clear Registers to 0 + + CLR MACRO Register, R2, R3, R4, R5, R6 + IFNB + XOR Register, Register ; Set Register = 0 + CLR R2, R3, R4, R5, R6 + ENDIF + ENDM + + ; Macros to Decrement Counter & Jump on Condition + + LOOPx MACRO Register, Destination + DEC Register ; Counter-- + JNZ Destination ; Jump if not 0 + ENDM + + LOOPjz MACRO Register, Destination + DEC Register ; Counter-- + JZ Destination ; Jump if 0 + ENDM + + + ; ===== General Constants ===== + + = 0000 False EQU 0 + =-0001 True EQU -1 + = 0000 nil EQU 0 + + = BYTE PTR b EQU BYTE PTR + = WORD PTR w EQU WORD PTR + = DWORD PTR d EQU DWORD PTR + = OFFSET o EQU OFFSET + = FAR PTR f EQU FAR PTR + = SHORT s EQU SHORT + = ?,?,?,? ?x4 EQU + = ?,?,? ?x3 EQU + + ; ===== VGA Register Values ===== + + = A000 VGA_Segment EQU 0A000h ; Vga Memory Segment + + = 03C0 ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller + = 03CE GC_Index EQU 03CEh ; VGA Graphics Controller + = 03C4 SC_Index EQU 03C4h ; VGA Sequencer Controller + = 03C5 SC_Data EQU 03C5h ; VGA Sequencer Data Port + = 03D4 CRTC_Index EQU 03D4h ; VGA CRT Controller + = 03D5 CRTC_Data EQU 03D5h ; VGA CRT Controller Data + = 03C2 MISC_OUTPUT EQU 03C2h ; VGA Misc Register + = 03DA INPUT_1 EQU 03DAh ; Input Status #1 Register + + = 03C8 DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register + = 03C7 DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register + = 03C9 PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W + + = 0033 PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg + = 0002 MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg + = 0004 READ_MAP EQU 004h ; GC Index: Read Map Register + = 000C START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi + = 000D START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo + + = 0102 MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1 + = 1102 MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1 + = 0F02 ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes + + = 0604 CHAIN4_OFF EQU 00604h ; Chain 4 mode Off + = 0100 ASYNC_RESET EQU 00100h ; (A)synchronous Reset + = 0300 SEQU_RESTART EQU 00300h ; Sequencer Restart + + = 0008 LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches + = FF08 LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU + + = 0008 VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit + = 0003 PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane # + = 000F ALL_PLANES EQU 0Fh ; All Bit Planes Selected + = 000F CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data + + = 1130 GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set + = 0003 ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer + = 0004 ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer + + ; Constants Specific for these routines + + = 0008 NUM_MODES EQU 8 ; # of Mode X Variations + + ; Specific Mode Data Table format... + + 000C Mode_Data_Table STRUC + 0000 00 M_MiscR DB ? ; Value of MISC_OUTPUT register + 0001 00 M_Pages DB ? ; Maximum Possible # of pages + 0002 0000 M_XSize DW ? ; X Size Displayed on screen + 0004 0000 M_YSize DW ? ; Y Size Displayed on screen + 0006 0000 M_XMax DW ? ; Maximum Possible X Size + 0008 0000 M_YMax DW ? ; Maximum Possible Y Size + 000A 0000 M_CRTC DW ? ; Table of CRTC register values + Mode_Data_Table ENDS + + ; ===== DGROUP STORAGE NEEDED (42 BYTES) ===== + + 0000 .DATA? + + 0000 0000 SCREEN_WIDTH DW 0 ; Width of a line in Bytes + 0002 0000 SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels + + 0004 0000 LAST_PAGE DW 0 ; # of Display Pages + 0006 0004 [ PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page + 0000 + ] + + 000E 0000 PAGE_SIZE DW 0 ; Size of Page in Addr Bytes + + 0010 0000 DISPLAY_PAGE DW 0 ; Page # currently displayed + 0012 0000 ACTIVE_PAGE DW 0 ; Page # currently active + + 0014 0000 CURRENT_PAGE DW 0 ; Offset of current Page + 0016 0000 CURRENT_SEGMENT DW 0 ; Segment of VGA memory + + 0018 0000 CURRENT_XOFFSET DW 0 ; Current Display X Offset + 001A 0000 CURRENT_YOFFSET DW 0 ; Current Display Y Offset + + 001C 0000 CURRENT_MOFFSET DW 0 ; Current Start Offset + + 001E 0000 MAX_XOFFSET DW 0 ; Current Display X Offset + 0020 0000 MAX_YOFFSET DW 0 ; Current Display Y Offset + + 0022 0000 0000 CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127 + 0026 0000 0000 CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255 + + 0000 .CODE + + ; ===== DATA TABLES ===== + + ; Data Tables, Put in Code Segment for Easy Access + ; (Like when all the other Segment Registers are in + ; use!!) and reduced DGROUP requirements... + + ; Bit Mask Tables for Left/Right/Character Masks + + 0000 0F 0E 0C 08 Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H + + 0004 01 03 07 0F Right_Clip_Mask DB 01H, 03H, 07H, 0FH + + ; Bit Patterns for converting character fonts + + 0008 00 08 04 0C 02 0A Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH + 06 0E + 0010 01 09 05 0D 03 0B DB 01H,09H,05H,0DH,03H,0BH,07H,0FH + 07 0F + + ; CRTC Register Values for Various Configurations + + 0018 MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes + 0018 4009 DW 04009H ; Cell Height (1 Scan Line) + 001A 0014 DW 00014H ; Dword Mode off + 001C E317 DW 0E317H ; turn on Byte Mode + 001E 0000 DW nil ; End of CRTC Data for 400/480 Line Mode + + 0020 MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes + 0020 4109 DW 04109H ; Cell Height (2 Scan Lines) + 0022 0014 DW 00014H ; Dword Mode off + 0024 E317 DW 0E317H ; turn on Byte Mode + 0026 0000 DW nil ; End of CRTC Data for 200/240 Line Mode + + 0028 MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels + 0028 5F00 DW 05F00H ; Horz total + 002A 4F01 DW 04F01H ; Horz Displayed + 002C 5002 DW 05002H ; Start Horz Blanking + 002E 8203 DW 08203H ; End Horz Blanking + 0030 5404 DW 05404H ; Start H Sync + 0032 8005 DW 08005H ; End H Sync + 0034 0000 DW nil ; End of CRTC Data for 320 Horz pixels + + 0036 MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels + 0036 6B00 DW 06B00H ; Horz total + 0038 5901 DW 05901H ; Horz Displayed + 003A 5A02 DW 05A02H ; Start Horz Blanking + 003C 8E03 DW 08E03H ; End Horz Blanking + 003E 5E04 DW 05E04H ; Start H Sync + 0040 8A05 DW 08A05H ; End H Sync + 0042 0000 DW nil ; End of CRTC Data for 360 Horz pixels + + 0044 MODE_200_Tall: + 0044 MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes + 0044 BF06 DW 0BF06H ; Vertical Total + 0046 1F07 DW 01F07H ; Overflow + 0048 9C10 DW 09C10H ; V Sync Start + 004A 8E11 DW 08E11H ; V Sync End/Prot Cr0 Cr7 + 004C 8F12 DW 08F12H ; Vertical Displayed + 004E 9615 DW 09615H ; V Blank Start + 0050 B916 DW 0B916H ; V Blank End + 0052 0000 DW nil ; End of CRTC Data for 200/400 Lines + + 0054 MODE_240_Tall: + 0054 MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes + 0054 0D06 DW 00D06H ; Vertical Total + 0056 3E07 DW 03E07H ; Overflow + 0058 EA10 DW 0EA10H ; V Sync Start + 005A 8C11 DW 08C11H ; V Sync End/Prot Cr0 Cr7 + 005C DF12 DW 0DF12H ; Vertical Displayed + 005E E715 DW 0E715H ; V Blank Start + 0060 0616 DW 00616H ; V Blank End + 0062 0000 DW nil ; End of CRTC Data for 240/480 Lines + + ; Table of Display Mode Tables + + 0064 MODE_TABLE: + 0064 0074 R 0086 R DW o MODE_320x200, o MODE_320x400 + 0068 00E0 R 00F2 R DW o MODE_360x200, o MODE_360x400 + 006C 00BC R 00CE R DW o MODE_320x240, o MODE_320x480 + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 2 - 1 + + + 0070 0098 R 00AA R DW o MODE_360x240, o MODE_360x480 + + ; Table of Display Mode Components + + 0074 MODE_320x200: ; Data for 320 by 200 Pixels + + 0074 63 DB 063h ; 400 scan Lines & 25 Mhz Clock + 0075 04 DB 4 ; Maximum of 4 Pages + 0076 0140 00C8 DW 320, 200 ; Displayed Pixels (X,Y) + 007A 0516 0330 DW 1302, 816 ; Max Possible X and Y Sizes + + 007E 0028 R 0044 R DW o MODE_320_Wide, o MODE_200_Tall + 0082 0020 R 0000 DW o MODE_Double_Line, nil + + 0086 MODE_320x400: ; Data for 320 by 400 Pixels + + 0086 63 DB 063h ; 400 scan Lines & 25 Mhz Clock + 0087 02 DB 2 ; Maximum of 2 Pages + 0088 0140 0190 DW 320, 400 ; Displayed Pixels X,Y + 008C 0288 0330 DW 648, 816 ; Max Possible X and Y Sizes + + 0090 0028 R 0044 R DW o MODE_320_Wide, o MODE_400_Tall + 0094 0018 R 0000 DW o MODE_Single_Line, nil + + 0098 MODE_360x240: ; Data for 360 by 240 Pixels + + 0098 E7 DB 0E7h ; 480 scan Lines & 28 Mhz Clock + 0099 03 DB 3 ; Maximum of 3 Pages + 009A 0168 00F0 DW 360, 240 ; Displayed Pixels X,Y + 009E 0444 02D8 DW 1092, 728 ; Max Possible X and Y Sizes + + 00A2 0036 R 0054 R DW o MODE_360_Wide, o MODE_240_Tall + 00A6 0020 R 0000 DW o MODE_Double_Line , nil + + 00AA MODE_360x480: ; Data for 360 by 480 Pixels + + 00AA E7 DB 0E7h ; 480 scan Lines & 28 Mhz Clock + 00AB 01 DB 1 ; Only 1 Page Possible + 00AC 0168 01E0 DW 360, 480 ; Displayed Pixels X,Y + 00B0 0220 02D8 DW 544, 728 ; Max Possible X and Y Sizes + + 00B4 0036 R 0054 R DW o MODE_360_Wide, o MODE_480_Tall + 00B8 0018 R 0000 DW o MODE_Single_Line , nil + + 00BC MODE_320x240: ; Data for 320 by 240 Pixels + + 00BC E3 DB 0E3h ; 480 scan Lines & 25 Mhz Clock + 00BD 03 DB 3 ; Maximum of 3 Pages + 00BE 0140 00F0 DW 320, 240 ; Displayed Pixels X,Y + 00C2 0440 0332 DW 1088, 818 ; Max Possible X and Y Sizes + + 00C6 0028 R 0054 R DW o MODE_320_Wide, o MODE_240_Tall + 00CA 0020 R 0000 DW o MODE_Double_Line, nil + + 00CE MODE_320x480: ; Data for 320 by 480 Pixels + + 00CE E3 DB 0E3h ; 480 scan Lines & 25 Mhz Clock + 00CF 01 DB 1 ; Only 1 Page Possible + 00D0 0140 01E0 DW 320, 480 ; Displayed Pixels X,Y + 00D4 021C 0332 DW 540, 818 ; Max Possible X and Y Sizes + + 00D8 0028 R 0054 R DW o MODE_320_WIDE, o MODE_480_Tall + 00DC 0018 R 0000 DW o MODE_Single_Line, nil + + 00E0 MODE_360x200: ; Data for 360 by 200 Pixels + + 00E0 67 DB 067h ; 400 scan Lines & 28 Mhz Clock + 00E1 03 DB 3 ; Maximum of 3 Pages + 00E2 0168 00C8 DW 360, 200 ; Displayed Pixels (X,Y) + 00E6 0516 02D8 DW 1302, 728 ; Max Possible X and Y Sizes + + 00EA 0036 R 0044 R DW o MODE_360_Wide, MODE_200_Tall + 00EE 0020 R 0000 DW o MODE_Double_Line, nil + + 00F2 MODE_360x400: ; Data for 360 by 400 Pixels + + 00F2 67 DB 067h ; 400 scan Lines & 28 Mhz Clock + 00F3 01 DB 1 ; Maximum of 1 Pages + 00F4 0168 0190 DW 360, 400 ; Displayed Pixels X,Y + 00F8 0288 0330 DW 648, 816 ; Max Possible X and Y Sizes + + 00FC 0036 R 0044 R DW o MODE_360_Wide, MODE_400_Tall + 0100 0018 R 0000 DW o MODE_Single_Line, nil + + + ; ===== MODE X SETUP ROUTINES ===== + + ;====================================================== + ;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%) + ;====================================================== + ; + ; Sets Up the specified version of Mode X. Allows for + ; the setup of multiple video pages, and a virtual + ; screen which can be larger than the displayed screen + ; (which can then be scrolled a pixel at a time) + ; + ; ENTRY: ModeType = Desired Screen Resolution (0-7) + ; + ; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio + ; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio + ; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio + ; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio + ; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio + ; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio + ; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio + ; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio + ; + ; MaxXpos = The Desired Virtual Screen Width + ; MaxYpos = The Desired Virtual Screen Height + ; Pages = The Desired # of Video Pages + ; + ; EXIT: AX = Success Flag: 0 = Failure / -1= Success + ; + + 0016 SVM_STACK STRUC + 0000 0000 SVM_Table DW ? ; Offset of Mode Info Table + 0002 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 000A 00000000 DD ? ; Caller + 000E 0000 SVM_Pages DW ? ; # of Screen Pages desired + 0010 0000 SVM_Ysize DW ? ; Vertical Screen Size Desired + 0012 0000 SVM_Xsize DW ? ; Horizontal Screen Size Desired + 0014 0000 SVM_Mode DW ? ; Display Resolution Desired + SVM_STACK ENDS + + PUBLIC SET_VGA_MODEX + + 0104 SET_VGA_MODEX PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 0104 55 1 PUSH BP ; Save R1 + 0105 1E 2 PUSH DS ; Save R1 + 0106 56 3 PUSH SI ; Save R1 + 0107 57 4 PUSH DI ; Save R1 + 0108 83 EC 02 SUB SP, 2 ; Allocate workspace + 010B 8B EC MOV BP, SP ; Set up Stack Frame + + ; Check Legality of Mode Request.... + + 010D 8B 5E 14 MOV BX, [BP].SVM_Mode ; Get Requested Mode # + 0110 83 FB 08 CMP BX, NUM_MODES ; Is it 0..7? + 0113 73 47 JAE @SVM_BadModeSetup ; If Not, Error out + + 0115 D1 E3 SHL BX, 1 ; Scale BX + 0117 2E: 8B B7 0064 R MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + 011C 89 76 00 MOV [BP].SVM_Table, SI ; Save ptr for later use + + ; Check # of Requested Display Pages + + 011F 8B 4E 0E MOV CX, [BP].SVM_Pages ; Get # of Requested Pages + CLR CH ; Set Hi Word = 0! + 0122 32 ED 1 XOR CH, CH ; Set Register = 0 + 0124 2E: 3A 4C 01 CMP CL, CS:[SI].M_Pages ; Check # Pages for mode + 0128 77 32 JA @SVM_BadModeSetup ; Report Error if too Many Pages + 012A E3 30 JCXZ @SVM_BadModeSetup ; Report Error if 0 Pages + + ; Check Validity of X Size + + 012C 83 66 12 F8 AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0 + + 0130 8B 46 12 MOV AX, [BP].SVM_XSize ; Get Logical Screen Width + 0133 2E: 3B 44 02 CMP AX, CS:[SI].M_XSize ; Check against Displayed X + 0137 72 23 JB @SVM_BadModeSetup ; Report Error if too small + 0139 2E: 3B 44 06 CMP AX, CS:[SI].M_XMax ; Check against Max X + 013D 77 1D JA @SVM_BadModeSetup ; Report Error if too big + + ; Check Validity of Y Size + + 013F 8B 5E 10 MOV BX, [BP].SVM_YSize ; Get Logical Screen Height + 0142 2E: 3B 5C 04 CMP BX, CS:[SI].M_YSize ; Check against Displayed Y + 0146 72 14 JB @SVM_BadModeSetup ; Report Error if too small + 0148 2E: 3B 5C 08 CMP BX, CS:[SI].M_YMax ; Check against Max Y + 014C 77 0E JA @SVM_BadModeSetup ; Report Error if too big + + ; Enough memory to Fit it all? + + 014E C1 E8 02 SHR AX, 2 ; # of Bytes:Line = XSize/4 + 0151 F7 E1 MUL CX ; AX = Bytes/Line * Pages + 0153 F7 E3 MUL BX ; DX:AX = Total VGA mem needed + 0155 71 0A JNO @SVM_Continue ; Exit if Total Size > 256K + + 0157 4A DEC DX ; Was it Exactly 256K??? + 0158 0B D0 OR DX, AX ; (DX = 1, AX = 0000) + 015A 74 05 JZ @SVM_Continue ; if so, it's valid... + + 015C @SVM_BadModeSetup: + + CLR AX ; Return Value = False + 015C 33 C0 1 XOR AX, AX ; Set Register = 0 + 015E E9 00E6 JMP @SVM_Exit ; Normal Exit + + 0161 @SVM_Continue: + + 0161 B8 0013 MOV AX, 13H ; Start with Mode 13H + 0164 CD 10 INT 10H ; Let BIOS Set Mode + + OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode + 0166 BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 0169 B8 0604 1 MOV AX, CHAIN4_OFF ; then Get Data Value + 016C EF 1 OUT DX, AX ; Set I/O Register(s) + OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset + 016D BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 0170 B8 0100 1 MOV AX, ASYNC_RESET ; then Get Data Value + 0173 EF 1 OUT DX, AX ; Set I/O Register(s) + OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size + 0174 BA 03C2 1 MOV DX, MISC_OUTPUT ; then Select Register + 0177 2E: 8A 04 1 MOV AL, CS:[SI].M_MiscR ; then Get Data Value + 017A EE 1 OUT DX, AL ; Set I/O Register + OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ... + 017B BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 017E B8 0300 1 MOV AX, SEQU_RESTART ; then Get Data Value + 0181 EF 1 OUT DX, AX ; Set I/O Register(s) + + OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register + 0182 BA 03D4 1 MOV DX, CRTC_INDEX ; then Select Register + 0185 B0 11 1 MOV AL, 11H ; then Get Data Value + 0187 EE 1 OUT DX, AL ; Set I/O Register + 0188 42 INC DX ; Point to Data + 0189 EC IN AL, DX ; Get Value, Bit 7 = Protect + 018A 24 7F AND AL, 7FH ; Mask out Write Protect + 018C EE OUT DX, AL ; And send it back + + 018D BA 03D4 MOV DX, CRTC_INDEX ; Vga Crtc Registers + 0190 83 C6 0A ADD SI, M_CRTC ; SI -> CRTC Parameter Data + + ; Load Tables of CRTC Parameters from List of Tables + + 0193 @SVM_Setup_Table: + + 0193 2E: 8B 3C MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl + 0196 83 C6 02 ADD SI, 2 ; Point to next Ptr Entry + 0199 0B FF OR DI, DI ; A nil Ptr means that we have + 019B 74 0D JZ @SVM_Set_Data ; finished CRTC programming + + 019D @SVM_Setup_CRTC: + 019D 2E: 8B 05 MOV AX, CS:[DI] ; Get CRTC Data from Table + 01A0 83 C7 02 ADD DI, 2 ; Advance Pointer + 01A3 0B C0 OR AX, AX ; At End of Data Table? + 01A5 74 EC JZ @SVM_Setup_Table ; If so, Exit & get next Table + + 01A7 EF OUT DX, AX ; Reprogram VGA CRTC reg + 01A8 EB F3 JMP s @SVM_Setup_CRTC ; Process Next Table Entry + + ; Initialize Page & Scroll info, DI = 0 + + 01AA @SVM_Set_Data: + 01AA 89 3E 0010 R MOV DISPLAY_PAGE, DI ; Display Page = 0 + 01AE 89 3E 0012 R MOV ACTIVE_PAGE, DI ; Active Page = 0 + 01B2 89 3E 0014 R MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0 + 01B6 89 3E 0018 R MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0 + 01BA 89 3E 001A R MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0 + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 3 - 1 + + + 01BE 89 3E 001C R MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0 + + 01C2 B8 A000 MOV AX, VGA_SEGMENT ; Segment for VGA memory + 01C5 A3 0016 R MOV CURRENT_SEGMENT, AX ; Save for Future LES's + + ; Set Logical Screen Width, X Scroll and Our Data + + 01C8 8B 76 00 MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info + 01CB 8B 46 12 MOV AX, [BP].SVM_Xsize ; Get Display Width + + 01CE 8B C8 MOV CX, AX ; CX = Logical Width + 01D0 2E: 2B 4C 02 SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value + 01D4 89 0E 001E R MOV MAX_XOFFSET, CX ; Set Maximum X Scroll + + 01D8 C1 E8 02 SHR AX, 2 ; Bytes = Pixels / 4 + 01DB A3 0000 R MOV SCREEN_WIDTH, AX ; Save Width in Pixels + + 01DE D1 E8 SHR AX, 1 ; Offset Value = Bytes / 2 + 01E0 B4 13 MOV AH, 13h ; CRTC Offset Register Index + 01E2 86 C4 XCHG AL, AH ; Switch format for OUT + 01E4 EF OUT DX, AX ; Set VGA CRTC Offset Reg + + ; Setup Data table, Y Scroll, Misc for Other Routines + + 01E5 8B 46 10 MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height + + 01E8 8B C8 MOV CX, AX ; CX = Logical Height + 01EA 2E: 2B 5C 04 SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value + 01EE 89 0E 0020 R MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll + + 01F2 A3 0002 R MOV SCREEN_HEIGHT, AX ; Save Height in Pixels + 01F5 F7 26 0000 R MUL SCREEN_WIDTH ; AX = Page Size in Bytes, + 01F9 A3 000E R MOV PAGE_SIZE, AX ; Save Page Size + + 01FC 8B 4E 0E MOV CX, [BP].SVM_Pages ; Get # of Pages + 01FF 89 0E 0004 R MOV LAST_PAGE, CX ; Save # of Pages + + CLR BX ; Page # = 0 + 0203 33 DB 1 XOR BX, BX ; Set Register = 0 + 0205 8B D3 MOV DX, BX ; Page 0 Offset = 0 + + 0207 @SVM_Set_Pages: + + 0207 89 97 0006 R MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset + 020B 83 C3 02 ADD BX, 2 ; Page#++ + 020E 03 D0 ADD DX, AX ; Compute Addr of Next Page + LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set + 0210 49 1 DEC CX ; Counter-- + 0211 75 F4 1 JNZ @SVM_Set_Pages ; Jump if not 0 + + ; Clear VGA Memory + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + 0213 BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 0216 B8 0F02 1 MOV AX, ALL_PLANES_ON ; then Get Data Value + 0219 EF 1 OUT DX, AX ; Set I/O Register(s) + 021A C4 3E 0014 R LES DI, d CURRENT_PAGE ; -> Start of VGA memory + + CLR AX ; AX = 0 + 021E 33 C0 1 XOR AX, AX ; Set Register = 0 + 0220 FC CLD ; Block Xfer Forwards + 0221 B9 8000 MOV CX, 8000H ; 32K * 4 * 2 = 256K + 0224 F3/ AB REP STOSW ; Clear dat memory! + + ; Setup Font Pointers + + 0226 B7 03 MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127 + 0228 B8 1130 MOV AX, GET_CHAR_PTR ; Service to Get Pointer + 022B CD 10 INT 10h ; Call VGA BIOS + + 022D 89 2E 0022 R MOV CHARSET_LOW, BP ; Save Char Set Offset + 0231 8C 06 0024 R MOV CHARSET_LOW+2, ES ; Save Char Set Segment + + 0235 B7 04 MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255 + 0237 B8 1130 MOV AX, GET_CHAR_PTR ; Service to Get Pointer + 023A CD 10 INT 10h ; Call VGA BIOS + + 023C 89 2E 0026 R MOV CHARSET_HI, BP ; Save Char Set Offset + 0240 8C 06 0028 R MOV CHARSET_HI+2, ES ; Save Char Set Segment + + 0244 B8 FFFF MOV AX, True ; Return Success Code + + 0247 @SVM_EXIT: + 0247 83 C4 02 ADD SP, 2 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + 024A 5F 1 POP DI ; Restore R1 + 024B 5E 2 POP SI ; Restore R1 + 024C 1F 3 POP DS ; Restore R1 + 024D 5D 4 POP BP ; Restore R1 + 024E CA 0008 RET 8 ; Exit & Clean Up Stack + + 0251 SET_VGA_MODEX ENDP + + + ;================== + ;SET_MODEX% (Mode%) + ;================== + ; + ; Quickie Mode Set - Sets Up Mode X to Default Configuration + ; + ; ENTRY: ModeType = Desired Screen Resolution (0-7) + ; (See SET_VGA_MODEX for list) + ; + ; EXIT: AX = Success Flag: 0 = Failure / -1= Success + ; + + 000A SM_STACK STRUC + 0000 0000 0000 DW ?,? ; BP, SI + 0004 00000000 DD ? ; Caller + 0008 0000 SM_Mode DW ? ; Desired Screen Resolution + SM_STACK ENDS + + PUBLIC SET_MODEX + + 0251 SET_MODEX PROC FAR + + PUSHx BP, SI ; Preserve Important registers + 0251 55 1 PUSH BP ; Save R1 + 0252 56 2 PUSH SI ; Save R1 + 0253 8B EC MOV BP, SP ; Set up Stack Frame + + CLR AX ; Assume Failure + 0255 33 C0 1 XOR AX, AX ; Set Register = 0 + 0257 8B 5E 08 MOV BX, [BP].SM_Mode ; Get Desired Mode # + 025A 83 FB 08 CMP BX, NUM_MODES ; Is it a Valid Mode #? + 025D 73 1C JAE @SMX_Exit ; If Not, don't Bother + + 025F 53 PUSH BX ; Push Mode Parameter + + 0260 D1 E3 SHL BX, 1 ; Scale BX to word Index + 0262 2E: 8B B7 0064 R MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info + + 0267 2E: FF 74 02 PUSH CS:[SI].M_XSize ; Push Default X Size + 026B 2E: FF 74 04 PUSH CS:[SI].M_Ysize ; Push Default Y size + 026F 2E: 8A 44 01 MOV AL, CS:[SI].M_Pages ; Get Default # of Pages + CLR AH ; Hi Byte = 0 + 0273 32 E4 1 XOR AH, AH ; Set Register = 0 + 0275 50 PUSH AX ; Push # Pages + + 0276 9A ---- 0104 R CALL f SET_VGA_MODEX ; Set up Mode X! + + 027B @SMX_Exit: + POPx SI, BP ; Restore Registers + 027B 5E 1 POP SI ; Restore R1 + 027C 5D 2 POP BP ; Restore R1 + 027D CA 0002 RET 2 ; Exit & Clean Up Stack + + 0280 SET_MODEX ENDP + + + ; ===== BASIC GRAPHICS PRIMITIVES ===== + + ;============================ + ;CLEAR_VGA_SCREEN (ColorNum%) + ;============================ + ; + ; Clears the active display page + ; + ; ENTRY: ColorNum = Color Value to fill the page with + ; + ; EXIT: No meaningful values returned + ; + + 000A CVS_STACK STRUC + 0000 0000 0000 DW ?,? ; DI, BP + 0004 00000000 DD ? ; Caller + 0008 00 00 CVS_COLOR DB ?,? ; Color to Set Screen to + CVS_STACK ENDS + + PUBLIC CLEAR_VGA_SCREEN + + 0280 CLEAR_VGA_SCREEN PROC FAR + + PUSHx BP, DI ; Preserve Important Registers + 0280 55 1 PUSH BP ; Save R1 + 0281 57 2 PUSH DI ; Save R1 + 0282 8B EC MOV BP, SP ; Set up Stack Frame + + OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes + 0284 BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 0287 B8 0F02 1 MOV AX, ALL_PLANES_ON ; then Get Data Value + 028A EF 1 OUT DX, AX ; Set I/O Register(s) + 028B C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + 028F 8A 46 08 MOV AL, [BP].CVS_COLOR ; Get Color + 0292 8A E0 MOV AH, AL ; Copy for Word Write + 0294 FC CLD ; Block fill Forwards + + 0295 8B 0E 000E R MOV CX, PAGE_SIZE ; Get Size of Page + 0299 D1 E9 SHR CX, 1 ; Divide by 2 for Words + 029B F3/ AB REP STOSW ; Block Fill VGA memory + + POPx DI, BP ; Restore Saved Registers + 029D 5F 1 POP DI ; Restore R1 + 029E 5D 2 POP BP ; Restore R1 + 029F CA 0002 RET 2 ; Exit & Clean Up Stack + + 02A2 CLEAR_VGA_SCREEN ENDP + + + ;=================================== + ;SET_POINT (Xpos%, Ypos%, ColorNum%) + ;=================================== + ; + ; Plots a single Pixel on the active display page + ; + ; ENTRY: Xpos = X position to plot pixel at + ; Ypos = Y position to plot pixel at + ; ColorNum = Color to plot pixel with + ; + ; EXIT: No meaningful values returned + ; + + 000E SP_STACK STRUC + 0000 0000 0000 DW ?,? ; BP, DI + 0004 00000000 DD ? ; Caller + 0008 00 00 SETP_Color DB ?,? ; Color of Point to Plot + 000A 0000 SETP_Ypos DW ? ; Y pos of Point to Plot + 000C 0000 SETP_Xpos DW ? ; X pos of Point to Plot + SP_STACK ENDS + + PUBLIC SET_POINT + + 02A2 SET_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + 02A2 55 1 PUSH BP ; Save R1 + 02A3 57 2 PUSH DI ; Save R1 + 02A4 8B EC MOV BP, SP ; Set up Stack Frame + + 02A6 C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + 02AA 8B 46 0A MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel + 02AD F7 26 0000 R MUL SCREEN_WIDTH ; Get Offset to Start of Line + + 02B1 8B 5E 0C MOV BX, [BP].SETP_Xpos ; Get Xpos + 02B4 8B CB MOV CX, BX ; Copy to extract Plane # from + 02B6 C1 EB 02 SHR BX, 2 ; X offset (Bytes) = Xpos/4 + 02B9 03 D8 ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + 02BB B8 0102 MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register + 02BE 80 E1 03 AND CL, PLANE_BITS ; Get Plane Bits + 02C1 D2 E4 SHL AH, CL ; Get Plane Select Value + OUT_16 SC_Index, AX ; Select Plane + 02C3 BA 03C4 1 MOV DX, SC_Index ; then Select Register + 02C6 EF 1 OUT DX, AX ; Set I/O Register(s) + + 02C7 8A 46 08 MOV AL,[BP].SETP_Color ; Get Pixel Color + 02CA 26: 88 01 MOV ES:[DI+BX], AL ; Draw Pixel + + POPx DI, BP ; Restore Saved Registers + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 4 - 1 + + + 02CD 5F 1 POP DI ; Restore R1 + 02CE 5D 2 POP BP ; Restore R1 + 02CF CA 0006 RET 6 ; Exit and Clean up Stack + + 02D2 SET_POINT ENDP + + + ;========================== + ;READ_POINT% (Xpos%, Ypos%) + ;========================== + ; + ; Read the color of a pixel from the Active Display Page + ; + ; ENTRY: Xpos = X position of pixel to read + ; Ypos = Y position of pixel to read + ; + ; EXIT: AX = Color of Pixel at (Xpos, Ypos) + ; + + 000C RP_STACK STRUC + 0000 0000 0000 DW ?,? ; BP, DI + 0004 00000000 DD ? ; Caller + 0008 0000 RP_Ypos DW ? ; Y pos of Point to Read + 000A 0000 RP_Xpos DW ? ; X pos of Point to Read + RP_STACK ENDS + + PUBLIC READ_POINT + + 02D2 READ_POINT PROC FAR + + PUSHx BP, DI ; Preserve Registers + 02D2 55 1 PUSH BP ; Save R1 + 02D3 57 2 PUSH DI ; Save R1 + 02D4 8B EC MOV BP, SP ; Set up Stack Frame + + 02D6 C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + 02DA 8B 46 08 MOV AX, [BP].RP_Ypos ; Get Line # of Pixel + 02DD F7 26 0000 R MUL SCREEN_WIDTH ; Get Offset to Start of Line + + 02E1 8B 5E 0A MOV BX, [BP].RP_Xpos ; Get Xpos + 02E4 8B CB MOV CX, BX + 02E6 C1 EB 02 SHR BX, 2 ; X offset (Bytes) = Xpos/4 + 02E9 03 D8 ADD BX, AX ; Offset = Width*Ypos + Xpos/4 + + 02EB B0 04 MOV AL, READ_MAP ; GC Read Mask Register + 02ED 8A E1 MOV AH, CL ; Get Xpos + 02EF 80 E4 03 AND AH, PLANE_BITS ; & mask out Plane # + OUT_16 GC_INDEX, AX ; Select Plane to read in + 02F2 BA 03CE 1 MOV DX, GC_INDEX ; then Select Register + 02F5 EF 1 OUT DX, AX ; Set I/O Register(s) + + CLR AH ; Clear Return Value Hi byte + 02F6 32 E4 1 XOR AH, AH ; Set Register = 0 + 02F8 26: 8A 01 MOV AL, ES:[DI+BX] ; Get Color of Pixel + + POPx DI, BP ; Restore Saved Registers + 02FB 5F 1 POP DI ; Restore R1 + 02FC 5D 2 POP BP ; Restore R1 + 02FD CA 0004 RET 4 ; Exit and Clean up Stack + + 0300 READ_POINT ENDP + + + ;====================================================== + ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) + ;====================================================== + ; + ; Fills a rectangular block on the active display Page + ; + ; ENTRY: Xpos1 = Left X position of area to fill + ; Ypos1 = Top Y position of area to fill + ; Xpos2 = Right X position of area to fill + ; Ypos2 = Bottom Y position of area to fill + ; ColorNum = Color to fill area with + ; + ; EXIT: No meaningful values returned + ; + + 0016 FB_STACK STRUC + 0000 0000 0000 0000 DW ?x4 ; DS, DI, SI, BP + 0000 + 0008 00000000 DD ? ; Caller + 000C 00 00 FB_Color DB ?,? ; Fill Color + 000E 0000 FB_Ypos2 DW ? ; Y pos of Lower Right Pixel + 0010 0000 FB_Xpos2 DW ? ; X pos of Lower Right Pixel + 0012 0000 FB_Ypos1 DW ? ; Y pos of Upper Left Pixel + 0014 0000 FB_Xpos1 DW ? ; X pos of Upper Left Pixel + FB_STACK ENDS + + PUBLIC FILL_BLOCK + + 0300 FILL_BLOCK PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 0300 55 1 PUSH BP ; Save R1 + 0301 1E 2 PUSH DS ; Save R1 + 0302 56 3 PUSH SI ; Save R1 + 0303 57 4 PUSH DI ; Save R1 + 0304 8B EC MOV BP, SP ; Set up Stack Frame + + 0306 C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + 030A FC CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + 030B BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 030E B0 02 1 MOV AL, MAP_MASK ; then Get Data Value + 0310 EE 1 OUT DX, AL ; Set I/O Register + + ; Validate Pixel Coordinates + ; If necessary, Swap so X1 <= X2, Y1 <= Y2 + + 0311 8B 46 12 MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2? + 0314 8B 5E 0E MOV BX, [BP].FB_Ypos2 ; BX = Y2 + 0317 3B C3 CMP AX, BX + 0319 7E 04 JLE @FB_NOSWAP1 + + 031B 89 5E 12 MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1 + 031E 93 XCHG AX, BX ; on stack for future use + + 031F @FB_NOSWAP1: + 031F 2B D8 SUB BX, AX ; Get Y width + 0321 43 INC BX ; Add 1 to avoid 0 value + 0322 89 5E 0E MOV [BP].FB_Ypos2, BX ; Save in Ypos2 + + 0325 F7 26 0000 R MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line + 0329 03 F8 ADD DI, AX ; DI = Start of Line Y1 + + 032B 8B 46 14 MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2 + 032E 8B 5E 10 MOV BX, [BP].FB_Xpos2 ; + 0331 3B C3 CMP AX, BX + 0333 7E 04 JLE @FB_NOSWAP2 ; Skip Ahead if Ok + + 0335 89 46 10 MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2 + 0338 93 XCHG AX, BX ; on stack for future use + + ; All our Input Values are in order, Now determine + ; How many full "bands" 4 pixels wide (aligned) there + ; are, and if there are partial bands (<4 pixels) on + ; the left and right edges. + + 0339 @FB_NOSWAP2: + 0339 8B D0 MOV DX, AX ; DX = X1 (Pixel Position) + 033B C1 EA 02 SHR DX, 2 ; DX/4 = Bytes into Line + 033E 03 FA ADD DI, DX ; DI = Addr of Upper-Left Corner + + 0340 8B CB MOV CX, BX ; CX = X2 (Pixel Position) + 0342 C1 E9 02 SHR CX, 2 ; CX/4 = Bytes into Line + + 0345 3B D1 CMP DX, CX ; Start and end in same band? + 0347 75 03 JNE @FB_NORMAL ; if not, check for l & r edges + 0349 E9 0086 JMP @FB_ONE_BAND_ONLY ; if so, then special processing + + 034C @FB_NORMAL: + 034C 2B CA SUB CX, DX ; CX = # bands -1 + 034E 8B F0 MOV SI, AX ; SI = PLANE#(X1) + 0350 83 E6 03 AND SI, PLANE_BITS ; if Left edge is aligned then + 0353 74 27 JZ @FB_L_PLANE_FLUSH ; no special processing.. + + ; Draw "Left Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask + 0355 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0358 2E: 8A 84 0000 R 1 MOV AL, Left_Clip_Mask[SI] ; then Get Data Value + 035D EE 1 OUT DX, AL ; Set I/O Register + + 035E 8B F7 MOV SI, DI ; SI = Copy of Start Addr (UL) + + 0360 8B 56 0E MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + 0363 8A 46 0C MOV AL, [BP].FB_Color ; Get Fill Color + 0366 8B 1E 0000 R MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + + 036A @FB_LEFT_LOOP: + 036A 26: 88 04 MOV ES:[SI], AL ; Fill in Left Edge Pixels + 036D 03 F3 ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn + 036F 4A 1 DEC DX ; Counter-- + 0370 74 08 1 JZ @FB_LEFT_CONT ; Jump if 0 + + 0372 26: 88 04 MOV ES:[SI], AL ; Fill in Left Edge Pixels + 0375 03 F3 ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn + 0377 4A 1 DEC DX ; Counter-- + 0378 75 F0 1 JNZ @FB_LEFT_LOOP ; Jump if not 0 + + 037A @FB_LEFT_CONT: + + 037A 47 INC DI ; Point to Middle (or Right) Block + 037B 49 DEC CX ; Reset CX instead of JMP @FB_RIGHT + + 037C @FB_L_PLANE_FLUSH: + 037C 41 INC CX ; Add in Left band to middle block + + ; DI = Addr of 1st middle Pixel (band) to fill + ; CX = # of Bands to fill -1 + + 037D @FB_RIGHT: + 037D 8B 76 10 MOV SI, [BP].FB_Xpos2 ; Get Xpos2 + 0380 83 E6 03 AND SI, PLANE_BITS ; Get Plane values + 0383 83 FE 03 CMP SI, 0003 ; Plane = 3? + 0386 74 2B JE @FB_R_EDGE_FLUSH ; Hey, add to middle + + ; Draw "Right Edge" vertical strip of 1-3 pixels... + + OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask + 0388 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 038B 2E: 8A 84 0004 R 1 MOV AL, Right_Clip_Mask[SI] ; then Get Data Value + 0390 EE 1 OUT DX, AL ; Set I/O Register + + 0391 8B F7 MOV SI, DI ; Get Addr of Left Edge + 0393 03 F1 ADD SI, CX ; Add Width-1 (Bands) + 0395 4E DEC SI ; To point to top of Right Edge + + 0396 8B 56 0E MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw + 0399 8A 46 0C MOV AL, [BP].FB_Color ; Get Fill Color + 039C 8B 1E 0000 R MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + + 03A0 @FB_RIGHT_LOOP: + 03A0 26: 88 04 MOV ES:[SI], AL ; Fill in Right Edge Pixels + 03A3 03 F3 ADD SI, BX ; Point to Next Line (Below) + LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn + 03A5 4A 1 DEC DX ; Counter-- + 03A6 74 08 1 JZ @FB_RIGHT_CONT ; Jump if 0 + + 03A8 26: 88 04 MOV ES:[SI], AL ; Fill in Right Edge Pixels + 03AB 03 F3 ADD SI, BX ; Point to Next Line (Below) + LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn + 03AD 4A 1 DEC DX ; Counter-- + 03AE 75 F0 1 JNZ @FB_RIGHT_LOOP ; Jump if not 0 + + 03B0 @FB_RIGHT_CONT: + + 03B0 49 DEC CX ; Minus 1 for Middle bands + 03B1 74 51 JZ @FB_EXIT ; Uh.. no Middle bands... + + 03B3 @FB_R_EDGE_FLUSH: + + ; DI = Addr of Upper Left block to fill + ; CX = # of Bands to fill in (width) + + OUT_8 SC_Data, ALL_PLANES ; Write to All Planes + 03B3 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 03B6 B0 0F 1 MOV AL, ALL_PLANES ; then Get Data Value + 03B8 EE 1 OUT DX, AL ; Set I/O Register + + 03B9 8B 16 0000 R MOV DX, SCREEN_WIDTH ; DX = DI Increment + 03BD 2B D1 SUB DX, CX ; = Screen_Width-# Planes Filled + + 03BF 8B D9 MOV BX, CX ; BX = Quick Refill for CX + 03C1 8B 76 0E MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill + 03C4 8A 46 0C MOV AL, [BP].FB_Color ; Get Fill Color + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 5 - 1 + + + + 03C7 @FB_MIDDLE_LOOP: + 03C7 F3/ AA REP STOSB ; Fill in entire line + + 03C9 8B CB MOV CX, BX ; Recharge CX (Line Width) + 03CB 03 FA ADD DI, DX ; Point to start of Next Line + LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn + 03CD 4E 1 DEC SI ; Counter-- + 03CE 75 F7 1 JNZ @FB_MIDDLE_LOOP ; Jump if not 0 + + 03D0 EB 32 JMP s @FB_EXIT ; Outa here + + 03D2 @FB_ONE_BAND_ONLY: + 03D2 8B F0 MOV SI, AX ; Get Left Clip Mask, Save X1 + 03D4 83 E6 03 AND SI, PLANE_BITS ; Mask out Row # + 03D7 2E: 8A 84 0000 R MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask + 03DC 8B F3 MOV SI, BX ; Get Right Clip Mask, Save X2 + 03DE 83 E6 03 AND SI, PLANE_BITS ; Mask out Row # + 03E1 2E: 22 84 0004 R AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + 03E6 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 03E9 EE 1 OUT DX, AL ; Set I/O Register + + 03EA 8B 4E 0E MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw + 03ED 8A 46 0C MOV AL, [BP].FB_Color ; Get Fill Color + 03F0 8B 1E 0000 R MOV BX, SCREEN_WIDTH ; Get Vertical increment Value + + 03F4 @FB_ONE_LOOP: + 03F4 26: 88 05 MOV ES:[DI], AL ; Fill in Pixels + 03F7 03 FB ADD DI, BX ; Point to Next Line (Below) + LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn + 03F9 49 1 DEC CX ; Counter-- + 03FA 74 08 1 JZ @FB_EXIT ; Jump if 0 + + 03FC 26: 88 05 MOV ES:[DI], AL ; Fill in Pixels + 03FF 03 FB ADD DI, BX ; Point to Next Line (Below) + LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn + 0401 49 1 DEC CX ; Counter-- + 0402 75 F0 1 JNZ @FB_ONE_LOOP ; Jump if not 0 + + 0404 @FB_EXIT: + POPx DI, SI, DS, BP ; Restore Saved Registers + 0404 5F 1 POP DI ; Restore R1 + 0405 5E 2 POP SI ; Restore R1 + 0406 1F 3 POP DS ; Restore R1 + 0407 5D 4 POP BP ; Restore R1 + 0408 CA 000A RET 10 ; Exit and Clean up Stack + + 040B FILL_BLOCK ENDP + + + ;===================================================== + ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%) + ;===================================================== + ; + ; Draws a Line on the active display page + ; + ; ENTRY: Xpos1 = X position of first point on line + ; Ypos1 = Y position of first point on line + ; Xpos2 = X position of last point on line + ; Ypos2 = Y position of last point on line + ; ColorNum = Color to draw line with + ; + ; EXIT: No meaningful values returned + ; + + 0014 DL_STACK STRUC + 0000 0000 0000 0000 DW ?x3 ; DI, SI, BP + 0006 00000000 DD ? ; Caller + 000A 00 00 DL_ColorF DB ?,? ; Line Draw Color + 000C 0000 DL_Ypos2 DW ? ; Y pos of last point + 000E 0000 DL_Xpos2 DW ? ; X pos of last point + 0010 0000 DL_Ypos1 DW ? ; Y pos of first point + 0012 0000 DL_Xpos1 DW ? ; X pos of first point + DL_STACK ENDS + + PUBLIC DRAW_LINE + + 040B DRAW_LINE PROC FAR + + PUSHx BP, SI, DI ; Preserve Important Registers + 040B 55 1 PUSH BP ; Save R1 + 040C 56 2 PUSH SI ; Save R1 + 040D 57 3 PUSH DI ; Save R1 + 040E 8B EC MOV BP, SP ; Set up Stack Frame + 0410 FC CLD ; Direction Flag = Forward + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + 0411 BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 0414 B0 02 1 MOV AL, MAP_MASK ; then Get Data Value + 0416 EE 1 OUT DX, AL ; Set I/O Register + 0417 8A 6E 0A MOV CH, [BP].DL_ColorF ; Save Line Color in CH + + ; Check Line Type + + 041A 8B 76 12 MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2? + 041D 8B 7E 0E MOV DI, [BP].DL_Xpos2 ; DX = X2 + 0420 3B F7 CMP SI, DI ; Is X1 < X2 + 0422 74 5D JE @DL_VLINE ; If X1=X2, Draw Vertical Line + 0424 7C 02 JL @DL_NOSWAP1 ; If X1 < X2, don't swap + + 0426 87 F7 XCHG SI, DI ; X2 IS > X1, SO SWAP THEM + + 0428 @DL_NOSWAP1: + + ; SI = X1, DI = X2 + + 0428 8B 46 10 MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2? + 042B 3B 46 0C CMP AX, [BP].DL_Ypos2 ; Y1 = Y2? + 042E 74 03 JE @DL_HORZ ; If so, Draw a Horizontal Line + + 0430 E9 0094 JMP @DL_BREZHAM ; Diagonal line... go do it... + + ; This Code draws a Horizontal Line in Mode X where: + ; SI = X1, DI = X2, and AX = Y1/Y2 + + 0433 @DL_HORZ: + + 0433 F7 26 0000 R MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width + 0437 8B D0 MOV DX, AX ; CX = Line offset into Page + + 0439 8B C6 MOV AX, SI ; Get Left edge, Save X1 + 043B 83 E6 03 AND SI, PLANE_BITS ; Mask out Row # + 043E 2E: 8A 9C 0000 R MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask + 0443 8B CF MOV CX, DI ; Get Right edge, Save X2 + 0445 83 E7 03 AND DI, PLANE_BITS ; Mask out Row # + 0448 2E: 8A BD 0004 R MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte + + 044D C1 E8 02 SHR AX, 2 ; Get X1 Byte # (=X1/4) + 0450 C1 E9 02 SHR CX, 2 ; Get X2 Byte # (=X2/4) + + 0453 C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + 0457 03 FA ADD DI, DX ; Point to Start of Line + 0459 03 F8 ADD DI, AX ; Point to Pixel X1 + + 045B 2B C8 SUB CX, AX ; CX = # Of Bands (-1) to set + 045D 75 02 JNZ @DL_LONGLN ; jump if longer than one segment + + 045F 22 DF AND BL, BH ; otherwise, merge clip masks + + 0461 @DL_LONGLN: + + OUT_8 SC_Data, BL ; Set the Left Clip Mask + 0461 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0464 8A C3 1 MOV AL, BL ; then Get Data Value + 0466 EE 1 OUT DX, AL ; Set I/O Register + + 0467 8A 46 0A MOV AL, [BP].DL_ColorF ; Get Line Color + 046A 8A D8 MOV BL, AL ; BL = Copy of Line Color + 046C AA STOSB ; Set Left (1-4) Pixels + + 046D E3 55 JCXZ @DL_EXIT ; Done if only one Line Segment + + 046F 49 DEC CX ; CX = # of Middle Segments + 0470 74 07 JZ @DL_XRSEG ; If no middle segments.... + + ; Draw Middle Segments + + OUT_8 DX, ALL_PLANES ; Write to ALL Planes + 0472 B0 0F 1 MOV AL, ALL_PLANES ; then Get Data Value + 0474 EE 1 OUT DX, AL ; Set I/O Register + + 0475 8A C3 MOV AL, BL ; Get Color from BL + 0477 F3/ AA REP STOSB ; Draw Middle (4 Pixel) Segments + + 0479 @DL_XRSEG: + OUT_8 DX, BH ; Select Planes for Right Clip Mask + 0479 8A C7 1 MOV AL, BH ; then Get Data Value + 047B EE 1 OUT DX, AL ; Set I/O Register + 047C 8A C3 MOV AL, BL ; Get Color Value + 047E AA STOSB ; Draw Right (1-4) Pixels + + 047F EB 43 JMP s @DL_EXIT ; We Are Done... + + + ; This Code Draws A Vertical Line. On entry: + ; CH = Line Color, SI & DI = X1 + + 0481 @DL_VLINE: + + 0481 8B 46 10 MOV AX, [BP].DL_Ypos1 ; AX = Y1 + 0484 8B 76 0C MOV SI, [BP].DL_Ypos2 ; SI = Y2 + 0487 3B C6 CMP AX, SI ; Is Y1 < Y2? + 0489 7E 01 JLE @DL_NOSWAP2 ; if so, Don't Swap them + + 048B 96 XCHG AX, SI ; Ok, NOW Y1 < Y2 + + 048C @DL_NOSWAP2: + + 048C 2B F0 SUB SI, AX ; SI = Line Height (Y2-Y1+1) + 048E 46 INC SI + + ; AX = Y1, DI = X1, Get offset into Page into AX + + 048F F7 26 0000 R MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width + 0493 8B D7 MOV DX, DI ; Copy Xpos into DX + 0495 C1 EF 02 SHR DI, 2 ; DI = Xpos/4 + 0498 03 C7 ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1 + + 049A C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + 049E 03 F8 ADD DI, AX ; Point to Pixel X1, Y1 + + ;Select Plane + + 04A0 8A CA MOV CL, DL ; CL = Save X1 + 04A2 80 E1 03 AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #) + 04A5 B8 0102 MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1 + 04A8 D2 E4 SHL AH, CL ; Change to Correct Plane # + OUT_16 SC_Index, AX ; Select Plane + 04AA BA 03C4 1 MOV DX, SC_Index ; then Select Register + 04AD EF 1 OUT DX, AX ; Set I/O Register(s) + + 04AE 8A C5 MOV AL, CH ; Get Saved Color + 04B0 8B 1E 0000 R MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By + + 04B4 @DL_VLoop: + 04B4 26: 88 05 MOV ES:[DI], AL ; Draw Single Pixel + 04B7 03 FB ADD DI, BX ; Point to Next Line + LOOPjz SI, @DL_EXIT ; Lines--, Exit if done + 04B9 4E 1 DEC SI ; Counter-- + 04BA 74 08 1 JZ @DL_EXIT ; Jump if 0 + + 04BC 26: 88 05 MOV ES:[DI], AL ; Draw Single Pixel + 04BF 03 FB ADD DI, BX ; Point to Next Line + LOOPx SI, @DL_VLoop ; Lines--, Loop until Done + 04C1 4E 1 DEC SI ; Counter-- + 04C2 75 F0 1 JNZ @DL_VLoop ; Jump if not 0 + + 04C4 @DL_EXIT: + + 04C4 E9 0157 JMP @DL_EXIT2 ; Done! + + ; This code Draws a diagonal line in Mode X + + 04C7 @DL_BREZHAM: + 04C7 C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + 04CB 8B 46 10 MOV AX, [BP].DL_Ypos1 ; get Y1 value + 04CE 8B 5E 0C MOV BX, [BP].DL_Ypos2 ; get Y2 value + 04D1 8B 4E 12 MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos + + 04D4 3B D8 CMP BX, AX ; Y2-Y1 is? + 04D6 73 04 JNC @DL_DeltaYOK ; if Y2>=Y1 then goto... + + 04D8 93 XCHG BX, AX ; Swap em... + 04D9 8B 4E 0E MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos + + 04DC @DL_DeltaYOK: + 04DC F7 26 0000 R MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1 + + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 6 - 1 + + + 04E0 03 F8 ADD DI, AX ; DI -> Start of Line Y1 on Page + 04E2 8B C1 MOV AX, CX ; AX = Xpos (X1) + 04E4 C1 E8 02 SHR AX, 2 ; /4 = Byte Offset into Line + 04E7 03 F8 ADD DI, AX ; DI = Starting pos (X1,Y1) + + 04E9 B0 11 MOV AL, 11h ; Staring Mask + 04EB 80 E1 03 AND CL, PLANE_BITS ; Get Plane # + 04EE D2 E0 SHL AL, CL ; and shift into place + 04F0 8A 66 0A MOV AH, [BP].DL_ColorF ; Color in Hi Bytes + + 04F3 50 PUSH AX ; Save Mask,Color... + + 04F4 8A E0 MOV AH, AL ; Plane # in AH + 04F6 B0 02 MOV AL, MAP_MASK ; Select Plane Register + OUT_16 SC_Index, AX ; Select initial plane + 04F8 BA 03C4 1 MOV DX, SC_Index ; then Select Register + 04FB EF 1 OUT DX, AX ; Set I/O Register(s) + + 04FC 8B 46 12 MOV AX, [BP].DL_Xpos1 ; get X1 value + 04FF 8B 5E 10 MOV BX, [BP].DL_Ypos1 ; get Y1 value + 0502 8B 4E 0E MOV CX, [BP].DL_Xpos2 ; get X2 value + 0505 8B 56 0C MOV DX, [BP].DL_Ypos2 ; get Y2 value + + 0508 8B 2E 0000 R MOV BP, SCREEN_WIDTH ; Use BP for Line width to + ; to avoid extra memory access + + 050C 2B D3 SUB DX, BX ; figure Delta_Y + 050E 73 05 JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1 + + 0510 03 DA ADD BX, DX ; put Y2 into Y1 + 0512 F7 DA NEG DX ; abs(Delta_Y) + 0514 91 XCHG AX, CX ; and exchange X1 and X2 + + 0515 @DL_DeltaYOK2: + 0515 BB 8000 MOV BX, 08000H ; seed for fraction accumulator + + 0518 2B C8 SUB CX, AX ; figure Delta_X + 051A 72 03 JC @DL_DrawLeft ; if negative, go left + + 051C E9 0084 JMP @DL_DrawRight ; Draw Line that slopes right + + 051F @DL_DrawLeft: + + 051F F7 D9 NEG CX ; abs(Delta_X) + + 0521 3B CA CMP CX, DX ; is Delta_X < Delta_Y? + 0523 72 41 JB @DL_SteepLeft ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the left in Mode X + + 0525 @DL_ShallowLeft: + CLR AX ; zero low word of Delta_Y * 10000h + 0525 33 C0 1 XOR AX, AX ; Set Register = 0 + 0527 2B C2 SUB AX, DX ; DX:AX <- DX * 0FFFFh + 0529 83 DA 00 SBB DX, 0 ; include carry + 052C F7 F1 DIV CX ; divide by Delta_X + + 052E 8B F3 MOV SI, BX ; SI = Accumulator + 0530 8B D8 MOV BX, AX ; BX = Add fraction + 0532 58 POP AX ; Get Color, Bit mask + 0533 BA 03C5 MOV DX, SC_Data ; Sequence controller data register + 0536 41 INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down... + + 0537 @DL_SLLLoop: + 0537 26: 88 25 MOV ES:[DI], AH ; set first pixel, plane data set up + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + 053A 49 1 DEC CX ; Counter-- + 053B 74 26 1 JZ @DL_SLLExit ; Jump if 0 + + 053D 03 F3 ADD SI, BX ; add numerator to accumulator + 053F 73 02 JNC @DL_SLLL2nc ; move down on carry + + 0541 03 FD ADD DI, BP ; Move Down one line... + + 0543 @DL_SLLL2nc: + 0543 4F DEC DI ; Left one addr + 0544 D0 C8 ROR AL, 1 ; Move Left one plane, back on 0 1 2 + 0546 3C 87 CMP AL, 87h ; wrap?, if AL <88 then Carry set + 0548 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 054B EE OUT DX, AL ; Set up New Bit Plane mask + + 054C 26: 88 25 MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done + 054F 49 1 DEC CX ; Counter-- + 0550 74 11 1 JZ @DL_SLLExit ; Jump if 0 + + 0552 03 F3 ADD SI, BX ; add numerator to accumulator, + 0554 73 02 JNC @DL_SLLL3nc ; move down on carry + + 0556 03 FD ADD DI, BP ; Move Down one line... + + 0558 @DL_SLLL3nc: ; Now move left a pixel... + 0558 4F DEC DI ; Left one addr + 0559 D0 C8 ROR AL, 1 ; Move Left one plane, back on 0 1 2 + 055B 3C 87 CMP AL, 87h ; Wrap?, if AL <88 then Carry set + 055D 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 0560 EE OUT DX, AL ; Set up New Bit Plane mask + 0561 EB D4 JMP s @DL_SLLLoop ; loop until done + + 0563 @DL_SLLExit: + 0563 E9 00B8 JMP @DL_EXIT2 ; and exit + + ; Draw a steep line to the left in Mode X + + 0566 @DL_SteepLeft: + CLR AX ; zero low word of Delta_Y * 10000h + 0566 33 C0 1 XOR AX, AX ; Set Register = 0 + 0568 87 D1 XCHG DX, CX ; Delta_Y switched with Delta_X + 056A F7 F1 DIV CX ; divide by Delta_Y + + 056C 8B F3 MOV SI, BX ; SI = Accumulator + 056E 8B D8 MOV BX, AX ; BX = Add Fraction + 0570 58 POP AX ; Get Color, Bit mask + 0571 BA 03C5 MOV DX, SC_Data ; Sequence controller data register + 0574 41 INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe left + + 0575 @DL_STLLoop: + + 0575 26: 88 25 MOV ES:[DI], AH ; set first pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + 0578 49 1 DEC CX ; Counter-- + 0579 74 26 1 JZ @DL_STLExit ; Jump if 0 + + 057B 03 F3 ADD SI, BX ; add numerator to accumulator + 057D 73 09 JNC @DL_STLnc2 ; No carry, just move down! + + 057F 4F DEC DI ; Move Left one addr + 0580 D0 C8 ROR AL, 1 ; Move Left one plane, back on 0 1 2 + 0582 3C 87 CMP AL, 87h ; Wrap?, if AL <88 then Carry set + 0584 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 0587 EE OUT DX, AL ; Set up New Bit Plane mask + + 0588 @DL_STLnc2: + 0588 03 FD ADD DI, BP ; advance to next line. + + 058A 26: 88 25 MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done + 058D 49 1 DEC CX ; Counter-- + 058E 74 11 1 JZ @DL_STLExit ; Jump if 0 + + 0590 03 F3 ADD SI, BX ; add numerator to accumulator + 0592 73 09 JNC @DL_STLnc3 ; No carry, just move down! + + 0594 4F DEC DI ; Move Left one addr + 0595 D0 C8 ROR AL, 1 ; Move Left one plane, back on 0 1 2 + 0597 3C 87 CMP AL, 87h ; Wrap?, if AL <88 then Carry set + 0599 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 059C EE OUT DX, AL ; Set up New Bit Plane mask + + 059D @DL_STLnc3: + 059D 03 FD ADD DI, BP ; advance to next line. + 059F EB D4 JMP s @DL_STLLoop ; Loop until done + + 05A1 @DL_STLExit: + 05A1 EB 7B JMP @DL_EXIT2 ; and exit + + ; Draw a line that goes to the Right... + + 05A3 @DL_DrawRight: + 05A3 3B CA CMP CX, DX ; is Delta_X < Delta_Y? + 05A5 72 3E JB @DL_SteepRight ; yes, so go do steep line + ; (Delta_Y iterations) + + ; Draw a Shallow line to the Right in Mode X + + 05A7 @DL_ShallowRight: + CLR AX ; zero low word of Delta_Y * 10000h + 05A7 33 C0 1 XOR AX, AX ; Set Register = 0 + 05A9 2B C2 SUB AX, DX ; DX:AX <- DX * 0FFFFh + 05AB 83 DA 00 SBB DX, 0 ; include carry + 05AE F7 F1 DIV CX ; divide by Delta_X + + 05B0 8B F3 MOV SI, BX ; SI = Accumulator + 05B2 8B D8 MOV BX, AX ; BX = Add Fraction + 05B4 58 POP AX ; Get Color, Bit mask + 05B5 BA 03C5 MOV DX, SC_Data ; Sequence controller data register + 05B8 41 INC CX ; Inc Delta_X so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down... + + 05B9 @DL_SLRLoop: + 05B9 26: 88 25 MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + 05BC 49 1 DEC CX ; Counter-- + 05BD 74 24 1 JZ @DL_SLRExit ; Jump if 0 + + 05BF 03 F3 ADD SI, BX ; add numerator to accumulator + 05C1 73 02 JNC @DL_SLR2nc ; don't move down if carry not set + + 05C3 03 FD ADD DI, BP ; Move Down one line... + + 05C5 @DL_SLR2nc: ; Now move right a pixel... + 05C5 D0 C0 ROL AL, 1 ; Move Right one addr if Plane = 0 + 05C7 3C 12 CMP AL, 12h ; Wrap? if AL >12 then Carry not set + 05C9 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 05CC EE OUT DX, AL ; Set up New Bit Plane mask + + 05CD 26: 88 25 MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done.. + 05D0 49 1 DEC CX ; Counter-- + 05D1 74 10 1 JZ @DL_SLRExit ; Jump if 0 + + 05D3 03 F3 ADD SI, BX ; add numerator to accumulator + 05D5 73 02 JNC @DL_SLR3nc ; don't move down if carry not set + + 05D7 03 FD ADD DI, BP ; Move Down one line... + + 05D9 @DL_SLR3nc: + 05D9 D0 C0 ROL AL, 1 ; Move Right one addr if Plane = 0 + 05DB 3C 12 CMP AL, 12h ; Wrap? if AL >12 then Carry not set + 05DD 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 05E0 EE OUT DX, AL ; Set up New Bit Plane mask + 05E1 EB D6 JMP s @DL_SLRLoop ; loop till done + + 05E3 @DL_SLRExit: + 05E3 EB 39 JMP @DL_EXIT2 ; and exit + + ; Draw a Steep line to the Right in Mode X + + 05E5 @DL_SteepRight: + CLR AX ; zero low word of Delta_Y * 10000h + 05E5 33 C0 1 XOR AX, AX ; Set Register = 0 + 05E7 87 D1 XCHG DX, CX ; Delta_Y switched with Delta_X + 05E9 F7 F1 DIV CX ; divide by Delta_Y + + 05EB 8B F3 MOV SI, BX ; SI = Accumulator + 05ED 8B D8 MOV BX, AX ; BX = Add Fraction + 05EF 58 POP AX ; Get Color, Bit mask + 05F0 BA 03C5 MOV DX, SC_Data ; Sequence controller data register + 05F3 41 INC CX ; Inc Delta_Y so we can unroll loop + + ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right + + 05F4 @STRLoop: + 05F4 26: 88 25 MOV ES:[DI], AH ; set first pixel, mask is set up + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + 05F7 49 1 DEC CX ; Counter-- + 05F8 74 24 1 JZ @DL_EXIT2 ; Jump if 0 + + 05FA 03 F3 ADD SI, BX ; add numerator to accumulator + 05FC 73 08 JNC @STRnc2 ; if no carry then just go down... + + 05FE D0 C0 ROL AL, 1 ; Move Right one addr if Plane = 0 + 0600 3C 12 CMP AL, 12h ; Wrap? if AL >12 then Carry not set + 0602 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 0605 EE OUT DX, AL ; Set up New Bit Plane mask + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 7 - 1 + + + + 0606 @STRnc2: + 0606 03 FD ADD DI, BP ; advance to next line. + + 0608 26: 88 25 MOV ES:[DI], AH ; set pixel + LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done + 060B 49 1 DEC CX ; Counter-- + 060C 74 10 1 JZ @DL_EXIT2 ; Jump if 0 + + 060E 03 F3 ADD SI, BX ; add numerator to accumulator + 0610 73 08 JNC @STRnc3 ; if no carry then just go down... + + 0612 D0 C0 ROL AL, 1 ; Move Right one addr if Plane = 0 + 0614 3C 12 CMP AL, 12h ; Wrap? if AL >12 then Carry not set + 0616 83 D7 00 ADC DI, 0 ; Adjust Address: DI = DI + Carry + 0619 EE OUT DX, AL ; Set up New Bit Plane mask + + 061A @STRnc3: + 061A 03 FD ADD DI, BP ; advance to next line. + 061C EB D6 JMP s @STRLoop ; loop till done + + 061E @DL_EXIT2: + POPx DI, SI, BP ; Restore Saved Registers + 061E 5F 1 POP DI ; Restore R1 + 061F 5E 2 POP SI ; Restore R1 + 0620 5D 3 POP BP ; Restore R1 + 0621 CA 000A RET 10 ; Exit and Clean up Stack + + 0624 DRAW_LINE ENDP + + + ; ===== DAC COLOR REGISTER ROUTINES ===== + + ;================================================= + ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%) + ;================================================= + ; + ; Sets a single (RGB) Vga Palette Register + ; + ; ENTRY: Register = The DAC # to modify (0-255) + ; Red = The new Red Intensity (0-63) + ; Green = The new Green Intensity (0-63) + ; Blue = The new Blue Intensity (0-63) + ; + ; EXIT: No meaningful values returned + ; + + 000E SDR_STACK STRUC + 0000 0000 DW ? ; BP + 0002 00000000 DD ? ; Caller + 0006 00 00 SDR_Blue DB ?,? ; Blue Data Value + 0008 00 00 SDR_Green DB ?,? ; Green Data Value + 000A 00 00 SDR_Red DB ?,? ; Red Data Value + 000C 00 00 SDR_Register DB ?,? ; Palette Register # + SDR_STACK ENDS + + PUBLIC SET_DAC_REGISTER + + 0624 SET_DAC_REGISTER PROC FAR + + 0624 55 PUSH BP ; Save BP + 0625 8B EC MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to modify + + OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register + 0627 BA 03C8 1 MOV DX, DAC_WRITE_ADDR ; then Select Register + 062A 8A 46 0C 1 MOV AL, [BP].SDR_Register ; then Get Data Value + 062D EE 1 OUT DX, AL ; Set I/O Register + + 062E BA 03C9 MOV DX, PEL_DATA_REG ; Dac Data Register + OUT_8 DX, [BP].SDR_Red ; Set Red Intensity + 0631 8A 46 0A 1 MOV AL, [BP].SDR_Red ; then Get Data Value + 0634 EE 1 OUT DX, AL ; Set I/O Register + OUT_8 DX, [BP].SDR_Green ; Set Green Intensity + 0635 8A 46 08 1 MOV AL, [BP].SDR_Green ; then Get Data Value + 0638 EE 1 OUT DX, AL ; Set I/O Register + OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity + 0639 8A 46 06 1 MOV AL, [BP].SDR_Blue ; then Get Data Value + 063C EE 1 OUT DX, AL ; Set I/O Register + + 063D 5D POP BP ; Restore Registers + 063E CA 0008 RET 8 ; Exit & Clean Up Stack + + 0641 SET_DAC_REGISTER ENDP + + ;==================================================== + ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%) + ;==================================================== + ; + ; Reads the RGB Values of a single Vga Palette Register + ; + ; ENTRY: Register = The DAC # to read (0-255) + ; Red = Offset to Red Variable in DS + ; Green = Offset to Green Variable in DS + ; Blue = Offset to Blue Variable in DS + ; + ; EXIT: The values of the integer variables Red, + ; Green, and Blue are set to the values + ; taken from the specified DAC register. + ; + + 000E GDR_STACK STRUC + 0000 0000 DW ? ; BP + 0002 00000000 DD ? ; Caller + 0006 0000 GDR_Blue DW ? ; Addr of Blue Data Value in DS + 0008 0000 GDR_Green DW ? ; Addr of Green Data Value in DS + 000A 0000 GDR_Red DW ? ; Addr of Red Data Value in DS + 000C 00 00 GDR_Register DB ?,? ; Palette Register # + GDR_STACK ENDS + + PUBLIC GET_DAC_REGISTER + + 0641 GET_DAC_REGISTER PROC FAR + + 0641 55 PUSH BP ; Save BP + 0642 8B EC MOV BP, SP ; Set up Stack Frame + + ; Select which DAC Register to read in + + OUT_8 DAC_READ_ADDR, [BP].GDR_Register + 0644 BA 03C7 1 MOV DX, DAC_READ_ADDR ; then Select Register + 0647 8A 46 0C 1 MOV AL, [BP].GDR_Register ; then Get Data Value + 064A EE 1 OUT DX, AL ; Set I/O Register + + 064B BA 03C9 MOV DX, PEL_DATA_REG ; Dac Data Register + CLR AX ; Clear AX + 064E 33 C0 1 XOR AX, AX ; Set Register = 0 + + 0650 EC IN AL, DX ; Read Red Value + 0651 8B 5E 0A MOV BX, [BP].GDR_Red ; Get Address of Red% + 0654 89 07 MOV [BX], AX ; *Red% = AX + + 0656 EC IN AL, DX ; Read Green Value + 0657 8B 5E 08 MOV BX, [BP].GDR_Green ; Get Address of Green% + 065A 89 07 MOV [BX], AX ; *Green% = AX + + 065C EC IN AL, DX ; Read Blue Value + 065D 8B 5E 06 MOV BX, [BP].GDR_Blue ; Get Address of Blue% + 0660 89 07 MOV [BX], AX ; *Blue% = AX + + 0662 5D POP BP ; Restore Registers + 0663 CA 0008 RET 8 ; Exit & Clean Up Stack + + 0666 GET_DAC_REGISTER ENDP + + + ;=========================================================== + ;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%) + ;=========================================================== + ; + ; Sets a Block of Vga Palette Registers + ; + ; ENTRY: PalData = Far Pointer to Block of palette data + ; StartReg = First Register # in range to set (0-255) + ; EndReg = Last Register # in Range to set (0-255) + ; Sync = Wait for Vertical Retrace Flag (Boolean) + ; + ; EXIT: No meaningful values returned + ; + ; NOTES: PalData is a linear array of 3 byte Palette values + ; in the order: Red (0-63), Green (0-63), Blue (0-63) + ; + + 0014 LDR_STACK STRUC + 0000 0000 0000 0000 DW ?x3 ; BP, DS, SI + 0006 00000000 DD ? ; Caller + 000A 0000 LDR_Sync DW ? ; Vertical Sync Flag + 000C 00 00 LDR_EndReg DB ?,? ; Last Register # + 000E 00 00 LDR_StartReg DB ?,? ; First Register # + 0010 00000000 LDR_PalData DD ? ; Far Ptr to Palette Data + LDR_STACK ENDS + + PUBLIC LOAD_DAC_REGISTERS + + 0666 LOAD_DAC_REGISTERS PROC FAR + + PUSHx BP, DS, SI ; Save Registers + 0666 55 1 PUSH BP ; Save R1 + 0667 1E 2 PUSH DS ; Save R1 + 0668 56 3 PUSH SI ; Save R1 + 0669 8B EC mov BP, SP ; Set up Stack Frame + + 066B 8B 46 0A mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag + 066E 0B C0 or AX, AX ; is Sync Flag = 0? + 0670 74 05 jz @LDR_Load ; if so, skip call + + 0672 9A ---- 0795 R call f SYNC_DISPLAY ; wait for vsync + + ; Determine register #'s, size to copy, etc + + 0677 @LDR_Load: + + 0677 C5 76 10 lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data + 067A BA 03C8 mov DX, DAC_WRITE_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + 067D 33 C0 1 XOR AX, AX ; Set Register = 0 + 067F 33 DB 2 XOR BX, BX ; Set Register = 0 + 0681 8A 46 0E mov AL, [BP].LDR_StartReg ; Get Start Register + 0684 8A 5E 0C mov BL, [BP].LDR_EndReg ; Get End Register + + 0687 2B D8 sub BX, AX ; BX = # of DAC registers -1 + 0689 43 inc BX ; BX = # of DAC registers + 068A 8B CB mov CX, BX ; CX = # of DAC registers + 068C 03 CB add CX, BX ; CX = " " * 2 + 068E 03 CB add CX, BX ; CX = " " * 3 + 0690 FC cld ; Block OUTs forward + 0691 EE out DX, AL ; set up correct register # + + ; Load a block of DAC Registers + + 0692 BA 03C9 mov DX, PEL_DATA_REG ; Dac Data Register + + 0695 F3/ 6E rep outsb ; block set DAC registers + + POPx SI, DS, BP ; Restore Registers + 0697 5E 1 POP SI ; Restore R1 + 0698 1F 2 POP DS ; Restore R1 + 0699 5D 3 POP BP ; Restore R1 + 069A CA 000A ret 10 ; Exit & Clean Up Stack + + 069D LOAD_DAC_REGISTERS ENDP + + + ;==================================================== + ;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%) + ;==================================================== + ; + ; Reads a Block of Vga Palette Registers + ; + ; ENTRY: PalData = Far Pointer to block to store palette data + ; StartReg = First Register # in range to read (0-255) + ; EndReg = Last Register # in Range to read (0-255) + ; + ; EXIT: No meaningful values returned + ; + ; NOTES: PalData is a linear array of 3 byte Palette values + ; in the order: Red (0-63), Green (0-63), Blue (0-63) + ; + + 0012 RDR_STACK STRUC + 0000 0000 0000 0000 DW ?x3 ; BP, ES, DI + 0006 00000000 DD ? ; Caller + 000A 00 00 RDR_EndReg DB ?,? ; Last Register # + 000C 00 00 RDR_StartReg DB ?,? ; First Register # + 000E 00000000 RDR_PalData DD ? ; Far Ptr to Palette Data + RDR_STACK ENDS + + PUBLIC READ_DAC_REGISTERS + + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 8 - 1 + + + 069D READ_DAC_REGISTERS PROC FAR + + PUSHx BP, ES, DI ; Save Registers + 069D 55 1 PUSH BP ; Save R1 + 069E 06 2 PUSH ES ; Save R1 + 069F 57 3 PUSH DI ; Save R1 + 06A0 8B EC mov BP, SP ; Set up Stack Frame + + ; Determine register #'s, size to copy, etc + + 06A2 C4 7E 0E les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer + 06A5 BA 03C7 mov DX, DAC_READ_ADDR ; DAC register # selector + + CLR AX, BX ; Clear for byte loads + 06A8 33 C0 1 XOR AX, AX ; Set Register = 0 + 06AA 33 DB 2 XOR BX, BX ; Set Register = 0 + 06AC 8A 46 0C mov AL, [BP].RDR_StartReg ; Get Start Register + 06AF 8A 5E 0A mov BL, [BP].RDR_EndReg ; Get End Register + + 06B2 2B D8 sub BX, AX ; BX = # of DAC registers -1 + 06B4 43 inc BX ; BX = # of DAC registers + 06B5 8B CB mov CX, BX ; CX = # of DAC registers + 06B7 03 CB add CX, BX ; CX = " " * 2 + 06B9 03 CB add CX, BX ; CX = " " * 3 + 06BB FC cld ; Block INs forward + + ; Read a block of DAC Registers + + 06BC EE out DX, AL ; set up correct register # + 06BD BA 03C9 mov DX, PEL_DATA_REG ; Dac Data Register + + 06C0 F3/ 6C rep insb ; block read DAC registers + + POPx DI, ES, BP ; Restore Registers + + 06C2 5F 1 POP DI ; Restore R1 + 06C3 07 2 POP ES ; Restore R1 + 06C4 5D 3 POP BP ; Restore R1 + 06C5 CA 0008 ret 8 ; Exit & Clean Up Stack + + 06C8 READ_DAC_REGISTERS ENDP + + + ; ===== PAGE FLIPPING AND SCROLLING ROUTINES ===== + + ;========================= + ;SET_ACTIVE_PAGE (PageNo%) + ;========================= + ; + ; Sets the active display Page to be used for future drawing + ; + ; ENTRY: PageNo = Display Page to make active + ; (values: 0 to Number of Pages - 1) + ; + ; EXIT: No meaningful values returned + ; + + 0008 SAP_STACK STRUC + 0000 0000 DW ? ; BP + 0002 00000000 DD ? ; Caller + 0006 0000 SAP_Page DW ? ; Page # for Drawing + SAP_STACK ENDS + + PUBLIC SET_ACTIVE_PAGE + + 06C8 SET_ACTIVE_PAGE PROC FAR + + 06C8 55 PUSH BP ; Preserve Registers + 06C9 8B EC MOV BP, SP ; Set up Stack Frame + + 06CB 8B 5E 06 MOV BX, [BP].SAP_Page ; Get Desired Page # + 06CE 3B 1E 0004 R CMP BX, LAST_PAGE ; Is Page # Valid? + 06D2 73 0D JAE @SAP_Exit ; IF Not, Do Nothing + + 06D4 89 1E 0012 R MOV ACTIVE_PAGE, BX ; Set Active Page # + + 06D8 D1 E3 SHL BX, 1 ; Scale Page # to Word + 06DA 8B 87 0006 R MOV AX, PAGE_ADDR[BX] ; Get offset to Page + + 06DE A3 0014 R MOV CURRENT_PAGE, AX ; And set for future LES's + + 06E1 @SAP_Exit: + 06E1 5D POP BP ; Restore Registers + 06E2 CA 0002 RET 2 ; Exit and Clean up Stack + + 06E5 SET_ACTIVE_PAGE ENDP + + + ;================ + ;GET_ACTIVE_PAGE% + ;================ + ; + ; Returns the Video Page # currently used for Drawing + ; + ; ENTRY: No Parameters are passed + ; + ; EXIT: AX = Current Video Page used for Drawing + ; + + PUBLIC GET_ACTIVE_PAGE + + 06E5 GET_ACTIVE_PAGE PROC FAR + + 06E5 A1 0012 R MOV AX, ACTIVE_PAGE ; Get Active Page # + 06E8 CB RET ; Exit and Clean up Stack + + 06E9 GET_ACTIVE_PAGE ENDP + + + ;=============================== + ;SET_DISPLAY_PAGE (DisplayPage%) + ;=============================== + ; + ; Sets the currently visible display page. + ; When called this routine syncronizes the display + ; to the vertical blank. + ; + ; ENTRY: PageNo = Display Page to show on the screen + ; (values: 0 to Number of Pages - 1) + ; + ; EXIT: No meaningful values returned + ; + + 0008 SDP_STACK STRUC + 0000 0000 DW ? ; BP + 0002 00000000 DD ? ; Caller + 0006 0000 SDP_Page DW ? ; Page # to Display... + SDP_STACK ENDS + + PUBLIC SET_DISPLAY_PAGE + + 06E9 SET_DISPLAY_PAGE PROC FAR + + 06E9 55 PUSH BP ; Preserve Registers + 06EA 8B EC MOV BP, SP ; Set up Stack Frame + + 06EC 8B 5E 06 MOV BX, [BP].SDP_Page ; Get Desired Page # + 06EF 3B 1E 0004 R CMP BX, LAST_PAGE ; Is Page # Valid? + 06F3 73 2B JAE @SDP_Exit ; IF Not, Do Nothing + + 06F5 89 1E 0010 R MOV DISPLAY_PAGE, BX ; Set Display Page # + + 06F9 D1 E3 SHL BX, 1 ; Scale Page # to Word + 06FB 8B 8F 0006 R MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page + 06FF 03 0E 001C R ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling + + ; Wait if we are currently in a Vertical Retrace + + 0703 BA 03DA MOV DX, INPUT_1 ; Input Status #1 Register + + 0706 @DP_WAIT0: + 0706 EC IN AL, DX ; Get VGA status + 0707 24 08 AND AL, VERT_RETRACE ; In Display mode yet? + 0709 75 FB JNZ @DP_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new page + + 070B BA 03D4 MOV DX, CRTC_Index ; We Change the VGA Sequencer + + 070E B0 0D MOV AL, START_DISP_LO ; Display Start Low Register + 0710 8A E1 MOV AH, CL ; Low 8 Bits of Start Addr + 0712 EF OUT DX, AX ; Set Display Addr Low + + 0713 B0 0C MOV AL, START_DISP_HI ; Display Start High Register + 0715 8A E5 MOV AH, CH ; High 8 Bits of Start Addr + 0717 EF OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + 0718 BA 03DA MOV DX, INPUT_1 ; Input Status #1 Register + + 071B @DP_WAIT1: + 071B EC IN AL, DX ; Get VGA status + 071C 24 08 AND AL, VERT_RETRACE ; Vertical Retrace Start? + 071E 74 FB JZ @DP_WAIT1 ; If Not, wait for it + + ; Now Set Display Starting Address + + + 0720 @SDP_Exit: + 0720 5D POP BP ; Restore Registers + 0721 CA 0002 RET 2 ; Exit and Clean up Stack + + 0724 SET_DISPLAY_PAGE ENDP + + + ;================= + ;GET_DISPLAY_PAGE% + ;================= + ; + ; Returns the Video Page # currently displayed + ; + ; ENTRY: No Parameters are passed + ; + ; EXIT: AX = Current Video Page being displayed + ; + + PUBLIC GET_DISPLAY_PAGE + + 0724 GET_DISPLAY_PAGE PROC FAR + + 0724 A1 0010 R MOV AX, DISPLAY_PAGE ; Get Display Page # + 0727 CB RET ; Exit & Clean Up Stack + + 0728 GET_DISPLAY_PAGE ENDP + + + ;======================================= + ;SET_WINDOW (DisplayPage%, Xpos%, Ypos%) + ;======================================= + ; + ; Since a Logical Screen can be larger than the Physical + ; Screen, Scrolling is possible. This routine sets the + ; Upper Left Corner of the Screen to the specified Pixel. + ; Also Sets the Display page to simplify combined page + ; flipping and scrolling. When called this routine + ; syncronizes the display to the vertical blank. + ; + ; ENTRY: DisplayPage = Display Page to show on the screen + ; Xpos = # of pixels to shift screen right + ; Ypos = # of lines to shift screen down + ; + ; EXIT: No meaningful values returned + ; + + 000C SW_STACK STRUC + 0000 0000 DW ? ; BP + 0002 00000000 DD ? ; Caller + 0006 0000 SW_Ypos DW ? ; Y pos of UL Screen Corner + 0008 0000 SW_Xpos DW ? ; X pos of UL Screen Corner + 000A 0000 SW_Page DW ? ; (new) Display Page + SW_STACK ENDS + + PUBLIC SET_WINDOW + + 0728 SET_WINDOW PROC FAR + + 0728 55 PUSH BP ; Preserve Registers + 0729 8B EC MOV BP, SP ; Set up Stack Frame + + ; Check if our Scroll Offsets are Valid + + 072B 8B 5E 0A MOV BX, [BP].SW_Page ; Get Desired Page # + 072E 3B 1E 0004 R CMP BX, LAST_PAGE ; Is Page # Valid? + 0732 73 55 JAE @SW_Exit ; IF Not, Do Nothing + + 0734 8B 46 06 MOV AX, [BP].SW_Ypos ; Get Desired Y Offset + 0737 3B 06 0020 R CMP AX, MAX_YOFFSET ; Is it Within Limits? + 073B 77 4C JA @SW_Exit ; if not, exit + + 073D 8B 4E 08 MOV CX, [BP].SW_Xpos ; Get Desired X Offset + 0740 3B 0E 001E R CMP CX, MAX_XOFFSET ; Is it Within Limits? + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 9 - 1 + + + 0744 77 43 JA @SW_Exit ; if not, exit + + ; Compute proper Display start address to use + + 0746 F7 26 0000 R MUL SCREEN_WIDTH ; AX = YOffset * Line Width + 074A C1 E9 02 SHR CX, 2 ; CX / 4 = Bytes into Line + 074D 03 C1 ADD AX, CX ; AX = Offset of Upper Left Pixel + + 074F A3 001C R MOV CURRENT_MOFFSET, AX ; Save Offset Info + + 0752 89 1E 0010 R MOV DISPLAY_PAGE, BX ; Set Current Page # + 0756 D1 E3 SHL BX, 1 ; Scale Page # to Word + 0758 03 87 0006 R ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page + 075C 8B D8 MOV BX, AX ; BX = Desired Display Start + + 075E BA 03DA MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait if we are currently in a Vertical Retrace + + 0761 @SW_WAIT0: + 0761 EC IN AL, DX ; Get VGA status + 0762 24 08 AND AL, VERT_RETRACE ; In Display mode yet? + 0764 75 FB JNZ @SW_WAIT0 ; If Not, wait for it + + ; Set the Start Display Address to the new window + + 0766 BA 03D4 MOV DX, CRTC_Index ; We Change the VGA Sequencer + 0769 B0 0D MOV AL, START_DISP_LO ; Display Start Low Register + 076B 8A E3 MOV AH, BL ; Low 8 Bits of Start Addr + 076D EF OUT DX, AX ; Set Display Addr Low + + 076E B0 0C MOV AL, START_DISP_HI ; Display Start High Register + 0770 8A E7 MOV AH, BH ; High 8 Bits of Start Addr + 0772 EF OUT DX, AX ; Set Display Addr High + + ; Wait for a Vertical Retrace to smooth out things + + 0773 BA 03DA MOV DX, INPUT_1 ; Input Status #1 Register + + 0776 @SW_WAIT1: + 0776 EC IN AL, DX ; Get VGA status + 0777 24 08 AND AL, VERT_RETRACE ; Vertical Retrace Start? + 0779 74 FB JZ @SW_WAIT1 ; If Not, wait for it + + ; Now Set the Horizontal Pixel Pan values + + OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register + 077B BA 03C0 1 MOV DX, ATTRIB_Ctrl ; then Select Register + 077E B0 33 1 MOV AL, PIXEL_PAN_REG ; then Get Data Value + 0780 EE 1 OUT DX, AL ; Set I/O Register + + 0781 8B 46 08 MOV AX, [BP].SW_Xpos ; Get Desired X Offset + 0784 24 03 AND AL, 03 ; Get # of Pixels to Pan (0-3) + 0786 D0 E0 SHL AL, 1 ; Shift for 256 Color Mode + 0788 EE OUT DX, AL ; Fine tune the display! + + 0789 @SW_Exit: + 0789 5D POP BP ; Restore Saved Registers + 078A CA 0006 RET 6 ; Exit and Clean up Stack + + 078D SET_WINDOW ENDP + + + ;============= + ;GET_X_OFFSET% + ;============= + ; + ; Returns the X coordinate of the Pixel currently display + ; in the upper left corner of the display + ; + ; ENTRY: No Parameters are passed + ; + ; EXIT: AX = Current Horizontal Scroll Offset + ; + + PUBLIC GET_X_OFFSET + + 078D GET_X_OFFSET PROC FAR + + 078D A1 0018 R MOV AX, CURRENT_XOFFSET ; Get current horz offset + 0790 CB RET ; Exit & Clean Up Stack + + 0791 GET_X_OFFSET ENDP + + + ;============= + ;GET_Y_OFFSET% + ;============= + ; + ; Returns the Y coordinate of the Pixel currently display + ; in the upper left corner of the display + ; + ; ENTRY: No Parameters are passed + ; + ; EXIT: AX = Current Vertical Scroll Offset + ; + + PUBLIC GET_Y_OFFSET + + 0791 GET_Y_OFFSET PROC FAR + + 0791 A1 001A R MOV AX, CURRENT_YOFFSET ; Get current vertical offset + 0794 CB RET ; Exit & Clean Up Stack + + 0795 GET_Y_OFFSET ENDP + + + ;============ + ;SYNC_DISPLAY + ;============ + ; + ; Pauses the computer until the next Vertical Retrace starts + ; + ; ENTRY: No Parameters are passed + ; + ; EXIT: No meaningful values returned + ; + + PUBLIC SYNC_DISPLAY + + 0795 SYNC_DISPLAY PROC FAR + + 0795 BA 03DA MOV DX, INPUT_1 ; Input Status #1 Register + + ; Wait for any current retrace to end + + 0798 @SD_WAIT0: + 0798 EC IN AL, DX ; Get VGA status + 0799 24 08 AND AL, VERT_RETRACE ; In Display mode yet? + 079B 75 FB JNZ @SD_WAIT0 ; If Not, wait for it + + ; Wait for the start of the next vertical retrace + + 079D @SD_WAIT1: + 079D EC IN AL, DX ; Get VGA status + 079E 24 08 AND AL, VERT_RETRACE ; Vertical Retrace Start? + 07A0 74 FB JZ @SD_WAIT1 ; If Not, wait for it + + 07A2 CB RET ; Exit & Clean Up Stack + + 07A3 SYNC_DISPLAY ENDP + + + ; ===== TEXT DISPLAY ROUTINES ===== + + ;================================================== + ;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%) + ;================================================== + ; + ; Draws an ASCII Text Character using the currently selected + ; 8x8 font on the active display page. It would be a simple + ; exercise to make this routine process variable height fonts. + ; + ; ENTRY: CharNum = ASCII character # to draw + ; Xpos = X position to draw Character at + ; Ypos = Y position of to draw Character at + ; ColorF = Color to draw text character in + ; ColorB = Color to set background to + ; + ; EXIT: No meaningful values returned + ; + + 001E GPC_STACK STRUC + 0000 0000 GPC_Width DW ? ; Screen Width-1 + 0002 00 00 GPC_Lines DB ?,? ; Scan lines to Decode + 0004 0000 GPC_T_SETS DW ? ; Saved Charset Segment + 0006 0000 GPC_T_SETO DW ? ; Saved Charset Offset + 0008 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 0010 00000000 DD ? ; Caller + 0014 00 00 GPC_ColorB DB ?,? ; Background Color + 0016 00 00 GPC_ColorF DB ?,? ; Text Color + 0018 0000 GPC_Ypos DW ? ; Y Position to Print at + 001A 0000 GPC_Xpos DW ? ; X position to Print at + 001C 00 00 GPC_Char DB ?,? ; Character to Print + GPC_STACK ENDS + + PUBLIC GPRINTC + + 07A3 GPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 07A3 55 1 PUSH BP ; Save R1 + 07A4 1E 2 PUSH DS ; Save R1 + 07A5 56 3 PUSH SI ; Save R1 + 07A6 57 4 PUSH DI ; Save R1 + 07A7 83 EC 08 SUB SP, 8 ; Allocate WorkSpace on Stack + 07AA 8B EC MOV BP, SP ; Set up Stack Frame + + 07AC C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + 07B0 A1 0000 R MOV AX, SCREEN_WIDTH ; Get Logical Line Width + 07B3 8B D8 MOV BX, AX ; BX = Screen Width + 07B5 4B DEC BX ; = Screen Width-1 + 07B6 89 5E 00 MOV [BP].GPC_Width, BX ; Save for later use + + 07B9 F7 66 18 MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width + 07BC 03 F8 ADD DI, AX ; DI -> Start of Line Ypos + + 07BE 8B 46 1A MOV AX, [BP].GPC_Xpos ; Get Xpos of Character + 07C1 8B C8 MOV CX, AX ; Save Copy of Xpos + 07C3 C1 E8 02 SHR AX, 2 ; Bytes into Line = Xpos/4 + 07C6 03 F8 ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + 07C8 8A 46 1C MOV AL, [BP].GPC_Char ; Get Character # + 07CB A8 80 TEST AL, 080h ; Is Hi Bit Set? + 07CD 74 0C JZ @GPC_LowChar ; Nope, use low char set ptr + + 07CF 24 7F AND AL, 07Fh ; Mask Out Hi Bit + 07D1 8B 1E 0026 R MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + 07D5 8B 16 0028 R MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + 07D9 EB 08 JMP s @GPC_Set_Char ; Go Setup Character Ptr + + 07DB @GPC_LowChar: + + 07DB 8B 1E 0022 R MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + 07DF 8B 16 0024 R MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + + 07E3 @GPC_Set_Char: + 07E3 89 56 04 MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack + + 07E6 B4 00 MOV AH, 0 ; Valid #'s are 0..127 + 07E8 C1 E0 03 SHL AX, 3 ; * 8 Bytes Per Bitmap + 07EB 03 D8 ADD BX, AX ; BX = Offset of Selected char + 07ED 89 5E 06 MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack + + 07F0 83 E1 03 AND CX, PLANE_BITS ; Get Plane # + 07F3 B5 0F MOV CH, ALL_PLANES ; Get Initial Plane mask + 07F5 D2 E5 SHL CH, CL ; And shift into position + 07F7 80 E5 0F AND CH, ALL_PLANES ; And mask to lower nibble + + 07FA B0 04 MOV AL, 04 ; 4-Plane # = # of initial + 07FC 2A C1 SUB AL, CL ; shifts to align bit mask + 07FE 8A C8 MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + 0800 BA 03C4 1 MOV DX, SC_Index ; then Select Register + 0803 B0 02 1 MOV AL, MAP_MASK ; then Get Data Value + 0805 EE 1 OUT DX, AL ; Set I/O Register + 0806 42 INC DX ; DX -> SC_Data + + 0807 B0 08 MOV AL, 08 ; 8 Lines to Process + 0809 88 46 02 MOV [BP].GPC_Lines, AL ; Save on Stack + + 080C 8E 5E 04 MOV DS, [BP].GPC_T_SETS ; Point to character set + + 080F @GPC_DECODE_CHAR_BYTE: + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 10 - 1 + + + + 080F 8B 76 06 MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String + + 0812 8A 3C MOV BH, [SI] ; Get Bit Map + 0814 46 INC SI ; Point to Next Line + 0815 89 76 06 MOV [BP].GPC_T_SETO, SI ; And save new Pointer... + + CLR AX ; Clear AX + 0818 33 C0 1 XOR AX, AX ; Set Register = 0 + + CLR BL ; Clear BL + 081A 32 DB 1 XOR BL, BL ; Set Register = 0 + 081C D3 C3 ROL BX, CL ; BL holds left edge bits + 081E 8B F3 MOV SI, BX ; Use as Table Index + 0820 83 E6 0F AND SI, CHAR_BITS ; Get Low Bits + 0823 2E: 8A 84 0008 R MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + 0828 74 07 JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set + + 082A 8A 66 16 MOV AH, [BP].GPC_ColorF ; Get Foreground Color + 082D EE OUT DX, AL ; Set up Screen Mask + 082E 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + 0831 @GPC_NO_LEFT1BITS: + 0831 32 C5 XOR AL, CH ; Invert mask for Background + 0833 74 07 JZ @GPC_NO_LEFT0BITS ; Hey, no need for this + + 0835 8A 66 14 MOV AH, [BP].GPC_ColorB ; Get background Color + 0838 EE OUT DX, AL ; Set up Screen Mask + 0839 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + + 083C @GPC_NO_LEFT0BITS: + 083C 47 INC DI ; Point to next Byte + 083D C1 C3 04 ROL BX, 4 ; Shift 4 bits + + 0840 8B F3 MOV SI, BX ; Make Lookup Pointer + 0842 83 E6 0F AND SI, CHAR_BITS ; Get Low Bits + 0845 2E: 8A 84 0008 R MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + 084A 74 07 JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set + + 084C 8A 66 16 MOV AH, [BP].GPC_ColorF ; Get Foreground Color + 084F EE OUT DX, AL ; Set up Screen Mask + 0850 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + 0853 @GPC_NO_MIDDLE1BITS: + 0853 34 0F XOR AL, ALL_PLANES ; Invert mask for Background + 0855 74 07 JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this + + 0857 8A 66 14 MOV AH, [BP].GPC_ColorB ; Get background Color + 085A EE OUT DX, AL ; Set up Screen Mask + 085B 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + 085E @GPC_NO_MIDDLE0BITS: + 085E 80 F5 0F XOR CH, ALL_PLANES ; Invert Clip Mask + 0861 80 F9 04 CMP CL, 4 ; Aligned by 4? + 0864 74 23 JZ @GPC_NEXT_LINE ; If so, Exit now.. + + 0866 47 INC DI ; Point to next Byte + 0867 C1 C3 04 ROL BX, 4 ; Shift 4 bits + + 086A 8B F3 MOV SI, BX ; Make Lookup Pointer + 086C 83 E6 0F AND SI, CHAR_BITS ; Get Low Bits + 086F 2E: 8A 84 0008 R MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + 0874 74 07 JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set + + 0876 8A 66 16 MOV AH, [BP].GPC_ColorF ; Get Foreground Color + 0879 EE OUT DX, AL ; Set up Screen Mask + 087A 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + 087D @GPC_NO_RIGHT1BITS: + + 087D 32 C5 XOR AL, CH ; Invert mask for Background + 087F 74 07 JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this + + 0881 8A 66 14 MOV AH, [BP].GPC_ColorB ; Get background Color + 0884 EE OUT DX, AL ; Set up Screen Mask + 0885 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + 0888 @GPC_NO_RIGHT0BITS: + 0888 4F DEC DI ; Adjust for Next Line Advance + + 0889 @GPC_NEXT_LINE: + 0889 03 7E 00 ADD DI, [BP].GPC_Width ; Point to Next Line + 088C 80 F5 0F XOR CH, CHAR_BITS ; Flip the Clip mask back + + 088F FE 4E 02 DEC [BP].GPC_Lines ; Count Down Lines + 0892 74 03 JZ @GPC_EXIT ; Ok... Done! + + 0894 E9 FF78 JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey! + + 0897 @GPC_EXIT: + 0897 83 C4 08 ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + 089A 5F 1 POP DI ; Restore R1 + 089B 5E 2 POP SI ; Restore R1 + 089C 1F 3 POP DS ; Restore R1 + 089D 5D 4 POP BP ; Restore R1 + 089E CA 000A RET 10 ; Exit and Clean up Stack + + 08A1 GPRINTC ENDP + + + ;========================================== + ;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%) + ;========================================== + ; + ; Transparently draws an ASCII Text Character using the + ; currently selected 8x8 font on the active display page. + ; + ; ENTRY: CharNum = ASCII character # to draw + ; Xpos = X position to draw Character at + ; Ypos = Y position of to draw Character at + ; ColorF = Color to draw text character in + ; + ; EXIT: No meaningful values returned + ; + + 001C TGP_STACK STRUC + 0000 0000 TGP_Width DW ? ; Screen Width-1 + 0002 00 00 TGP_Lines DB ?,? ; Scan lines to Decode + 0004 0000 TGP_T_SETS DW ? ; Saved Charset Segment + 0006 0000 TGP_T_SETO DW ? ; Saved Charset Offset + 0008 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 0010 00000000 DD ? ; Caller + 0014 00 00 TGP_ColorF DB ?,? ; Text Color + 0016 0000 TGP_Ypos DW ? ; Y Position to Print at + 0018 0000 TGP_Xpos DW ? ; X position to Print at + 001A 00 00 TGP_Char DB ?,? ; Character to Print + TGP_STACK ENDS + + PUBLIC TGPRINTC + + 08A1 TGPRINTC PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 08A1 55 1 PUSH BP ; Save R1 + 08A2 1E 2 PUSH DS ; Save R1 + 08A3 56 3 PUSH SI ; Save R1 + 08A4 57 4 PUSH DI ; Save R1 + 08A5 83 EC 08 SUB SP, 8 ; Allocate WorkSpace on Stack + 08A8 8B EC MOV BP, SP ; Set up Stack Frame + + 08AA C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + + 08AE A1 0000 R MOV AX, SCREEN_WIDTH ; Get Logical Line Width + 08B1 8B D8 MOV BX, AX ; BX = Screen Width + 08B3 4B DEC BX ; = Screen Width-1 + 08B4 89 5E 00 MOV [BP].TGP_Width, BX ; Save for later use + + 08B7 F7 66 16 MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width + 08BA 03 F8 ADD DI, AX ; DI -> Start of Line Ypos + + 08BC 8B 46 18 MOV AX, [BP].TGP_Xpos ; Get Xpos of Character + 08BF 8B C8 MOV CX, AX ; Save Copy of Xpos + 08C1 C1 E8 02 SHR AX, 2 ; Bytes into Line = Xpos/4 + 08C4 03 F8 ADD DI, AX ; DI -> (Xpos, Ypos) + + ;Get Source ADDR of Character Bit Map & Save + + 08C6 8A 46 1A MOV AL, [BP].TGP_Char ; Get Character # + 08C9 A8 80 TEST AL, 080h ; Is Hi Bit Set? + 08CB 74 0C JZ @TGP_LowChar ; Nope, use low char set ptr + + 08CD 24 7F AND AL, 07Fh ; Mask Out Hi Bit + 08CF 8B 1E 0026 R MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset + 08D3 8B 16 0028 R MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment + 08D7 EB 08 JMP s @TGP_Set_Char ; Go Setup Character Ptr + + 08D9 @TGP_LowChar: + + 08D9 8B 1E 0022 R MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset + 08DD 8B 16 0024 R MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment + + 08E1 @TGP_Set_Char: + 08E1 89 56 04 MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack + + 08E4 B4 00 MOV AH, 0 ; Valid #'s are 0..127 + 08E6 C1 E0 03 SHL AX, 3 ; * 8 Bytes Per Bitmap + 08E9 03 D8 ADD BX, AX ; BX = Offset of Selected char + 08EB 89 5E 06 MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack + + 08EE 83 E1 03 AND CX, PLANE_BITS ; Get Plane # + 08F1 B5 0F MOV CH, ALL_PLANES ; Get Initial Plane mask + 08F3 D2 E5 SHL CH, CL ; And shift into position + 08F5 80 E5 0F AND CH, ALL_PLANES ; And mask to lower nibble + + 08F8 B0 04 MOV AL, 04 ; 4-Plane # = # of initial + 08FA 2A C1 SUB AL, CL ; shifts to align bit mask + 08FC 8A C8 MOV CL, AL ; Shift Count for SHL + + ;Get segment of character map + + OUT_8 SC_Index, MAP_MASK ; Setup Plane selections + 08FE BA 03C4 1 MOV DX, SC_Index ; then Select Register + 0901 B0 02 1 MOV AL, MAP_MASK ; then Get Data Value + 0903 EE 1 OUT DX, AL ; Set I/O Register + 0904 42 INC DX ; DX -> SC_Data + + 0905 B0 08 MOV AL, 08 ; 8 Lines to Process + 0907 88 46 02 MOV [BP].TGP_Lines, AL ; Save on Stack + + 090A 8E 5E 04 MOV DS, [BP].TGP_T_SETS ; Point to character set + + 090D @TGP_DECODE_CHAR_BYTE: + + 090D 8B 76 06 MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String + + 0910 8A 3C MOV BH, [SI] ; Get Bit Map + 0912 46 INC SI ; Point to Next Line + 0913 89 76 06 MOV [BP].TGP_T_SETO, SI ; And save new Pointer... + + 0916 8A 66 14 MOV AH, [BP].TGP_ColorF ; Get Foreground Color + + CLR BL ; Clear BL + 0919 32 DB 1 XOR BL, BL ; Set Register = 0 + 091B D3 C3 ROL BX, CL ; BL holds left edge bits + 091D 8B F3 MOV SI, BX ; Use as Table Index + 091F 83 E6 0F AND SI, CHAR_BITS ; Get Low Bits + 0922 2E: 8A 84 0008 R MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + 0927 74 04 JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set + + 0929 EE OUT DX, AL ; Set up Screen Mask + 092A 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + ;Now Do Middle/Last Band + + 092D @TGP_NO_LEFT1BITS: + + 092D 47 INC DI ; Point to next Byte + 092E C1 C3 04 ROL BX, 4 ; Shift 4 bits + + 0931 8B F3 MOV SI, BX ; Make Lookup Pointer + 0933 83 E6 0F AND SI, CHAR_BITS ; Get Low Bits + 0936 2E: 8A 84 0008 R MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + 093B 74 04 JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set + + 093D EE OUT DX, AL ; Set up Screen Mask + 093E 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + 0941 @TGP_NO_MIDDLE1BITS: + 0941 80 F5 0F XOR CH, ALL_PLANES ; Invert Clip Mask + 0944 80 F9 04 CMP CL, 4 ; Aligned by 4? + 0947 74 15 JZ @TGP_NEXT_LINE ; If so, Exit now.. + + 0949 47 INC DI ; Point to next Byte + 094A C1 C3 04 ROL BX, 4 ; Shift 4 bits + + 094D 8B F3 MOV SI, BX ; Make Lookup Pointer + 094F 83 E6 0F AND SI, CHAR_BITS ; Get Low Bits + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 11 - 1 + + + 0952 2E: 8A 84 0008 R MOV AL, Char_Plane_Data[SI] ; Get Mask in AL + 0957 74 04 JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set + + 0959 EE OUT DX, AL ; Set up Screen Mask + 095A 26: 88 25 MOV ES:[DI], AH ; Write Foreground color + + 095D @TGP_NO_RIGHT1BITS: + + 095D 4F DEC DI ; Adjust for Next Line Advance + + 095E @TGP_NEXT_LINE: + 095E 03 7E 00 ADD DI, [BP].TGP_Width ; Point to Next Line + 0961 80 F5 0F XOR CH, CHAR_BITS ; Flip the Clip mask back + + 0964 FE 4E 02 DEC [BP].TGP_Lines ; Count Down Lines + 0967 74 02 JZ @TGP_EXIT ; Ok... Done! + + 0969 EB A2 JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey! + + 096B @TGP_EXIT: + 096B 83 C4 08 ADD SP, 08 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + 096E 5F 1 POP DI ; Restore R1 + 096F 5E 2 POP SI ; Restore R1 + 0970 1F 3 POP DS ; Restore R1 + 0971 5D 4 POP BP ; Restore R1 + 0972 CA 0008 RET 8 ; Exit and Clean up Stack + + 0975 TGPRINTC ENDP + + + ;=============================================================== + ;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) + ;=============================================================== + ; + ; Routine to quickly Print a null terminated ASCII string on the + ; active display page up to a maximum length. + ; + ; ENTRY: String = Far Pointer to ASCII string to print + ; MaxLen = # of characters to print if no null found + ; Xpos = X position to draw Text at + ; Ypos = Y position of to draw Text at + ; ColorF = Color to draw text in + ; ColorB = Color to set background to + ; + ; EXIT: No meaningful values returned + ; + + 001A PS_STACK STRUC + 0000 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 0008 00000000 DD ? ; Caller + 000C 0000 PS_ColorB DW ? ; Background Color + 000E 0000 PS_ColorF DW ? ; Text Color + 0010 0000 PS_Ypos DW ? ; Y Position to Print at + 0012 0000 PS_Xpos DW ? ; X position to Print at + 0014 0000 PS_Len DW ? ; Maximum Length of string to print + 0016 0000 0000 PS_Text DW ?,? ; Far Ptr to Text String + PS_STACK ENDS + + PUBLIC PRINT_STR + + 0975 PRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 0975 55 1 PUSH BP ; Save R1 + 0976 1E 2 PUSH DS ; Save R1 + 0977 56 3 PUSH SI ; Save R1 + 0978 57 4 PUSH DI ; Save R1 + 0979 8B EC MOV BP, SP ; Set up Stack Frame + + 097B @PS_Print_It: + + 097B 8B 4E 14 MOV CX, [BP].PS_Len ; Get Remaining text Length + 097E E3 2F JCXZ @PS_Exit ; Exit when out of text + + 0980 C4 7E 16 LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text + 0983 26: 8A 05 MOV AL, ES:[DI] ; AL = Text Character + 0986 25 00FF AND AX, 00FFh ; Clear High Word + 0989 74 24 JZ @PS_Exit ; Exit if null character + + 098B FF 4E 14 DEC [BP].PS_Len ; Remaining Text length-- + 098E FF 46 16 INC [BP].PS_Text ; Point to Next text char + + ; Set up Call to GPRINTC + + 0991 50 PUSH AX ; Set Character Parameter + 0992 8B 5E 12 MOV BX, [BP].PS_Xpos ; Get Xpos + 0995 53 PUSH BX ; Set Xpos Parameter + 0996 83 C3 08 ADD BX, 8 ; Advance 1 Char to Right + 0999 89 5E 12 MOV [BP].PS_Xpos, BX ; Save for next time through + + 099C 8B 5E 10 MOV BX, [BP].PS_Ypos ; Get Ypos + 099F 53 PUSH BX ; Set Ypos Parameter + + 09A0 8B 5E 0E MOV BX, [BP].PS_ColorF ; Get Text Color + 09A3 53 PUSH BX ; Set ColorF Parameter + + 09A4 8B 5E 0C MOV BX, [BP].PS_ColorB ; Get Background Color + 09A7 53 PUSH BX ; Set ColorB Parameter + + 09A8 9A ---- 07A3 R CALL f GPRINTC ; Print Character! + 09AD EB CC JMP s @PS_Print_It ; Process next character + + 09AF @PS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + 09AF 5F 1 POP DI ; Restore R1 + 09B0 5E 2 POP SI ; Restore R1 + 09B1 1F 3 POP DS ; Restore R1 + 09B2 5D 4 POP BP ; Restore R1 + 09B3 CA 000E RET 14 ; Exit and Clean up Stack + + 09B6 PRINT_STR ENDP + + + ;================================================================ + ;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%) + ;================================================================ + ; + ; Routine to quickly transparently Print a null terminated ASCII + ; string on the active display page up to a maximum length. + ; + ; ENTRY: String = Far Pointer to ASCII string to print + ; MaxLen = # of characters to print if no null found + ; Xpos = X position to draw Text at + ; Ypos = Y position of to draw Text at + ; ColorF = Color to draw text in + ; + ; EXIT: No meaningful values returned + ; + + 0018 TPS_STACK STRUC + 0000 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 0008 00000000 DD ? ; Caller + 000C 0000 TPS_ColorF DW ? ; Text Color + 000E 0000 TPS_Ypos DW ? ; Y Position to Print at + 0010 0000 TPS_Xpos DW ? ; X position to Print at + 0012 0000 TPS_Len DW ? ; Maximum Length of string to print + 0014 0000 0000 TPS_Text DW ?,? ; Far Ptr to Text String + TPS_STACK ENDS + + PUBLIC TPRINT_STR + + 09B6 TPRINT_STR PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 09B6 55 1 PUSH BP ; Save R1 + 09B7 1E 2 PUSH DS ; Save R1 + 09B8 56 3 PUSH SI ; Save R1 + 09B9 57 4 PUSH DI ; Save R1 + 09BA 8B EC MOV BP, SP ; Set up Stack Frame + + 09BC @TPS_Print_It: + + 09BC 8B 4E 12 MOV CX, [BP].TPS_Len ; Get Remaining text Length + 09BF E3 2B JCXZ @TPS_Exit ; Exit when out of text + + 09C1 C4 7E 14 LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text + 09C4 26: 8A 05 MOV AL, ES:[DI] ; AL = Text Character + 09C7 25 00FF AND AX, 00FFh ; Clear High Word + 09CA 74 20 JZ @TPS_Exit ; Exit if null character + + 09CC FF 4E 12 DEC [BP].TPS_Len ; Remaining Text length-- + 09CF FF 46 14 INC [BP].TPS_Text ; Point to Next text char + + ; Set up Call to TGPRINTC + + 09D2 50 PUSH AX ; Set Character Parameter + 09D3 8B 5E 10 MOV BX, [BP].TPS_Xpos ; Get Xpos + 09D6 53 PUSH BX ; Set Xpos Parameter + 09D7 83 C3 08 ADD BX, 8 ; Advance 1 Char to Right + 09DA 89 5E 10 MOV [BP].TPS_Xpos, BX ; Save for next time through + + 09DD 8B 5E 0E MOV BX, [BP].TPS_Ypos ; Get Ypos + 09E0 53 PUSH BX ; Set Ypos Parameter + + 09E1 8B 5E 0C MOV BX, [BP].TPS_ColorF ; Get Text Color + 09E4 53 PUSH BX ; Set ColorF Parameter + + 09E5 9A ---- 08A1 R CALL f TGPRINTC ; Print Character! + 09EA EB D0 JMP s @TPS_Print_It ; Process next character + + 09EC @TPS_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + 09EC 5F 1 POP DI ; Restore R1 + 09ED 5E 2 POP SI ; Restore R1 + 09EE 1F 3 POP DS ; Restore R1 + 09EF 5D 4 POP BP ; Restore R1 + 09F0 CA 000C RET 12 ; Exit and Clean up Stack + + 09F3 TPRINT_STR ENDP + + + ;=========================================== + ;SET_DISPLAY_FONT(SEG FontData, FontNumber%) + ;=========================================== + ; + ; Allows the user to specify their own font data for + ; wither the lower or upper 128 characters. + ; + ; ENTRY: FontData = Far Pointer to Font Bitmaps + ; FontNumber = Which half of set this is + ; = 0, Lower 128 characters + ; = 1, Upper 128 characters + ; + ; EXIT: No meaningful values returned + ; + + 000C SDF_STACK STRUC + 0000 0000 DW ? ; BP + 0002 00000000 DD ? ; Caller + 0006 0000 SDF_Which DW ? ; Hi Table/Low Table Flag + 0008 00000000 SDF_Font DD ? ; Far Ptr to Font Table + SDF_STACK ENDS + + PUBLIC SET_DISPLAY_FONT + + 09F3 SET_DISPLAY_FONT PROC FAR + + 09F3 55 PUSH BP ; Preserve Registers + 09F4 8B EC MOV BP, SP ; Set up Stack Frame + + 09F6 C4 7E 08 LES DI, [BP].SDF_Font ; Get Far Ptr to Font + + 09F9 BE 0022 R MOV SI, o CHARSET_LOW ; Assume Lower 128 chars + 09FC F7 46 06 0001 TEST [BP].SDF_Which, 1 ; Font #1 selected? + 0A01 74 03 JZ @SDF_Set_Font ; If not, skip ahead + + 0A03 BE 0026 R MOV SI, o CHARSET_HI ; Ah, really it's 128-255 + + 0A06 @SDF_Set_Font: + 0A06 89 3C MOV [SI], DI ; Set Font Pointer Offset + 0A08 8C 44 02 MOV [SI+2], ES ; Set Font Pointer Segment + + 0A0B 5D POP BP ; Restore Registers + 0A0C CA 0006 RET 6 ; We are Done.. Outa here + + 0A0F SET_DISPLAY_FONT ENDP + + + ; ===== BITMAP (SPRITE) DISPLAY ROUTINES ===== + + ;====================================================== + ;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) + ;====================================================== + ; + ; Draws a variable sized Graphics Bitmap such as a + ; picture or an Icon on the current Display Page in + ; Mode X. The Bitmap is stored in a linear byte array + ; corresponding to (0,0) (1,0), (2,0) .. (Width, Height) + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 12 - 1 + + + ; This is the same linear manner as mode 13h graphics. + ; + ; ENTRY: Image = Far Pointer to Bitmap Data + ; Xpos = X position to Place Upper Left pixel at + ; Ypos = Y position to Place Upper Left pixel at + ; Width = Width of the Bitmap in Pixels + ; Height = Height of the Bitmap in Pixels + ; + ; EXIT: No meaningful values returned + ; + + 0022 DB_STACK STRUC + 0000 0000 DB_LineO DW ? ; Offset to Next Line + 0002 0000 DB_PixCount DW ? ; (Minimum) # of Pixels/Line + 0004 0000 DB_Start DW ? ; Addr of Upper Left Pixel + 0006 0000 DB_PixSkew DW ? ; # of bytes to Adjust EOL + 0008 0000 DB_SkewFlag DW ? ; Extra Pix on Plane Flag + 000A 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 0012 00000000 DD ? ; Caller + 0016 0000 DB_Height DW ? ; Height of Bitmap in Pixels + 0018 0000 DB_Width DW ? ; Width of Bitmap in Pixels + 001A 0000 DB_Ypos DW ? ; Y position to Draw Bitmap at + 001C 0000 DB_Xpos DW ? ; X position to Draw Bitmap at + 001E 00000000 DB_Image DD ? ; Far Pointer to Graphics Bitmap + DB_STACK ENDS + + PUBLIC DRAW_BITMAP + + 0A0F DRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 0A0F 55 1 PUSH BP ; Save R1 + 0A10 1E 2 PUSH DS ; Save R1 + 0A11 56 3 PUSH SI ; Save R1 + 0A12 57 4 PUSH DI ; Save R1 + 0A13 83 EC 0A SUB SP, 10 ; Allocate workspace + 0A16 8B EC MOV BP, SP ; Set up Stack Frame + + 0A18 C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + 0A1C FC CLD ; Direction Flag = Forward + + 0A1D 8B 46 1A MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos + 0A20 F7 26 0000 R MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + 0A24 8B 5E 1C MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos + 0A27 8A CB MOV CL, BL ; Save Plane # in CL + 0A29 C1 EB 02 SHR BX, 2 ; Xpos/4 = Offset Into Line + + 0A2C 03 F8 ADD DI, AX ; ES:DI -> Start of Line + 0A2E 03 FB ADD DI, BX ; ES:DI -> Upper Left Pixel + 0A30 89 7E 04 MOV [BP].DB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + 0A33 8B 5E 18 MOV BX, [BP].DB_Width ; Get Width of Image + 0A36 8B D3 MOV DX, BX ; Save Copy in DX + 0A38 C1 EB 02 SHR BX, 2 ; /4 = width in bands + 0A3B A1 0000 R MOV AX, SCREEN_WIDTH ; Get Screen Width + 0A3E 2B C3 SUB AX, BX ; - (Bitmap Width/4) + + 0A40 89 46 00 MOV [BP].DB_LineO, AX ; Save Line Width offset + 0A43 89 5E 02 MOV [BP].DB_PixCount, BX ; Minimum # pix to copy + + 0A46 83 E2 03 AND DX, PLANE_BITS ; Get "partial band" size (0-3) + 0A49 89 56 06 MOV [BP].DB_PixSkew, DX ; Also End of Line Skew + 0A4C 89 56 08 MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count + + 0A4F 83 E1 03 AND CX, PLANE_BITS ; CL = Starting Plane # + 0A52 B8 1102 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + 0A55 D2 E4 SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + 0A57 BA 03C4 1 MOV DX, SC_Index ; then Select Register + 0A5A EF 1 OUT DX, AX ; Set I/O Register(s) + 0A5B 8A FC MOV BH, AH ; BH = Saved Plane Mask + 0A5D B3 04 MOV BL, 4 ; BL = Planes to Copy + + 0A5F @DB_COPY_PLANE: + + 0A5F C5 76 1E LDS SI, [BP].DB_Image ; DS:SI-> Source Image + 0A62 8B 56 16 MOV DX, [BP].DB_Height ; # of Lines to Copy + 0A65 8B 7E 04 MOV DI, [BP].DB_Start ; ES:DI-> Dest pos + + 0A68 @DB_COPY_LINE: + 0A68 8B 4E 02 MOV CX, [BP].DB_PixCount ; Min # to copy + + 0A6B F6 C1 FC TEST CL, 0FCh ; 16+PixWide? + 0A6E 74 18 JZ @DB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + + 0A70 @DB_COPY_LOOP: + 0A70 A4 MOVSB ; Copy Bitmap Pixel + 0A71 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0A74 A4 MOVSB ; Copy Bitmap Pixel + 0A75 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0A78 A4 MOVSB ; Copy Bitmap Pixel + 0A79 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0A7C A4 MOVSB ; Copy Bitmap Pixel + 0A7D 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + + 0A80 80 E9 04 SUB CL, 4 ; Pixels to Copy=-4 + 0A83 F6 C1 FC TEST CL, 0FCh ; 4+ Pixels Left? + 0A86 75 E8 JNZ @DB_COPY_LOOP ; if so, do another block + + 0A88 @DB_COPY_REMAINDER: + 0A88 E3 07 JCXZ @DB_NEXT_LINE ; Any Pixels left on line + + 0A8A @DB_COPY2: + 0A8A A4 MOVSB ; Copy Bitmap Pixel + 0A8B 83 C6 03 ADD SI,3 ; Skip to Next Byte in same plane + LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done + 0A8E 49 1 DEC CX ; Counter-- + 0A8F 75 F9 1 JNZ @DB_COPY2 ; Jump if not 0 + + 0A91 @DB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + 0A91 0B 4E 08 OR CX, [BP].DB_SkewFlag ; Get Skew Count + 0A94 74 03 JZ @DB_NEXT2 ; if no partial pixels + + 0A96 A4 MOVSB ; Copy Bitmap Pixel + 0A97 4F DEC DI ; Back up to align + 0A98 4E DEC SI ; Back up to align + + 0A99 @DB_NEXT2: + 0A99 03 76 06 ADD SI, [BP].DB_PixSkew ; Adjust Skew + 0A9C 03 7E 00 ADD DI, [BP].DB_LineO ; Set to Next Display Line + LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more + 0A9F 4A 1 DEC DX ; Counter-- + 0AA0 75 C6 1 JNZ @DB_COPY_LINE ; Jump if not 0 + + ; Copy Next Plane.... + + 0AA2 FE CB DEC BL ; Planes to Go-- + 0AA4 74 1B JZ @DB_Exit ; Hey! We are done + + 0AA6 D0 C7 ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + 0AA8 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0AAB 8A C7 1 MOV AL, BH ; then Get Data Value + 0AAD EE 1 OUT DX, AL ; Set I/O Register + + 0AAE 3C 12 CMP AL, 12h ; Carry Set if AL=11h + 0AB0 83 56 04 00 ADC [BP].DB_Start, 0 ; Screen Addr =+Carry + 0AB4 FF 46 1E INC w [BP].DB_Image ; Start @ Next Byte + + 0AB7 83 6E 08 01 SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew + 0ABB 83 56 08 00 ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1 + + 0ABF EB 9E JMP s @DB_COPY_PLANE ; Go Copy the Next Plane + + 0AC1 @DB_Exit: + 0AC1 83 C4 0A ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + 0AC4 5F 1 POP DI ; Restore R1 + 0AC5 5E 2 POP SI ; Restore R1 + 0AC6 1F 3 POP DS ; Restore R1 + 0AC7 5D 4 POP BP ; Restore R1 + 0AC8 CA 000C RET 12 ; Exit and Clean up Stack + + 0ACB DRAW_BITMAP ENDP + + + ;======================================================= + ;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%) + ;======================================================= + ; + ; Transparently Draws a variable sized Graphics Bitmap + ; such as a picture or an Icon on the current Display Page + ; in Mode X. Pixels with a value of 0 are not drawn, + ; leaving the previous "background" contents intact. + ; + ; The Bitmap format is the same as for the DRAW_BITMAP function. + ; + ; ENTRY: Image = Far Pointer to Bitmap Data + ; Xpos = X position to Place Upper Left pixel at + ; Ypos = Y position to Place Upper Left pixel at + ; Width = Width of the Bitmap in Pixels + ; Height = Height of the Bitmap in Pixels + ; + ; EXIT: No meaningful values returned + ; + + 0022 TB_STACK STRUC + 0000 0000 TB_LineO DW ? ; Offset to Next Line + 0002 0000 TB_PixCount DW ? ; (Minimum) # of Pixels/Line + 0004 0000 TB_Start DW ? ; Addr of Upper Left Pixel + 0006 0000 TB_PixSkew DW ? ; # of bytes to Adjust EOL + 0008 0000 TB_SkewFlag DW ? ; Extra Pix on Plane Flag + 000A 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 0012 00000000 DD ? ; Caller + 0016 0000 TB_Height DW ? ; Height of Bitmap in Pixels + 0018 0000 TB_Width DW ? ; Width of Bitmap in Pixels + 001A 0000 TB_Ypos DW ? ; Y position to Draw Bitmap at + 001C 0000 TB_Xpos DW ? ; X position to Draw Bitmap at + 001E 00000000 TB_Image DD ? ; Far Pointer to Graphics Bitmap + TB_STACK ENDS + + PUBLIC TDRAW_BITMAP + + 0ACB TDRAW_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 0ACB 55 1 PUSH BP ; Save R1 + 0ACC 1E 2 PUSH DS ; Save R1 + 0ACD 56 3 PUSH SI ; Save R1 + 0ACE 57 4 PUSH DI ; Save R1 + 0ACF 83 EC 0A SUB SP, 10 ; Allocate workspace + 0AD2 8B EC MOV BP, SP ; Set up Stack Frame + + 0AD4 C4 3E 0014 R LES DI, d CURRENT_PAGE ; Point to Active VGA Page + 0AD8 FC CLD ; Direction Flag = Forward + + 0AD9 8B 46 1A MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos + 0ADC F7 26 0000 R MUL SCREEN_WIDTH ; AX = Offset to Line Ypos + + 0AE0 8B 5E 1C MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos + 0AE3 8A CB MOV CL, BL ; Save Plane # in CL + 0AE5 C1 EB 02 SHR BX, 2 ; Xpos/4 = Offset Into Line + + 0AE8 03 F8 ADD DI, AX ; ES:DI -> Start of Line + 0AEA 03 FB ADD DI, BX ; ES:DI -> Upper Left Pixel + 0AEC 89 7E 04 MOV [BP].TB_Start, DI ; Save Starting Addr + + ; Compute line to line offset + + 0AEF 8B 5E 18 MOV BX, [BP].TB_Width ; Get Width of Image + 0AF2 8B D3 MOV DX, BX ; Save Copy in DX + 0AF4 C1 EB 02 SHR BX, 2 ; /4 = width in bands + 0AF7 A1 0000 R MOV AX, SCREEN_WIDTH ; Get Screen Width + 0AFA 2B C3 SUB AX, BX ; - (Bitmap Width/4) + + 0AFC 89 46 00 MOV [BP].TB_LineO, AX ; Save Line Width offset + 0AFF 89 5E 02 MOV [BP].TB_PixCount, BX ; Minimum # pix to copy + + 0B02 83 E2 03 AND DX, PLANE_BITS ; Get "partial band" size (0-3) + 0B05 89 56 06 MOV [BP].TB_PixSkew, DX ; Also End of Line Skew + 0B08 89 56 08 MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count + + 0B0B 83 E1 03 AND CX, PLANE_BITS ; CL = Starting Plane # + 0B0E B8 1102 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select + 0B11 D2 E4 SHL AH, CL ; Select correct Plane + OUT_16 SC_Index, AX ; Select Plane... + 0B13 BA 03C4 1 MOV DX, SC_Index ; then Select Register + 0B16 EF 1 OUT DX, AX ; Set I/O Register(s) + 0B17 8A FC MOV BH, AH ; BH = Saved Plane Mask + 0B19 B3 04 MOV BL, 4 ; BL = Planes to Copy + + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 13 - 1 + + + 0B1B @TB_COPY_PLANE: + + 0B1B C5 76 1E LDS SI, [BP].TB_Image ; DS:SI-> Source Image + 0B1E 8B 56 16 MOV DX, [BP].TB_Height ; # of Lines to Copy + 0B21 8B 7E 04 MOV DI, [BP].TB_Start ; ES:DI-> Dest pos + + ; Here AH is set with the value to be considered + ; "Transparent". It can be changed! + + 0B24 B4 00 MOV AH, 0 ; Value to Detect 0 + + 0B26 @TB_COPY_LINE: + 0B26 8B 4E 02 MOV CX, [BP].TB_PixCount ; Min # to copy + + 0B29 F6 C1 FC TEST CL, 0FCh ; 16+PixWide? + 0B2C 74 3A JZ @TB_COPY_REMAINDER ; Nope... + + ; Pixel Copy loop has been unrolled to x4 + + 0B2E @TB_COPY_LOOP: + 0B2E AC LODSB ; Get Pixel Value in AL + 0B2F 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0B32 38 E0 CMP AL, AH ; It is "Transparent"? + 0B34 74 03 JE @TB_SKIP_01 ; Skip ahead if so + 0B36 26: 88 05 MOV ES:[DI], AL ; Copy Pixel to VGA screen + + 0B39 @TB_SKIP_01: + 0B39 AC LODSB ; Get Pixel Value in AL + 0B3A 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0B3D 38 E0 CMP AL, AH ; It is "Transparent"? + 0B3F 74 04 JE @TB_SKIP_02 ; Skip ahead if so + 0B41 26: 88 45 01 MOV ES:[DI+1], AL ; Copy Pixel to VGA screen + + 0B45 @TB_SKIP_02: + 0B45 AC LODSB ; Get Pixel Value in AL + 0B46 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0B49 38 E0 CMP AL, AH ; It is "Transparent"? + 0B4B 74 04 JE @TB_SKIP_03 ; Skip ahead if so + 0B4D 26: 88 45 02 MOV ES:[DI+2], AL ; Copy Pixel to VGA screen + + 0B51 @TB_SKIP_03: + 0B51 AC LODSB ; Get Pixel Value in AL + 0B52 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0B55 38 E0 CMP AL, AH ; It is "Transparent"? + 0B57 74 04 JE @TB_SKIP_04 ; Skip ahead if so + 0B59 26: 88 45 03 MOV ES:[DI+3], AL ; Copy Pixel to VGA screen + + 0B5D @TB_SKIP_04: + 0B5D 83 C7 04 ADD DI, 4 ; Adjust Pixel Write Location + 0B60 80 E9 04 SUB CL, 4 ; Pixels to Copy=-4 + 0B63 F6 C1 FC TEST CL, 0FCh ; 4+ Pixels Left? + 0B66 75 C6 JNZ @TB_COPY_LOOP ; if so, do another block + + 0B68 @TB_COPY_REMAINDER: + 0B68 E3 0F JCXZ @TB_NEXT_LINE ; Any Pixels left on line + + 0B6A @TB_COPY2: + 0B6A AC LODSB ; Get Pixel Value in AL + 0B6B 83 C6 03 ADD SI, 3 ; Skip to Next Byte in same plane + 0B6E 38 E0 CMP AL, AH ; It is "Transparent"? + 0B70 74 03 JE @TB_SKIP_05 ; Skip ahead if so + 0B72 26: 88 05 MOV ES:[DI], AL ; Copy Pixel to VGA screen + + 0B75 @TB_SKIP_05: + 0B75 47 INC DI ; Advance Dest Addr + LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done + 0B76 49 1 DEC CX ; Counter-- + 0B77 75 F1 1 JNZ @TB_COPY2 ; Jump if not 0 + + 0B79 @TB_NEXT_LINE: + + ; any Partial Pixels? (some planes only) + + 0B79 0B 4E 08 OR CX, [BP].TB_SkewFlag ; Get Skew Count + 0B7C 74 09 JZ @TB_NEXT2 ; if no partial pixels + + 0B7E AC LODSB ; Get Pixel Value in AL + 0B7F 4E DEC SI ; Backup to Align + 0B80 38 E0 CMP AL, AH ; It is "Transparent"? + 0B82 74 03 JE @TB_NEXT2 ; Skip ahead if so + 0B84 26: 88 05 MOV ES:[DI], AL ; Copy Pixel to VGA screen + + 0B87 @TB_NEXT2: + 0B87 03 76 06 ADD SI, [BP].TB_PixSkew ; Adjust Skew + 0B8A 03 7E 00 ADD DI, [BP].TB_LineO ; Set to Next Display Line + LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More + 0B8D 4A 1 DEC DX ; Counter-- + 0B8E 75 96 1 JNZ @TB_COPY_LINE ; Jump if not 0 + + ;Copy Next Plane.... + + 0B90 FE CB DEC BL ; Planes to Go-- + 0B92 74 1C JZ @TB_Exit ; Hey! We are done + + 0B94 D0 C7 ROL BH, 1 ; Next Plane in line... + OUT_8 SC_Data, BH ; Select Plane + 0B96 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0B99 8A C7 1 MOV AL, BH ; then Get Data Value + 0B9B EE 1 OUT DX, AL ; Set I/O Register + + 0B9C 3C 12 CMP AL, 12h ; Carry Set if AL=11h + 0B9E 83 56 04 00 ADC [BP].TB_Start, 0 ; Screen Addr =+Carry + 0BA2 FF 46 1E INC w [BP].TB_Image ; Start @ Next Byte + + 0BA5 83 6E 08 01 SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew + 0BA9 83 56 08 00 ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1 + + 0BAD E9 FF6B JMP @TB_COPY_PLANE ; Go Copy the next Plane + + 0BB0 @TB_Exit: + 0BB0 83 C4 0A ADD SP, 10 ; Deallocate workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + 0BB3 5F 1 POP DI ; Restore R1 + 0BB4 5E 2 POP SI ; Restore R1 + 0BB5 1F 3 POP DS ; Restore R1 + 0BB6 5D 4 POP BP ; Restore R1 + 0BB7 CA 000C RET 12 ; Exit and Clean up Stack + + 0BBA TDRAW_BITMAP ENDP + + + ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES ===== + + ;================================== + ;COPY_PAGE (SourcePage%, DestPage%) + ;================================== + ; + ; Duplicate on display page onto another + ; + ; ENTRY: SourcePage = Display Page # to Duplicate + ; DestPage = Display Page # to hold copy + ; + ; EXIT: No meaningful values returned + ; + + 0010 CP_STACK STRUC + 0000 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 0008 00000000 DD ? ; Caller + 000C 0000 CP_DestP DW ? ; Page to hold copied image + 000E 0000 CP_SourceP DW ? ; Page to Make copy from + CP_STACK ENDS + + PUBLIC COPY_PAGE + + 0BBA COPY_PAGE PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 0BBA 55 1 PUSH BP ; Save R1 + 0BBB 1E 2 PUSH DS ; Save R1 + 0BBC 56 3 PUSH SI ; Save R1 + 0BBD 57 4 PUSH DI ; Save R1 + 0BBE 8B EC MOV BP, SP ; Set up Stack Frame + 0BC0 FC CLD ; Block Xfer Forwards + + ; Make sure Page #'s are valid + + 0BC1 8B 46 0E MOV AX, [BP].CP_SourceP ; Get Source Page # + 0BC4 3B 06 0004 R CMP AX, LAST_PAGE ; is it > Max Page #? + 0BC8 73 3D JAE @CP_Exit ; if so, abort + + 0BCA 8B 5E 0C MOV BX, [BP].CP_DestP ; Get Destination Page # + 0BCD 3B 1E 0004 R CMP BX, LAST_PAGE ; is it > Max Page #? + 0BD1 73 34 JAE @CP_Exit ; if so, abort + + 0BD3 3B C3 CMP AX, BX ; Pages #'s the same? + 0BD5 74 30 JE @CP_Exit ; if so, abort + + ; Setup DS:SI and ES:DI to Video Pages + + 0BD7 D1 E3 SHL BX, 1 ; Scale index to Word + 0BD9 8B BF 0006 R MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page + + 0BDD 8B D8 MOV BX, AX ; Index to Source page + 0BDF D1 E3 SHL BX, 1 ; Scale index to Word + 0BE1 8B B7 0006 R MOV SI, PAGE_ADDR[BX] ; Offset to Source Page + + 0BE5 8B 0E 000E R MOV CX, PAGE_SIZE ; Get size of Page + 0BE9 A1 0016 R MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment + 0BEC 8E C0 MOV ES, AX ; ES:DI -> Dest Page + 0BEE 8E D8 MOV DS, AX ; DS:SI -> Source Page + + ; Setup VGA registers for Mem to Mem copy + + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + 0BF0 BA 03CE 1 MOV DX, GC_Index ; then Select Register + 0BF3 B8 0008 1 MOV AX, LATCHES_ON ; then Get Data Value + 0BF6 EF 1 OUT DX, AX ; Set I/O Register(s) + OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes + 0BF7 BA 03C4 1 MOV DX, SC_Index ; then Select Register + 0BFA B8 0F02 1 MOV AX, ALL_PLANES_ON ; then Get Data Value + 0BFD EF 1 OUT DX, AX ; Set I/O Register(s) + + ; Note.. Do *NOT* use MOVSW or MOVSD - they will + ; Screw with the latches which are 8 bits x 4 + + 0BFE F3/ A4 REP MOVSB ; Copy entire Page! + + ; Reset VGA for normal memory access + + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off + 0C00 BA 03CE 1 MOV DX, GC_Index ; then Select Register + 0C03 B8 FF08 1 MOV AX, LATCHES_OFF ; then Get Data Value + 0C06 EF 1 OUT DX, AX ; Set I/O Register(s) + + 0C07 @CP_Exit: + POPx DI, SI, DS, BP ; Restore Saved Registers + 0C07 5F 1 POP DI ; Restore R1 + 0C08 5E 2 POP SI ; Restore R1 + 0C09 1F 3 POP DS ; Restore R1 + 0C0A 5D 4 POP BP ; Restore R1 + 0C0B CA 0004 RET 4 ; Exit and Clean up Stack + + 0C0E COPY_PAGE ENDP + + + ;========================================================================== + ;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%) + ;========================================================================== + ; + ; Copies a Bitmap Image from one Display Page to Another + ; This Routine is Limited to copying Images with the same + ; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4) + ; Copying an Image to the Same Page is supported, but results + ; may be defined when the when the rectangular areas + ; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) - + ; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap... + ; No Paramter checking to done to insure that + ; X2 >= X1 and Y2 >= Y1. Be Careful... + ; + ; ENTRY: SourcePage = Display Page # with Source Image + ; X1 = Upper Left Xpos of Source Image + ; Y1 = Upper Left Ypos of Source Image + ; X2 = Lower Right Xpos of Source Image + ; Y2 = Lower Right Ypos of Source Image + ; DestPage = Display Page # to copy Image to + ; DestX1 = Xpos to Copy UL Corner of Image to + ; DestY1 = Ypos to Copy UL Corner of Image to + ; + ; EXIT: AX = Success Flag: 0 = Failure / -1= Success + ; + + 0020 CB_STACK STRUC + 0000 0000 CB_Height DW ? ; Height of Image in Lines + 0002 0000 CB_Width DW ? ; Width of Image in "bands" + 0004 0000 0000 0000 DW ?x4 ; DI, SI, DS, BP + 0000 + 000C 00000000 DD ? ; Caller + 0010 0000 CB_DestY1 DW ? ; Destination Ypos + 0012 0000 CB_DestX1 DW ? ; Destination Xpos + 0014 0000 CB_DestP DW ? ; Page to Copy Bitmap To + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 14 - 1 + + + 0016 0000 CB_Y2 DW ? ; LR Ypos of Image + 0018 0000 CB_X2 DW ? ; LR Xpos of Image + 001A 0000 CB_Y1 DW ? ; UL Ypos of Image + 001C 0000 CB_X1 DW ? ; UL Xpos of Image + 001E 0000 CB_SourceP DW ? ; Page containing Source Bitmap + CB_STACK ENDS + + PUBLIC COPY_BITMAP + + 0C0E COPY_BITMAP PROC FAR + + PUSHx BP, DS, SI, DI ; Preserve Important Registers + 0C0E 55 1 PUSH BP ; Save R1 + 0C0F 1E 2 PUSH DS ; Save R1 + 0C10 56 3 PUSH SI ; Save R1 + 0C11 57 4 PUSH DI ; Save R1 + 0C12 83 EC 04 SUB SP, 4 ; Allocate WorkSpace on Stack + 0C15 8B EC MOV BP, SP ; Set up Stack Frame + + ; Prep Registers (and keep jumps short!) + + 0C17 8E 06 0016 R MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram + 0C1B FC CLD ; Block Xfer Forwards + + ; Make sure Parameters are valid + + 0C1C 8B 5E 1E MOV BX, [BP].CB_SourceP ; Get Source Page # + 0C1F 3B 1E 0004 R CMP BX, LAST_PAGE ; is it > Max Page #? + 0C23 73 7D JAE @CB_Abort ; if so, abort + + 0C25 8B 4E 14 MOV CX, [BP].CB_DestP ; Get Destination Page # + 0C28 3B 0E 0004 R CMP CX, LAST_PAGE ; is it > Max Page #? + 0C2C 73 74 JAE @CB_Abort ; if so, abort + + 0C2E 8B 46 1C MOV AX, [BP].CB_X1 ; Get Source X1 + 0C31 33 46 12 XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1 + 0C34 83 E0 03 AND AX, PLANE_BITS ; Check Plane Bits + 0C37 75 69 JNZ @CB_Abort ; They should cancel out + + ; Setup for Copy processing + + OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select + 0C39 BA 03C4 1 MOV DX, SC_INDEX ; then Select Register + 0C3C B0 02 1 MOV AL, MAP_MASK ; then Get Data Value + 0C3E EE 1 OUT DX, AL ; Set I/O Register + OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on + 0C3F BA 03CE 1 MOV DX, GC_Index ; then Select Register + 0C42 B8 0008 1 MOV AX, LATCHES_ON ; then Get Data Value + 0C45 EF 1 OUT DX, AX ; Set I/O Register(s) + + ; Compute Info About Images, Setup ES:SI & ES:DI + + 0C46 8B 46 16 MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines + 0C49 2B 46 1A SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1 + 0C4C 40 INC AX ; (add 1 since were not 0 based) + 0C4D 89 46 00 MOV [BP].CB_Height, AX ; Save on Stack for later use + + 0C50 8B 46 18 MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels + 0C53 8B 56 1C MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1 + 0C56 C1 E8 02 SHR AX, 2 ; Get X2 Band (X2 / 4) + 0C59 C1 EA 02 SHR DX, 2 ; Get X1 Band (X1 / 4) + 0C5C 2B C2 SUB AX, DX ; AX = # of Bands - 1 + 0C5E 40 INC AX ; AX = # of Bands + 0C5F 89 46 02 MOV [BP].CB_Width, AX ; Save on Stack for later use + + 0C62 D1 E3 SHL BX, 1 ; Scale Source Page to Word + 0C64 8B B7 0006 R MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page + 0C68 8B 46 1A MOV AX, [BP].CB_Y1 ; Get Source Y1 Line + 0C6B F7 26 0000 R MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + 0C6F 03 F0 ADD SI, AX ; SI = Offset to Line Y1 + 0C71 8B 46 1C MOV AX, [BP].CB_X1 ; Get Source X1 + 0C74 C1 E8 02 SHR AX, 2 ; X1 / 4 = Byte offset + 0C77 03 F0 ADD SI, AX ; SI = Byte Offset to (X1,Y1) + + 0C79 8B D9 MOV BX, CX ; Dest Page Index to BX + 0C7B D1 E3 SHL BX, 1 ; Scale Source Page to Word + 0C7D 8B BF 0006 R MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page + 0C81 8B 46 10 MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line + 0C84 F7 26 0000 R MUL SCREEN_WIDTH ; AX = Offset to Line Y1 + 0C88 03 F8 ADD DI, AX ; DI = Offset to Line Y1 + 0C8A 8B 46 12 MOV AX, [BP].CB_DestX1 ; Get Dest X1 + 0C8D C1 E8 02 SHR AX, 2 ; X1 / 4 = Byte offset + 0C90 03 F8 ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1) + + 0C92 8B 4E 02 MOV CX, [BP].CB_Width ; CX = Width of Image (Bands) + 0C95 49 DEC CX ; CX = 1? + 0C96 74 0F JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band + + 0C98 8B 5E 1C MOV BX, [BP].CB_X1 ; Get Source X1 + 0C9B 83 E3 03 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?) + 0C9E 74 70 JZ @CB_Check_Right ; if so, check right alignment + 0CA0 75 41 JNZ @CB_Left_Band ; not aligned? well.. + + 0CA2 @CB_Abort: + CLR AX ; Return False (Failure) + 0CA2 33 C0 1 XOR AX, AX ; Set Register = 0 + 0CA4 E9 00D7 JMP @CB_Exit ; and Finish Up + + ; Copy when Left & Right Clip Masks overlap... + + 0CA7 @CB_Only_One_Band: + 0CA7 8B 5E 1C MOV BX, [BP].CB_X1 ; Get Left Clip Mask + 0CAA 83 E3 03 AND BX, PLANE_BITS ; Mask out Row # + 0CAD 2E: 8A 87 0000 R MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask + 0CB2 8B 5E 18 MOV BX, [BP].CB_X2 ; Get Right Clip Mask + 0CB5 83 E3 03 AND BX, PLANE_BITS ; Mask out Row # + 0CB8 2E: 22 87 0004 R AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte + + OUT_8 SC_Data, AL ; Clip For Left & Right Masks + 0CBD BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0CC0 EE 1 OUT DX, AL ; Set I/O Register + + 0CC1 8B 4E 00 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + 0CC4 8B 16 0000 R MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + 0CC8 33 DB 1 XOR BX, BX ; Set Register = 0 + + 0CCA @CB_One_Loop: + 0CCA 26: 8A 00 MOV AL, ES:[SI+BX] ; Load Latches + 0CCD 26: 88 01 MOV ES:[DI+BX], AL ; Unload Latches + 0CD0 03 DA ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_One_Done ; Exit Loop if Finished + 0CD2 49 1 DEC CX ; Counter-- + 0CD3 74 0B 1 JZ @CB_One_Done ; Jump if 0 + + 0CD5 26: 8A 00 MOV AL, ES:[SI+BX] ; Load Latches + 0CD8 26: 88 01 MOV ES:[DI+BX], AL ; Unload Latches + 0CDB 03 DA ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_One_Loop ; Loop until Finished + 0CDD 49 1 DEC CX ; Counter-- + 0CDE 75 EA 1 JNZ @CB_One_Loop ; Jump if not 0 + + 0CE0 @CB_One_Done: + 0CE0 E9 0094 JMP @CB_Finish ; Outa Here! + + ; Copy Left Edge of Bitmap + + 0CE3 @CB_Left_Band: + + OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask + 0CE3 BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0CE6 2E: 8A 87 0000 R 1 MOV AL, Left_Clip_Mask[BX] ; then Get Data Value + 0CEB EE 1 OUT DX, AL ; Set I/O Register + + 0CEC 8B 4E 00 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + 0CEF 8B 16 0000 R MOV DX, SCREEN_WIDTH ; DX = Width of Screen + CLR BX ; BX = Offset into Image + 0CF3 33 DB 1 XOR BX, BX ; Set Register = 0 + + 0CF5 @CB_Left_Loop: + 0CF5 26: 8A 00 MOV AL, ES:[SI+BX] ; Load Latches + 0CF8 26: 88 01 MOV ES:[DI+BX], AL ; Unload Latches + 0CFB 03 DA ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished + 0CFD 49 1 DEC CX ; Counter-- + 0CFE 74 0B 1 JZ @CB_Left_Done ; Jump if 0 + + 0D00 26: 8A 00 MOV AL, ES:[SI+BX] ; Load Latches + 0D03 26: 88 01 MOV ES:[DI+BX], AL ; Unload Latches + 0D06 03 DA ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Left_Loop ; Loop until Finished + 0D08 49 1 DEC CX ; Counter-- + 0D09 75 EA 1 JNZ @CB_Left_Loop ; Jump if not 0 + + 0D0B @CB_Left_Done: + 0D0B 47 INC DI ; Move Dest Over 1 band + 0D0C 46 INC SI ; Move Source Over 1 band + 0D0D FF 4E 02 DEC [BP].CB_Width ; Band Width-- + + ; Determine if Right Edge of Bitmap needs special copy + + 0D10 @CB_Check_Right: + 0D10 8B 5E 18 MOV BX, [BP].CB_X2 ; Get Source X2 + 0D13 83 E3 03 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?) + 0D16 80 FB 03 CMP BL, 03h ; Plane = 3? + 0D19 74 2C JE @CB_Copy_Middle ; Copy the Middle then! + + ; Copy Right Edge of Bitmap + + 0D1B @CB_Right_Band: + + OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask + 0D1B BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0D1E 2E: 8A 87 0004 R 1 MOV AL, Right_Clip_Mask[BX] ; then Get Data Value + 0D23 EE 1 OUT DX, AL ; Set I/O Register + + 0D24 FF 4E 02 DEC [BP].CB_Width ; Band Width-- + 0D27 8B 4E 00 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy + 0D2A 8B 16 0000 R MOV DX, SCREEN_WIDTH ; DX = Width of Screen + 0D2E 8B 5E 02 MOV BX, [BP].CB_Width ; BX = Offset to Right Edge + + 0D31 @CB_Right_Loop: + 0D31 26: 8A 00 MOV AL, ES:[SI+BX] ; Load Latches + 0D34 26: 88 01 MOV ES:[DI+BX], AL ; Unload Latches + 0D37 03 DA ADD BX, DX ; Advance Offset to Next Line + LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished + 0D39 49 1 DEC CX ; Counter-- + 0D3A 74 0B 1 JZ @CB_Right_Done ; Jump if 0 + + 0D3C 26: 8A 00 MOV AL, ES:[SI+BX] ; Load Latches + 0D3F 26: 88 01 MOV ES:[DI+BX], AL ; Unload Latches + 0D42 03 DA ADD BX, DX ; Advance Offset to Next Line + LOOPx CX, @CB_Right_Loop ; Loop until Finished + 0D44 49 1 DEC CX ; Counter-- + 0D45 75 EA 1 JNZ @CB_Right_Loop ; Jump if not 0 + + 0D47 @CB_Right_Done: + + ; Copy the Main Block of the Bitmap + + 0D47 @CB_Copy_Middle: + + 0D47 8B 4E 02 MOV CX, [BP].CB_Width ; Get Width Remaining + 0D4A E3 2B JCXZ @CB_Finish ; Exit if Done + + OUT_8 SC_Data, ALL_PLANES ; Copy all Planes + 0D4C BA 03C5 1 MOV DX, SC_Data ; then Select Register + 0D4F B0 0F 1 MOV AL, ALL_PLANES ; then Get Data Value + 0D51 EE 1 OUT DX, AL ; Set I/O Register + + 0D52 8B 16 0000 R MOV DX, SCREEN_WIDTH ; Get Width of Screen minus + 0D56 2B D1 SUB DX, CX ; Image width (for Adjustment) + 0D58 8B 46 00 MOV AX, [BP].CB_Height ; AX = # of Lines to Copy + 0D5B 8B D9 MOV BX, CX ; BX = Quick REP reload count + 0D5D 8C C1 MOV CX, ES ; Move VGA Segment + 0D5F 8E D9 MOV DS, CX ; Into DS + + ; Actual Copy Loop. REP MOVSB does the work + + 0D61 @CB_Middle_Copy: + 0D61 8B CB MOV CX, BX ; Recharge Rep Count + 0D63 F3/ A4 REP MOVSB ; Move Bands + LOOPjz AX, @CB_Finish ; Exit Loop if Finished + 0D65 48 1 DEC AX ; Counter-- + 0D66 74 0F 1 JZ @CB_Finish ; Jump if 0 + + 0D68 03 F2 ADD SI, DX ; Adjust DS:SI to Next Line + 0D6A 03 FA ADD DI, DX ; Adjust ES:DI to Next Line + + 0D6C 8B CB MOV CX, BX ; Recharge Rep Count + 0D6E F3/ A4 REP MOVSB ; Move Bands + + 0D70 03 F2 ADD SI, DX ; Adjust DS:SI to Next Line + 0D72 03 FA ADD DI, DX ; Adjust ES:DI to Next Line + LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done + 0D74 48 1 DEC AX ; Counter-- + 0D75 75 EA 1 JNZ @CB_Middle_Copy ; Jump if not 0 + + 0D77 @CB_Finish: + OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on + 0D77 BA 03CE 1 MOV DX, GC_Index ; then Select Register + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Page 15 - 1 + + + 0D7A B8 FF08 1 MOV AX, LATCHES_OFF ; then Get Data Value + 0D7D EF 1 OUT DX, AX ; Set I/O Register(s) + + 0D7E @CB_Exit: + 0D7E 83 C4 04 ADD SP, 04 ; Deallocate stack workspace + POPx DI, SI, DS, BP ; Restore Saved Registers + 0D81 5F 1 POP DI ; Restore R1 + 0D82 5E 2 POP SI ; Restore R1 + 0D83 1F 3 POP DS ; Restore R1 + 0D84 5D 4 POP BP ; Restore R1 + 0D85 CA 0010 RET 16 ; Exit and Clean up Stack + + 0D88 COPY_BITMAP ENDP + + END ; End of Code Segment + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Symbols 16 - 1 + + + + +Macros: + + N a m e Type + +CLR . . . . . . . . . . . . . . Proc +LOOPjz . . . . . . . . . . . . . Proc +LOOPx . . . . . . . . . . . . . Proc +OUT_16 . . . . . . . . . . . . . Proc +OUT_8 . . . . . . . . . . . . . Proc +POPx . . . . . . . . . . . . . . Proc +PUSHx . . . . . . . . . . . . . Proc + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Symbols 17 - 1 + + + + +Structures and Unions: + + N a m e Size + Offset Type + +CB_STACK . . . . . . . . . . . . 0020 + CB_Height . . . . . . . . . . 0000 Word + CB_Width . . . . . . . . . . . 0002 Word + CB_DestY1 . . . . . . . . . . 0010 Word + CB_DestX1 . . . . . . . . . . 0012 Word + CB_DestP . . . . . . . . . . . 0014 Word + CB_Y2 . . . . . . . . . . . . 0016 Word + CB_X2 . . . . . . . . . . . . 0018 Word + CB_Y1 . . . . . . . . . . . . 001A Word + CB_X1 . . . . . . . . . . . . 001C Word + CB_SourceP . . . . . . . . . . 001E Word +CP_STACK . . . . . . . . . . . . 0010 + CP_DestP . . . . . . . . . . . 000C Word + CP_SourceP . . . . . . . . . . 000E Word +CVS_STACK . . . . . . . . . . . 000A + CVS_COLOR . . . . . . . . . . 0008 Byte +DB_STACK . . . . . . . . . . . . 0022 + DB_LineO . . . . . . . . . . . 0000 Word + DB_PixCount . . . . . . . . . 0002 Word + DB_Start . . . . . . . . . . . 0004 Word + DB_PixSkew . . . . . . . . . . 0006 Word + DB_SkewFlag . . . . . . . . . 0008 Word + DB_Height . . . . . . . . . . 0016 Word + DB_Width . . . . . . . . . . . 0018 Word + DB_Ypos . . . . . . . . . . . 001A Word + DB_Xpos . . . . . . . . . . . 001C Word + DB_Image . . . . . . . . . . . 001E DWord +DL_STACK . . . . . . . . . . . . 0014 + DL_ColorF . . . . . . . . . . 000A Byte + DL_Ypos2 . . . . . . . . . . . 000C Word + DL_Xpos2 . . . . . . . . . . . 000E Word + DL_Ypos1 . . . . . . . . . . . 0010 Word + DL_Xpos1 . . . . . . . . . . . 0012 Word +FB_STACK . . . . . . . . . . . . 0016 + FB_Color . . . . . . . . . . . 000C Byte + FB_Ypos2 . . . . . . . . . . . 000E Word + FB_Xpos2 . . . . . . . . . . . 0010 Word + FB_Ypos1 . . . . . . . . . . . 0012 Word + FB_Xpos1 . . . . . . . . . . . 0014 Word +GDR_STACK . . . . . . . . . . . 000E + GDR_Blue . . . . . . . . . . . 0006 Word + GDR_Green . . . . . . . . . . 0008 Word + GDR_Red . . . . . . . . . . . 000A Word + GDR_Register . . . . . . . . . 000C Byte +GPC_STACK . . . . . . . . . . . 001E + GPC_Width . . . . . . . . . . 0000 Word + GPC_Lines . . . . . . . . . . 0002 Byte + GPC_T_SETS . . . . . . . . . . 0004 Word + GPC_T_SETO . . . . . . . . . . 0006 Word + GPC_ColorB . . . . . . . . . . 0014 Byte + GPC_ColorF . . . . . . . . . . 0016 Byte + GPC_Ypos . . . . . . . . . . . 0018 Word + GPC_Xpos . . . . . . . . . . . 001A Word + GPC_Char . . . . . . . . . . . 001C Byte +LDR_STACK . . . . . . . . . . . 0014 + LDR_Sync . . . . . . . . . . . 000A Word + LDR_EndReg . . . . . . . . . . 000C Byte + LDR_StartReg . . . . . . . . . 000E Byte + LDR_PalData . . . . . . . . . 0010 DWord +Mode_Data_Table . . . . . . . . 000C + M_MiscR . . . . . . . . . . . 0000 Byte + M_Pages . . . . . . . . . . . 0001 Byte + M_XSize . . . . . . . . . . . 0002 Word + M_YSize . . . . . . . . . . . 0004 Word + M_XMax . . . . . . . . . . . . 0006 Word + M_YMax . . . . . . . . . . . . 0008 Word + M_CRTC . . . . . . . . . . . . 000A Word +PS_STACK . . . . . . . . . . . . 001A + PS_ColorB . . . . . . . . . . 000C Word + PS_ColorF . . . . . . . . . . 000E Word + PS_Ypos . . . . . . . . . . . 0010 Word + PS_Xpos . . . . . . . . . . . 0012 Word + PS_Len . . . . . . . . . . . . 0014 Word + PS_Text . . . . . . . . . . . 0016 Word +RDR_STACK . . . . . . . . . . . 0012 + RDR_EndReg . . . . . . . . . . 000A Byte + RDR_StartReg . . . . . . . . . 000C Byte + RDR_PalData . . . . . . . . . 000E DWord +RP_STACK . . . . . . . . . . . . 000C + RP_Ypos . . . . . . . . . . . 0008 Word + RP_Xpos . . . . . . . . . . . 000A Word +SAP_STACK . . . . . . . . . . . 0008 + SAP_Page . . . . . . . . . . . 0006 Word +SDF_STACK . . . . . . . . . . . 000C + SDF_Which . . . . . . . . . . 0006 Word + SDF_Font . . . . . . . . . . . 0008 DWord +SDP_STACK . . . . . . . . . . . 0008 + SDP_Page . . . . . . . . . . . 0006 Word +SDR_STACK . . . . . . . . . . . 000E + SDR_Blue . . . . . . . . . . . 0006 Byte + SDR_Green . . . . . . . . . . 0008 Byte + SDR_Red . . . . . . . . . . . 000A Byte + SDR_Register . . . . . . . . . 000C Byte +SM_STACK . . . . . . . . . . . . 000A + SM_Mode . . . . . . . . . . . 0008 Word +SP_STACK . . . . . . . . . . . . 000E + SETP_Color . . . . . . . . . . 0008 Byte + SETP_Ypos . . . . . . . . . . 000A Word + SETP_Xpos . . . . . . . . . . 000C Word +SVM_STACK . . . . . . . . . . . 0016 + SVM_Table . . . . . . . . . . 0000 Word + SVM_Pages . . . . . . . . . . 000E Word + SVM_Ysize . . . . . . . . . . 0010 Word + SVM_Xsize . . . . . . . . . . 0012 Word + SVM_Mode . . . . . . . . . . . 0014 Word +SW_STACK . . . . . . . . . . . . 000C + SW_Ypos . . . . . . . . . . . 0006 Word + SW_Xpos . . . . . . . . . . . 0008 Word + SW_Page . . . . . . . . . . . 000A Word +TB_STACK . . . . . . . . . . . . 0022 + TB_LineO . . . . . . . . . . . 0000 Word + TB_PixCount . . . . . . . . . 0002 Word + TB_Start . . . . . . . . . . . 0004 Word + TB_PixSkew . . . . . . . . . . 0006 Word + TB_SkewFlag . . . . . . . . . 0008 Word + TB_Height . . . . . . . . . . 0016 Word + TB_Width . . . . . . . . . . . 0018 Word + TB_Ypos . . . . . . . . . . . 001A Word + TB_Xpos . . . . . . . . . . . 001C Word + TB_Image . . . . . . . . . . . 001E DWord +TGP_STACK . . . . . . . . . . . 001C + TGP_Width . . . . . . . . . . 0000 Word + TGP_Lines . . . . . . . . . . 0002 Byte + TGP_T_SETS . . . . . . . . . . 0004 Word + TGP_T_SETO . . . . . . . . . . 0006 Word + TGP_ColorF . . . . . . . . . . 0014 Byte + TGP_Ypos . . . . . . . . . . . 0016 Word + TGP_Xpos . . . . . . . . . . . 0018 Word + TGP_Char . . . . . . . . . . . 001A Byte +TPS_STACK . . . . . . . . . . . 0018 + TPS_ColorF . . . . . . . . . . 000C Word + TPS_Ypos . . . . . . . . . . . 000E Word + TPS_Xpos . . . . . . . . . . . 0010 Word + TPS_Len . . . . . . . . . . . 0012 Word + TPS_Text . . . . . . . . . . . 0014 Word + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Symbols 18 - 1 + + + + +Segments and Groups: + + N a m e Size Length Align Combine Class + +DGROUP . . . . . . . . . . . . . GROUP +_DATA . . . . . . . . . . . . . 16 Bit 0000 Word Public 'DATA' +_BSS . . . . . . . . . . . . . . 16 Bit 002A Word Public 'BSS' +MODEX_TEXT . . . . . . . . . . . 16 Bit 0D88 Word Public 'CODE' + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Symbols 19 - 1 + + + + +Procedures, parameters and locals: + + N a m e Type Value Attr + +CLEAR_VGA_SCREEN . . . . . . . . P Far 0280 MODEX_TEXT Length= 0022 Public +COPY_BITMAP . . . . . . . . . . P Far 0C0E MODEX_TEXT Length= 017E Public +COPY_PAGE . . . . . . . . . . . P Far 0BBA MODEX_TEXT Length= 0054 Public +DRAW_BITMAP . . . . . . . . . . P Far 0A0F MODEX_TEXT Length= 00BC Public +DRAW_LINE . . . . . . . . . . . P Far 040B MODEX_TEXT Length= 02A7 Public +FILL_BLOCK . . . . . . . . . . . P Far 0300 MODEX_TEXT Length= 010B Public +GET_ACTIVE_PAGE . . . . . . . . P Far 06E5 MODEX_TEXT Length= 0004 Public +GET_DAC_REGISTER . . . . . . . . P Far 0641 MODEX_TEXT Length= 0025 Public +GET_DISPLAY_PAGE . . . . . . . . P Far 0724 MODEX_TEXT Length= 0004 Public +GET_X_OFFSET . . . . . . . . . . P Far 078D MODEX_TEXT Length= 0004 Public +GET_Y_OFFSET . . . . . . . . . . P Far 0791 MODEX_TEXT Length= 0004 Public +GPRINTC . . . . . . . . . . . . P Far 07A3 MODEX_TEXT Length= 00FE Public +LOAD_DAC_REGISTERS . . . . . . . P Far 0666 MODEX_TEXT Length= 0037 Public +PRINT_STR . . . . . . . . . . . P Far 0975 MODEX_TEXT Length= 0041 Public +READ_DAC_REGISTERS . . . . . . . P Far 069D MODEX_TEXT Length= 002B Public +READ_POINT . . . . . . . . . . . P Far 02D2 MODEX_TEXT Length= 002E Public +SET_ACTIVE_PAGE . . . . . . . . P Far 06C8 MODEX_TEXT Length= 001D Public +SET_DAC_REGISTER . . . . . . . . P Far 0624 MODEX_TEXT Length= 001D Public +SET_DISPLAY_FONT . . . . . . . . P Far 09F3 MODEX_TEXT Length= 001C Public +SET_DISPLAY_PAGE . . . . . . . . P Far 06E9 MODEX_TEXT Length= 003B Public +SET_MODEX . . . . . . . . . . . P Far 0251 MODEX_TEXT Length= 002F Public +SET_POINT . . . . . . . . . . . P Far 02A2 MODEX_TEXT Length= 0030 Public +SET_VGA_MODEX . . . . . . . . . P Far 0104 MODEX_TEXT Length= 014D Public +SET_WINDOW . . . . . . . . . . . P Far 0728 MODEX_TEXT Length= 0065 Public +SYNC_DISPLAY . . . . . . . . . . P Far 0795 MODEX_TEXT Length= 000E Public +TDRAW_BITMAP . . . . . . . . . . P Far 0ACB MODEX_TEXT Length= 00EF Public +TGPRINTC . . . . . . . . . . . . P Far 08A1 MODEX_TEXT Length= 00D4 Public +TPRINT_STR . . . . . . . . . . . P Far 09B6 MODEX_TEXT Length= 003D Public + Microsoft (R) Macro Assembler Version 6.11 06/22/14 14:00:02 +modex.asm Symbols 20 - 1 + + + + +Symbols: + + N a m e Type Value Attr + +?x3 . . . . . . . . . . . . . . Text ?,?,? +?x4 . . . . . . . . . . . . . . Text ?,?,?,? +@CB_Abort . . . . . . . . . . . L Near 0CA2 MODEX_TEXT +@CB_Check_Right . . . . . . . . L Near 0D10 MODEX_TEXT +@CB_Copy_Middle . . . . . . . . L Near 0D47 MODEX_TEXT +@CB_Exit . . . . . . . . . . . . L Near 0D7E MODEX_TEXT +@CB_Finish . . . . . . . . . . . L Near 0D77 MODEX_TEXT +@CB_Left_Band . . . . . . . . . L Near 0CE3 MODEX_TEXT +@CB_Left_Done . . . . . . . . . L Near 0D0B MODEX_TEXT +@CB_Left_Loop . . . . . . . . . L Near 0CF5 MODEX_TEXT +@CB_Middle_Copy . . . . . . . . L Near 0D61 MODEX_TEXT +@CB_One_Done . . . . . . . . . . L Near 0CE0 MODEX_TEXT +@CB_One_Loop . . . . . . . . . . L Near 0CCA MODEX_TEXT +@CB_Only_One_Band . . . . . . . L Near 0CA7 MODEX_TEXT +@CB_Right_Band . . . . . . . . . L Near 0D1B MODEX_TEXT +@CB_Right_Done . . . . . . . . . L Near 0D47 MODEX_TEXT +@CB_Right_Loop . . . . . . . . . L Near 0D31 MODEX_TEXT +@CP_Exit . . . . . . . . . . . . L Near 0C07 MODEX_TEXT +@CodeSize . . . . . . . . . . . Number 0001h +@DB_COPY2 . . . . . . . . . . . L Near 0A8A MODEX_TEXT +@DB_COPY_LINE . . . . . . . . . L Near 0A68 MODEX_TEXT +@DB_COPY_LOOP . . . . . . . . . L Near 0A70 MODEX_TEXT +@DB_COPY_PLANE . . . . . . . . . L Near 0A5F MODEX_TEXT +@DB_COPY_REMAINDER . . . . . . . L Near 0A88 MODEX_TEXT +@DB_Exit . . . . . . . . . . . . L Near 0AC1 MODEX_TEXT +@DB_NEXT2 . . . . . . . . . . . L Near 0A99 MODEX_TEXT +@DB_NEXT_LINE . . . . . . . . . L Near 0A91 MODEX_TEXT +@DL_BREZHAM . . . . . . . . . . L Near 04C7 MODEX_TEXT +@DL_DeltaYOK2 . . . . . . . . . L Near 0515 MODEX_TEXT +@DL_DeltaYOK . . . . . . . . . . L Near 04DC MODEX_TEXT +@DL_DrawLeft . . . . . . . . . . L Near 051F MODEX_TEXT +@DL_DrawRight . . . . . . . . . L Near 05A3 MODEX_TEXT +@DL_EXIT2 . . . . . . . . . . . L Near 061E MODEX_TEXT +@DL_EXIT . . . . . . . . . . . . L Near 04C4 MODEX_TEXT +@DL_HORZ . . . . . . . . . . . . L Near 0433 MODEX_TEXT +@DL_LONGLN . . . . . . . . . . . L Near 0461 MODEX_TEXT +@DL_NOSWAP1 . . . . . . . . . . L Near 0428 MODEX_TEXT +@DL_NOSWAP2 . . . . . . . . . . L Near 048C MODEX_TEXT +@DL_SLLExit . . . . . . . . . . L Near 0563 MODEX_TEXT +@DL_SLLL2nc . . . . . . . . . . L Near 0543 MODEX_TEXT +@DL_SLLL3nc . . . . . . . . . . L Near 0558 MODEX_TEXT +@DL_SLLLoop . . . . . . . . . . L Near 0537 MODEX_TEXT +@DL_SLR2nc . . . . . . . . . . . L Near 05C5 MODEX_TEXT +@DL_SLR3nc . . . . . . . . . . . L Near 05D9 MODEX_TEXT +@DL_SLRExit . . . . . . . . . . L Near 05E3 MODEX_TEXT +@DL_SLRLoop . . . . . . . . . . L Near 05B9 MODEX_TEXT +@DL_STLExit . . . . . . . . . . L Near 05A1 MODEX_TEXT +@DL_STLLoop . . . . . . . . . . L Near 0575 MODEX_TEXT +@DL_STLnc2 . . . . . . . . . . . L Near 0588 MODEX_TEXT +@DL_STLnc3 . . . . . . . . . . . L Near 059D MODEX_TEXT +@DL_ShallowLeft . . . . . . . . L Near 0525 MODEX_TEXT +@DL_ShallowRight . . . . . . . . L Near 05A7 MODEX_TEXT +@DL_SteepLeft . . . . . . . . . L Near 0566 MODEX_TEXT +@DL_SteepRight . . . . . . . . . L Near 05E5 MODEX_TEXT +@DL_VLINE . . . . . . . . . . . L Near 0481 MODEX_TEXT +@DL_VLoop . . . . . . . . . . . L Near 04B4 MODEX_TEXT +@DL_XRSEG . . . . . . . . . . . L Near 0479 MODEX_TEXT +@DP_WAIT0 . . . . . . . . . . . L Near 0706 MODEX_TEXT +@DP_WAIT1 . . . . . . . . . . . L Near 071B MODEX_TEXT +@DataSize . . . . . . . . . . . Number 0000h +@FB_EXIT . . . . . . . . . . . . L Near 0404 MODEX_TEXT +@FB_LEFT_CONT . . . . . . . . . L Near 037A MODEX_TEXT +@FB_LEFT_LOOP . . . . . . . . . L Near 036A MODEX_TEXT +@FB_L_PLANE_FLUSH . . . . . . . L Near 037C MODEX_TEXT +@FB_MIDDLE_LOOP . . . . . . . . L Near 03C7 MODEX_TEXT +@FB_NORMAL . . . . . . . . . . . L Near 034C MODEX_TEXT +@FB_NOSWAP1 . . . . . . . . . . L Near 031F MODEX_TEXT +@FB_NOSWAP2 . . . . . . . . . . L Near 0339 MODEX_TEXT +@FB_ONE_BAND_ONLY . . . . . . . L Near 03D2 MODEX_TEXT +@FB_ONE_LOOP . . . . . . . . . . L Near 03F4 MODEX_TEXT +@FB_RIGHT_CONT . . . . . . . . . L Near 03B0 MODEX_TEXT +@FB_RIGHT_LOOP . . . . . . . . . L Near 03A0 MODEX_TEXT +@FB_RIGHT . . . . . . . . . . . L Near 037D MODEX_TEXT +@FB_R_EDGE_FLUSH . . . . . . . . L Near 03B3 MODEX_TEXT +@GPC_DECODE_CHAR_BYTE . . . . . L Near 080F MODEX_TEXT +@GPC_EXIT . . . . . . . . . . . L Near 0897 MODEX_TEXT +@GPC_LowChar . . . . . . . . . . L Near 07DB MODEX_TEXT +@GPC_NEXT_LINE . . . . . . . . . L Near 0889 MODEX_TEXT +@GPC_NO_LEFT0BITS . . . . . . . L Near 083C MODEX_TEXT +@GPC_NO_LEFT1BITS . . . . . . . L Near 0831 MODEX_TEXT +@GPC_NO_MIDDLE0BITS . . . . . . L Near 085E MODEX_TEXT +@GPC_NO_MIDDLE1BITS . . . . . . L Near 0853 MODEX_TEXT +@GPC_NO_RIGHT0BITS . . . . . . . L Near 0888 MODEX_TEXT +@GPC_NO_RIGHT1BITS . . . . . . . L Near 087D MODEX_TEXT +@GPC_Set_Char . . . . . . . . . L Near 07E3 MODEX_TEXT +@Interface . . . . . . . . . . . Number 0000h +@LDR_Load . . . . . . . . . . . L Near 0677 MODEX_TEXT +@Model . . . . . . . . . . . . . Number 0004h +@PS_Exit . . . . . . . . . . . . L Near 09AF MODEX_TEXT +@PS_Print_It . . . . . . . . . . L Near 097B MODEX_TEXT +@SAP_Exit . . . . . . . . . . . L Near 06E1 MODEX_TEXT +@SDF_Set_Font . . . . . . . . . L Near 0A06 MODEX_TEXT +@SDP_Exit . . . . . . . . . . . L Near 0720 MODEX_TEXT +@SD_WAIT0 . . . . . . . . . . . L Near 0798 MODEX_TEXT +@SD_WAIT1 . . . . . . . . . . . L Near 079D MODEX_TEXT +@SMX_Exit . . . . . . . . . . . L Near 027B MODEX_TEXT +@STRLoop . . . . . . . . . . . . L Near 05F4 MODEX_TEXT +@STRnc2 . . . . . . . . . . . . L Near 0606 MODEX_TEXT +@STRnc3 . . . . . . . . . . . . L Near 061A MODEX_TEXT +@SVM_BadModeSetup . . . . . . . L Near 015C MODEX_TEXT +@SVM_Continue . . . . . . . . . L Near 0161 MODEX_TEXT +@SVM_EXIT . . . . . . . . . . . L Near 0247 MODEX_TEXT +@SVM_Set_Data . . . . . . . . . L Near 01AA MODEX_TEXT +@SVM_Set_Pages . . . . . . . . . L Near 0207 MODEX_TEXT +@SVM_Setup_CRTC . . . . . . . . L Near 019D MODEX_TEXT +@SVM_Setup_Table . . . . . . . . L Near 0193 MODEX_TEXT +@SW_Exit . . . . . . . . . . . . L Near 0789 MODEX_TEXT +@SW_WAIT0 . . . . . . . . . . . L Near 0761 MODEX_TEXT +@SW_WAIT1 . . . . . . . . . . . L Near 0776 MODEX_TEXT +@TB_COPY2 . . . . . . . . . . . L Near 0B6A MODEX_TEXT +@TB_COPY_LINE . . . . . . . . . L Near 0B26 MODEX_TEXT +@TB_COPY_LOOP . . . . . . . . . L Near 0B2E MODEX_TEXT +@TB_COPY_PLANE . . . . . . . . . L Near 0B1B MODEX_TEXT +@TB_COPY_REMAINDER . . . . . . . L Near 0B68 MODEX_TEXT +@TB_Exit . . . . . . . . . . . . L Near 0BB0 MODEX_TEXT +@TB_NEXT2 . . . . . . . . . . . L Near 0B87 MODEX_TEXT +@TB_NEXT_LINE . . . . . . . . . L Near 0B79 MODEX_TEXT +@TB_SKIP_01 . . . . . . . . . . L Near 0B39 MODEX_TEXT +@TB_SKIP_02 . . . . . . . . . . L Near 0B45 MODEX_TEXT +@TB_SKIP_03 . . . . . . . . . . L Near 0B51 MODEX_TEXT +@TB_SKIP_04 . . . . . . . . . . L Near 0B5D MODEX_TEXT +@TB_SKIP_05 . . . . . . . . . . L Near 0B75 MODEX_TEXT +@TGP_DECODE_CHAR_BYTE . . . . . L Near 090D MODEX_TEXT +@TGP_EXIT . . . . . . . . . . . L Near 096B MODEX_TEXT +@TGP_LowChar . . . . . . . . . . L Near 08D9 MODEX_TEXT +@TGP_NEXT_LINE . . . . . . . . . L Near 095E MODEX_TEXT +@TGP_NO_LEFT1BITS . . . . . . . L Near 092D MODEX_TEXT +@TGP_NO_MIDDLE1BITS . . . . . . L Near 0941 MODEX_TEXT +@TGP_NO_RIGHT1BITS . . . . . . . L Near 095D MODEX_TEXT +@TGP_Set_Char . . . . . . . . . L Near 08E1 MODEX_TEXT +@TPS_Exit . . . . . . . . . . . L Near 09EC MODEX_TEXT +@TPS_Print_It . . . . . . . . . L Near 09BC MODEX_TEXT +@code . . . . . . . . . . . . . Text MODEX_TEXT +@data . . . . . . . . . . . . . Text DGROUP +@fardata? . . . . . . . . . . . Text FAR_BSS +@fardata . . . . . . . . . . . . Text FAR_DATA +@stack . . . . . . . . . . . . . Text DGROUP +ACTIVE_PAGE . . . . . . . . . . Word 0012 _BSS +ALL_PLANES_ON . . . . . . . . . Number 0F02h +ALL_PLANES . . . . . . . . . . . Number 000Fh +ASYNC_RESET . . . . . . . . . . Number 0100h +ATTRIB_Ctrl . . . . . . . . . . Number 03C0h +CHAIN4_OFF . . . . . . . . . . . Number 0604h +CHARSET_HI . . . . . . . . . . . Word 0026 _BSS +CHARSET_LOW . . . . . . . . . . Word 0022 _BSS +CHAR_BITS . . . . . . . . . . . Number 000Fh +CRTC_Data . . . . . . . . . . . Number 03D5h +CRTC_Index . . . . . . . . . . . Number 03D4h +CURRENT_MOFFSET . . . . . . . . Word 001C _BSS +CURRENT_PAGE . . . . . . . . . . Word 0014 _BSS +CURRENT_SEGMENT . . . . . . . . Word 0016 _BSS +CURRENT_XOFFSET . . . . . . . . Word 0018 _BSS +CURRENT_YOFFSET . . . . . . . . Word 001A _BSS +Char_Plane_Data . . . . . . . . Byte 0008 MODEX_TEXT +DAC_READ_ADDR . . . . . . . . . Number 03C7h +DAC_WRITE_ADDR . . . . . . . . . Number 03C8h +DISPLAY_PAGE . . . . . . . . . . Word 0010 _BSS +False . . . . . . . . . . . . . Number 0000h +GC_Index . . . . . . . . . . . . Number 03CEh +GET_CHAR_PTR . . . . . . . . . . Number 1130h +INPUT_1 . . . . . . . . . . . . Number 03DAh +LAST_PAGE . . . . . . . . . . . Word 0004 _BSS +LATCHES_OFF . . . . . . . . . . Number FF08h +LATCHES_ON . . . . . . . . . . . Number 0008h +Left_Clip_Mask . . . . . . . . . Byte 0000 MODEX_TEXT +MAP_MASK_PLANE1 . . . . . . . . Number 0102h +MAP_MASK_PLANE2 . . . . . . . . Number 1102h +MAP_MASK . . . . . . . . . . . . Number 0002h +MAX_XOFFSET . . . . . . . . . . Word 001E _BSS +MAX_YOFFSET . . . . . . . . . . Word 0020 _BSS +MISC_OUTPUT . . . . . . . . . . Number 03C2h +MODE_200_Tall . . . . . . . . . L Near 0044 MODEX_TEXT +MODE_240_Tall . . . . . . . . . L Near 0054 MODEX_TEXT +MODE_320_Wide . . . . . . . . . L Near 0028 MODEX_TEXT +MODE_320x200 . . . . . . . . . . L Near 0074 MODEX_TEXT +MODE_320x240 . . . . . . . . . . L Near 00BC MODEX_TEXT +MODE_320x400 . . . . . . . . . . L Near 0086 MODEX_TEXT +MODE_320x480 . . . . . . . . . . L Near 00CE MODEX_TEXT +MODE_360_Wide . . . . . . . . . L Near 0036 MODEX_TEXT +MODE_360x200 . . . . . . . . . . L Near 00E0 MODEX_TEXT +MODE_360x240 . . . . . . . . . . L Near 0098 MODEX_TEXT +MODE_360x400 . . . . . . . . . . L Near 00F2 MODEX_TEXT +MODE_360x480 . . . . . . . . . . L Near 00AA MODEX_TEXT +MODE_400_Tall . . . . . . . . . L Near 0044 MODEX_TEXT +MODE_480_Tall . . . . . . . . . L Near 0054 MODEX_TEXT +MODE_Double_Line . . . . . . . . L Near 0020 MODEX_TEXT +MODE_Single_Line . . . . . . . . L Near 0018 MODEX_TEXT +MODE_TABLE . . . . . . . . . . . L Near 0064 MODEX_TEXT +NUM_MODES . . . . . . . . . . . Number 0008h +PAGE_ADDR . . . . . . . . . . . Word 0006 _BSS +PAGE_SIZE . . . . . . . . . . . Word 000E _BSS +PEL_DATA_REG . . . . . . . . . . Number 03C9h +PIXEL_PAN_REG . . . . . . . . . Number 0033h +PLANE_BITS . . . . . . . . . . . Number 0003h +READ_MAP . . . . . . . . . . . . Number 0004h +ROM_8x8_Hi . . . . . . . . . . . Number 0004h +ROM_8x8_Lo . . . . . . . . . . . Number 0003h +Right_Clip_Mask . . . . . . . . Byte 0004 MODEX_TEXT +SCREEN_HEIGHT . . . . . . . . . Word 0002 _BSS +SCREEN_WIDTH . . . . . . . . . . Word 0000 _BSS +SC_Data . . . . . . . . . . . . Number 03C5h +SC_Index . . . . . . . . . . . . Number 03C4h +SEQU_RESTART . . . . . . . . . . Number 0300h +START_DISP_HI . . . . . . . . . Number 000Ch +START_DISP_LO . . . . . . . . . Number 000Dh +True . . . . . . . . . . . . . . Number -0001h +VERT_RETRACE . . . . . . . . . . Number 0008h +VGA_Segment . . . . . . . . . . Number A000h +b . . . . . . . . . . . . . . . Text BYTE PTR +d . . . . . . . . . . . . . . . Text DWORD PTR +f . . . . . . . . . . . . . . . Text FAR PTR +nil . . . . . . . . . . . . . . Number 0000h +o . . . . . . . . . . . . . . . Text OFFSET +s . . . . . . . . . . . . . . . Text SHORT +w . . . . . . . . . . . . . . . Text WORD PTR + + 0 Warnings + 0 Errors diff --git a/16/lib/modex105/MODEX.OBJ b/16/lib/modex105/MODEX.OBJ new file mode 100644 index 00000000..80b311d6 Binary files /dev/null and b/16/lib/modex105/MODEX.OBJ differ diff --git a/16/lib/modex105/MODEX.SBR b/16/lib/modex105/MODEX.SBR new file mode 100644 index 00000000..ec6a15a4 Binary files /dev/null and b/16/lib/modex105/MODEX.SBR differ diff --git a/16/lib/modex105/PACKING.LST b/16/lib/modex105/PACKING.LST new file mode 100644 index 00000000..88f817ca --- /dev/null +++ b/16/lib/modex105/PACKING.LST @@ -0,0 +1,87 @@ + +PACKING LIST FOR MODEX104 + +DIRECTORY: \ - The Mode X Library versoon 1.04 + +ASM BAT 26 05-14-93 6:00p - Batch File to Assemble MODEX.ASM +MODE-X TXT 2135 05-14-93 6:00p - File Describing MODE X Routines +MODEX ASM 117039 05-14-93 6:00p - Assembly source to Mode X Library +MODEX BI 3238 05-14-93 6:00p - Include File for BASIC/PDS +MODEX H 2943 05-14-93 6:00p - Include File for C/C++ +MODEX OBJ 5208 05-14-93 6:00p - The Mode X Library +README DOC 3259 05-14-93 6:00p - Information on this Product +PACKING LST 4767 05-14-93 6:00p - This File + +DIRECTORY: \DEMOS - Mode X Demos + +CHARDEMO EXE 13066 05-14-93 6:00p - Demo of Multiple Fonts & Color Cycling +TEST6 EXE 19990 05-14-93 6:00p - Main Mode X Demo +ROM_8X8 FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE +SPACEAGE FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE +SYSTEM FNT 1024 05-14-93 6:00p - Font for CHARDEMO.EXE + +DIRECTORY: \DEMOS\BASIC7 - Demo Sources for Microsoft BASIC 7.1 (PDS) + +MAKE-LIB BAT 166 05-14-93 6:00p - Batch File to make MODEX.LIB/.QLB +MODEX BI 3238 05-14-93 6:00p - Include File for MODE X Library +MODEX LIB 7189 05-14-93 6:00p - Mode X & Utility Libraries for QBX +MODEX OBJ 5208 05-14-93 6:00p - Mode X Library - Object File +MODEX QLB 11141 05-14-93 6:00p - Mode X & Utility Quick Library +TEST6 BAS 12733 05-14-93 6:00p - Main Demo Source Code (TEST6.EXE) +UASM-BC7 BAT 43 05-14-93 6:00p - Batch file to Make UTILS.OBJ for QBX +UTILS ASM 8506 05-14-93 6:00p - Basic Utilities - Assembler source +UTILS BI 2028 05-14-93 6:00p - Basic Utilities - Basic Includes +UTILS OBJ 681 05-14-93 6:00p - Basic Utilities - Object File +CHARDEMO BAS 3431 05-14-93 6:00p - Source to CHARDEMO.EXE + +DIRECTORY: \DEMOS\C - Demo Sources for Borland C/C++ + +C_UTILS ASM 8782 05-14-93 6:00p - C Utilities - Assembler source +C_UTILS H 2623 05-14-93 6:00p - C Utilities - C Includes +C_UTILS OBJ 648 05-14-93 6:00p - C Utilities - Object File +MODEX H 2943 05-14-93 6:00p - Mode X Library C Incldues +MODEX OBJ 5208 05-14-93 6:00p - Mode X Library +UTLS-ASM BAT 36 05-14-93 6:00p - Batch File to Make C_UTILS.OBJ +X-DEMO C 15085 05-14-93 6:00p - Source to Main Demo (TEST6) in C +X-DEMO EXE 41090 05-14-93 6:00p - C Version of Main Demo +X-DEMO PRJ 5188 05-14-93 6:00p - Borland C Project file + +DIRECTORY: \DEMOS\PASCAL - Demo Sources for Turbo Pascal + +TEST5 PAS 15873 05-14-93 6:00p - Source for a TP Version of TEST6.EXE + +DIRECTORY: \DEMOS\QB45 - Demo Sources for Microsoft QuickBASIC 4.5 + +MAKE-LIB BAT 164 05-14-93 6:00p - Batch File to make MODEX.LIB/.QLB +MODEX BI 3238 05-14-93 6:00p - Include File for MODE X Library +MODEX LIB 7189 05-14-93 6:00p - Mode X & Utility Libraries for QB45 +MODEX OBJ 5208 05-14-93 6:00p - Mode X Library - Object File +MODEX QLB 9739 05-14-93 6:00p - Mode X & Utility Quick Library/QB45 +TEST6A BAS 12743 05-14-93 6:00p - Main Demo Source Code (TEST6.EXE) +TEST6A EXE 40544 05-14-93 6:00p - QB45 Version of Main Demo +UASM-QB4 BAT 30 05-14-93 6:00p - Batch file to Make UTILS.OBJ for QB45 +UTILS ASM 8506 05-14-93 6:00p - Basic Utilities - Assembler source +UTILS BI 2028 05-14-93 6:00p - Basic Utilities - Basic Includes +UTILS OBJ 628 05-14-93 6:00p - Basic Utilities - Object File + +DIRECTORY: \FONTEDIT - Font Editor + +CSEDIT EXE 39242 05-14-93 6:00p - Font Editor Program +CSEDIT DOC 8629 05-14-93 6:00p - Font Editor Documentation +CHARSETS CS 2144 05-14-93 6:00p - Internal Fonts for Editor +MOUSEIMG CS 128 05-14-93 6:00p - Mouse Pointers for Editor +PALETTE CS 768 05-14-93 6:00p - Palette for Editor +INVERSE FNT 1024 05-14-93 6:00p - Sample Font +ROM_8X8 FNT 1024 05-14-93 6:00p - Sample Font +SPACEAGE FNT 1024 05-14-93 6:00p - Sample Font +SYSTEM FNT 1024 05-14-93 6:00p - Sample Font + +DIRECTORY: \PALEDIT - Palette Editor + +PALEDIT EXE 31954 05-14-93 6:00p - Palette Editor Program +PALEDIT DOC 6688 05-14-93 6:00p - Palette Editor Documentation +CHARSETS CS 2144 05-14-93 6:00p - Internal Fonts for Editor +MOUSEIMG CS 128 05-14-93 6:00p - Mouse Pointers for Editor +GAMECOLR PAL 768 05-14-93 6:00p - Sample Palette +PRIME PAL 768 05-14-93 6:00p - Sample Palette +RGB PAL 768 05-14-93 6:00p - Sample Palette diff --git a/16/lib/modex105/PALEDIT/CHARSETS.CS b/16/lib/modex105/PALEDIT/CHARSETS.CS new file mode 100644 index 00000000..97fe608f Binary files /dev/null and b/16/lib/modex105/PALEDIT/CHARSETS.CS differ diff --git a/16/lib/modex105/PALEDIT/GAMECOLR.PAL b/16/lib/modex105/PALEDIT/GAMECOLR.PAL new file mode 100644 index 00000000..621b1e5e Binary files /dev/null and b/16/lib/modex105/PALEDIT/GAMECOLR.PAL differ diff --git a/16/lib/modex105/PALEDIT/MOUSEIMG.CS b/16/lib/modex105/PALEDIT/MOUSEIMG.CS new file mode 100644 index 00000000..101e2084 Binary files /dev/null and b/16/lib/modex105/PALEDIT/MOUSEIMG.CS differ diff --git a/16/lib/modex105/PALEDIT/PALEDIT.DOC b/16/lib/modex105/PALEDIT/PALEDIT.DOC new file mode 100644 index 00000000..61d0b2ee --- /dev/null +++ b/16/lib/modex105/PALEDIT/PALEDIT.DOC @@ -0,0 +1,166 @@ + +PALEDIT - A Simple VGA 256 Color Palette Editor + + +PALEDIT is distributed with MODEXnnn.ZIP, the general purpose MODE X +Library for VGA Graphics. + +WHAT YOU NEED TO RUN PALEDIT: + + * A Vga Monitor + * A Microsoft Compatible Mouse + + A Mouse is most definitely required, as the keyboard is used for + nothing except entering file names. + +FILES NEEDED IN THE CURRENT DIRECTORY: + + PALEDIT.EXE - The Palette Editor Program + CHARSETS.CS - The Palette Editor's Internal Fonts + MOUSEIMG.CS - The Palette Editor's Mouse Pointer + +SAMPLE PALETTE FILE THAT SHOULD BE INCLUDED: + + RGB.PAL - A Simple Palette with Reds, Greens, and Blues + PRIME.PAL - A Simple Palette + GAMECOLR.PAL - A Bright Palette from a Game of mine. + +WHAT IT EDITS: + + The VGA DAC Registers, all 256 of them. + +HOW IT WORKS/FEATURES: + + PALEDIT allows the user to see the entire VGA Palette of 256 colors + and select and modify the RED, GREEN, and BLUE values of any individual + color (DAC) register. The entire group of 256 colors can be saved to + a disk file for later retrieval. + + Individual "SLIDERS" show the current RED, GREEN, and BLUE color + components of the current color and allow them to be changed. + + The Following operations can be performed. + + * Raise, Lower, and set the RED, GREEN, or BLUE components. + * Copy the current RGB values to another Color (DAC) Register + * Brighten the selected color + * Darken and selected color + * Reset the selected color to its original state + * Blend an entire range of colors, creating a smooth + Transition from one color to another + * Optionally Lock out the first 16 colors to prevent + Accidental Modification + +DESCRIPTION OF OBJECTS/FEATURES FROM THE TOP DOWN: + + COLOR SLIDERS: In the upper left of the screen there are + Three Rectangular Boxes: One for each primary color: + RED, GREEN, and BLUE. Each Box has an arrow at each + end, and a scale bar in the middle, connecting the two + arrows. The scale bar is much like a thermometer, + indicating how much of that color is in the selected + color. To the right of each Box, the name of the color + is indicated, along with the content color in the form + of a number from 0 to 63; where 0 means none of that + color goes into making the selected color, and 63 means + that the selected color is saturated with that color. + + Clicking the mouse on the slider's left arrow box will + decrease the amount of that primary color in the selected + color. Holding the mouse button down will reduce the + color value all the way to 0. + + Clicking the mouse on the slider's right arrow box will + increase the amount of that primary color in the selected + color. Holding the mouse button down will increase the + color value all the way to 63. + + Clicking the mouse on the scale bar will set the amount + of that primary color to the value the represents that + position on the slider. + + LOCK Button: Clicking the button toggles the lockout of the + first 16 colors. When they are locked out, they can not + be modified, and when selected the word "LOCKED" will + appear below the color # on the Color Information Display. + + LOAD Button: Clicking this button will load the Palette file + that is named in the Palette File name box. If no name is + given or no such file exists, then nothing will be loaded. + + SAVE Button: Clicking this button will save the current Palette + in a file using the name given in the Palette File Name Box. + If a Valid name is not provided, nothing will be saved. + + QUIT Button: Clicking this button will return you to DOS. + Nothing is saved, and no confirmation is given. + + + Color Information Display: This Box is on the left side of the + Screen, below the Color Sliders. It shows the number of the + currently selected color (from 0 to 255) and indicates if + that color is locked. To the right of this box is a big + square showing the current color. + + LIGHTER Button: Clicking this button will make the selected + color brighter. + + DARKER Button: Clicking this button will make the selected + color darker. + + RESET Button: Clicking this button will restore the selected + color to the value it had when it was first selected. + + BLEND Button: Clicking this button will let you Blend a range + of colors together. One end of the range of colors is the + currently selected color. After Clicking the BLEND button. + You must click on the color at the other end of the range + in the Palette Display Box. All of the colors in between + those two colors will be changed to represent a gradual + transition from the color at one end to the color at the + other end. + + PALETTE FILE NAME BOX: This Text Box is used to enter the name + of a Palette file to load or the name to save the current + Palette as. Just click on the Box, and it will change color + and a flashing cursor will appear. Now you type in a filename + or edit the existing filename. Press or click + outside the text box to end editing. + + PALETTE DISPLAY BOX: This Box shows all 256 colors in an array + of 32 by 8 color blocks. The Currently Selected Color will + have a Box around it. Clicking on a color with the Left + Mouse button will make that color the new currently selected + color. Clicking on a color with the Right Mouse Button will + copy the color value from the old selected color to it, before + it is made the new selected color. + + Message Bar: At the very bottom of the screen, this Bar will display + information and messages for various functions. + +PALETTE FILE FORMAT: + + BINARY image, in order of VGA DAC (Color) Number. 3 Bytes Per + Color, 256 Colors. 768 Bytes total. The Files will be exactly + 768 bytes in size. + + COLOR: + RED: 1 BYTE + GREEN: 1 BYTE + BLUE: 1 BYTE + + PALETTE: Array (0 to 255) of COLOR + +COMMENTS, QUESTIONS, BUG REPORTS, etc: + + Send the to the Author: Matt Pritchard + + Through the 80xxx Fidonet Echo or + + Matt Pritchard + P.O. Box 140264 + Irving, TX 75014 + +CREDITS: + + This Palette Editor was written in QuickBASIC 4.5 diff --git a/16/lib/modex105/PALEDIT/PALEDIT.EXE b/16/lib/modex105/PALEDIT/PALEDIT.EXE new file mode 100644 index 00000000..f69e172d Binary files /dev/null and b/16/lib/modex105/PALEDIT/PALEDIT.EXE differ diff --git a/16/lib/modex105/PALEDIT/PRIME.PAL b/16/lib/modex105/PALEDIT/PRIME.PAL new file mode 100644 index 00000000..310ca6e7 Binary files /dev/null and b/16/lib/modex105/PALEDIT/PRIME.PAL differ diff --git a/16/lib/modex105/PALEDIT/RGB.PAL b/16/lib/modex105/PALEDIT/RGB.PAL new file mode 100644 index 00000000..bc03425d Binary files /dev/null and b/16/lib/modex105/PALEDIT/RGB.PAL differ diff --git a/16/lib/modex105/README.DOC b/16/lib/modex105/README.DOC new file mode 100644 index 00000000..63a9053f --- /dev/null +++ b/16/lib/modex105/README.DOC @@ -0,0 +1,76 @@ + +========================================================================= + þ þ þþþþþ þþþþ þþþþþ þ þ þ þþþþþ þ þ + þþ þþ þ þ þ þ þ þ þ þþ þ þ þ þ + þ þ þ þ þ þ þ þþþþ þ þ þ þ þ þþþþþ + þ þ þ þ þ þ þ þ þ þ þ þ þ + þ þ þþþþþ þþþþ þþþþþ þ þ þþþþþ þþ þþþþþ þ +========================================================================= + MODE X 1.04 +========================================================================= + Library & Editors by Matt Pritchard: Release 1.04 on 14 Mar 93 +========================================================================= + +MODEX104 is a library of high performance assembler routines for setting, +accessing, and manipulating the Undocumented 256 Color Modes available in +all VGA adaptors. + +MODEX104 includes the following elements: + + MODE X Library - A library of MODE X routines written in assembly. + + FONT EDITOR - An editor for creating and modifying fonts for use by + The MODE X Library. + + PALETTE EDITOR - An editor for creating and modifying palettes for + use in VGA 256 Color modes. + + MODE X Demos - Programs that show off the various features of the + MODE X Library + + MODE X Demo Source - The Full source code for the MODE X Demos for + the following Languages: Microsoft QuickBASIC 4.5, + Microsoft BASIC 7.1 PDS, Borland C/C++ 3.1, + and Borland Turbo Pascal. + +THE LEGAL STUFF: + + The Mode X Library has been placed into the Public Domain by the + Author (Matt Pritchard). The Font Editor and Palette Editor are also + placed into the Public Domain by the Author (Matt Pritchard). The + Source Code to the above editors is not in the Public Domain. + + The Mode X Demos and the Mode X Demo Sources have been placed into the + Public domain by the Author (Matt Pritchard). + + The Mode X Library may be used freely in any non commerical product. + It would be nice if the author was credited for the contribution, + but it is not necessary. No $$$ involved. + + The Mode X Library may be used freely in a commercial product, *IF* + the author (Matt Pritchard) is credited for the contribution. That's + it. No $$$ involved. + + The Mode X Library should not be re-sold or modified and re-sold. + No fee in excess of $5 should be charged for duplication of this + Library. + +CONTRIBUTORS: The following people have contributed to this effort. + + Michael Abrash - He told us all how to do it in the first place. + Scott Wyatt - He ported the Main Demo code to Turbo Pascal. + +THE AUTHOR: + + The author of MODEX104 is Matt Pritchard. + All Questions and correspondance can be directed to: + + "Matt Pritchard" on Fido Net ECHO Conference: 80xxx + + or mailed to: Matt Pritchard + P.O. Box 140264 + Irving, TX 75014-0264 + + Questions, Inquiries, Comments, Donations, etc are quite welcome. + + diff --git a/16/lib/modex105/modex105.zip b/16/lib/modex105/modex105.zip new file mode 100644 index 00000000..9457bd98 Binary files /dev/null and b/16/lib/modex105/modex105.zip differ diff --git a/16/vgap.pcx b/16/vgap.pcx new file mode 100644 index 00000000..5d4a39ba Binary files /dev/null and b/16/vgap.pcx differ