X-Git-Url: http://4ch.mooo.com/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fmodex%2Fmodex.asm;fp=src%2Flib%2Fmodex%2Fmodex.asm;h=0000000000000000000000000000000000000000;hb=ab0c7149375a68f5a0708e4114dcbbea42bfc251;hp=f2b1b5124db8b7d4f6132f68af8e718700e30f6d;hpb=a926eef7c1a72dcf71fc63bca7bddd8753b4eb98;p=16.git diff --git a/src/lib/modex/modex.asm b/src/lib/modex/modex.asm deleted file mode 100755 index f2b1b512..00000000 --- a/src/lib/modex/modex.asm +++ /dev/null @@ -1,3505 +0,0 @@ -;======================================================== -; 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 Huge - ;.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 - ?x1 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 / 0 = Success -; - -SVM_STACK STRUC - SVM_Table DW ? ; Offset of Mode Info Table - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; 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 - push bp - push ds - push si - push di - 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_BadModeSetup1 ; 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! - mov ch,0 ; Set Hi Word = 0! - CMP CL, CS:[SI].M_Pages ; Check # Pages for mode - JA @SVM_BadModeSetup2 ; Report Error if too Many Pages - JCXZ @SVM_BadModeSetup3 ; 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_BadModeSetup4 ; Report Error if too small - CMP AX, CS:[SI].M_XMax ; Check against Max X - JA @SVM_BadModeSetup5 ; 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_BadModeSetup6 ; Report Error if too small - CMP BX, CS:[SI].M_YMax ; Check against Max Y - JA @SVM_BadModeSetup7 ; Report Error if too big - - ; Enough memory to Fit it all? - - SHR AX, 1 ; # of Bytes:Line = XSize/4 - SHR AX, 1 ; # 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... - - jmp @SVM_Continue;0000 - -@SVM_BadModeSetup: - mov ax,8 ; Return Value = False - JMP @SVM_Exit ; Normal Exit -@SVM_BadModeSetup1: - mov ax,1 ; Return Value = False - JMP @SVM_Exit ; Normal Exit -@SVM_BadModeSetup2: - mov ax,2 ; Return Value = False - JMP @SVM_Exit ; Normal Exit -@SVM_BadModeSetup3: - mov ax,3 ; Return Value = False - JMP @SVM_Exit ; Normal Exit -@SVM_BadModeSetup4: - mov ax,4 ; Return Value = False - JMP @SVM_Exit ; Normal Exit -@SVM_BadModeSetup5: - mov ax,5 ; Return Value = False - JMP @SVM_Exit ; Normal Exit -@SVM_BadModeSetup6: - mov ax,6 ; Return Value = False - JMP @SVM_Exit ; Normal Exit -@SVM_BadModeSetup7: - mov ax,7 ; 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, 1 ; Bytes = Pixels / 4 - SHR AX, 1 ; 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 - - mov bx,0 ; 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 - - mov ax,0 ; 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 - pop di - pop si - pop ds - pop bp - 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 - push bp - push si - MOV BP, SP ; Set up Stack Frame - - mov ax,0 ; 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 - mov ah,0 ; Hi Byte = 0 - PUSH AX ; Push # Pages - - CALL f SET_VGA_MODEX ; Set up Mode X! - -@SMX_Exit: - ;POPx SI, BP ; Restore Registers - pop si - pop bp - 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 - push bp - push di - 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 - pop di - pop bp - 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 - push bp - push di - 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, 1 ; X offset (Bytes) = Xpos/4 - SHR BX, 1 ; 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 - pop di - pop bp - 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 - push bp - push di - 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, 1 ; X offset (Bytes) = Xpos/4 - SHR BX, 1 ; 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 - - mov ah,0 ; Clear Return Value Hi byte - MOV AL, ES:[DI+BX] ; Get Color of Pixel - - ;POPx DI, BP ; Restore Saved Registers - pop di - pop bp - 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 ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; 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 - push bp - push ds - push si - push di - 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, 1 ; DX/4 = Bytes into Line - SHR DX, 1 ; DX/4 = Bytes into Line - ADD DI, DX ; DI = Addr of Upper-Left Corner - - MOV CX, BX ; CX = X2 (Pixel Position) - SHR CX, 1 ; CX/4 = Bytes into Line - SHR CX, 1 ; 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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, BP - DW ?x1 ; DI, SI, BP - DW ?x1 ; 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 - push bp - push si - push di - 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, 1 ; Get X1 Byte # (=X1/4) - SHR CX, 1 ; Get X2 Byte # (=X2/4) - SHR AX, 1 ; Get X1 Byte # (=X1/4) - SHR CX, 1 ; 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, 1 ; DI = Xpos/4 - SHR DI, 1 ; 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, 1 ; /4 = Byte Offset into Line - SHR AX, 1 ; /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: - mov ax,0 ; 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: - mov ax,0 ; 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: - mov ax,0 ; 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: - mov ax,0 ; 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 - pop di - pop si - pop bp - 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 - mov ax,0 ; 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 ?x1 ; BP, DS, SI - DW ?x1 ; BP, DS, SI - DW ?x1 ; 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 - push bp - push ds - push si - 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 - - mov ax,0, 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 - pop si - pop ds - pop bp - 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 ?x1 ; BP, ES, DI - DW ?x1 ; BP, ES, DI - DW ?x1 ; 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 - push bp - push es - push di - 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 - - mov ax,0, 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 - pop di - pop es - pop bp - 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, 1 ; CX / 4 = Bytes into Line - SHR CX, 1 ; 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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, 1 ; Bytes into Line = Xpos/4 - SHR AX, 1 ; 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, 1 ; * 8 Bytes Per Bitmap - SHL AX, 1 ; * 8 Bytes Per Bitmap - SHL AX, 1 ; * 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... - - mov ax,0 ; Clear AX - - ;mov bl,0 ; Clear BL - mov bl,0 - 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, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; 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, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; 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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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, 1 ; Bytes into Line = Xpos/4 - SHR AX, 1 ; 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, 1 ; * 8 Bytes Per Bitmap - SHL AX, 1 ; * 8 Bytes Per Bitmap - SHL AX, 1 ; * 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 - - mov bl,0 ; 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, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; 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, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; Shift 4 bits - ROL BX, 1 ; 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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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, 1 ; Xpos/4 = Offset Into Line - SHR BX, 1 ; 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, 1 ; /4 = width in bands - SHR BX, 1 ; /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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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, 1 ; Xpos/4 = Offset Into Line - SHR BX, 1 ; 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, 1 ; /4 = width in bands - SHR BX, 1 ; /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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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 - pop di - pop si - pop ds - pop bp - 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 ?x1 ; DI, SI, DS, BP - DW ?x1 ; DI, SI, DS, BP - DW ?x1 ; DS, DI, SI, BP - DW ?x1 ; DS, DI, SI, 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 - push bp - push ds - push si - push di - 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, 1 ; Get X2 Band (X2 / 4) - SHR DX, 1 ; Get X1 Band (X1 / 4) - SHR AX, 1 ; Get X2 Band (X2 / 4) - SHR DX, 1 ; 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, 1 ; X1 / 4 = Byte offset - SHR AX, 1 ; 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, 1 ; X1 / 4 = Byte offset - SHR AX, 1 ; 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: - mov ax,0 ; 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 - mov bx,0 ; 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 - mov bx,0 ; 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 - pop di - pop si - pop ds - pop bp - RET 16 ; Exit and Clean up Stack - -COPY_BITMAP ENDP - - END ; End of Code Segment