+++ /dev/null
-;========================================================\r
-; MODEX.ASM - A Complete Mode X Library\r
-;\r
-; Version 1.04 Release, 3 May 1993, By Matt Pritchard\r
-; With considerable input from Michael Abrash\r
-;\r
-; The following information is donated to the public domain in\r
-; the hopes that save other programmers much frustration.\r
-;\r
-; If you do use this code in a product, it would be nice if\r
-; you include a line like "Mode X routines by Matt Pritchard"\r
-; in the credits.\r
-;\r
-; =========================================================\r
-;\r
-; All of this code is designed to be assembled with MASM 5.10a\r
-; but TASM 3.0 could be used as well.\r
-;\r
-; The routines contained are designed for use in a MEDIUM model\r
-; program. All Routines are FAR, and is assumed that a DGROUP\r
-; data segment exists and that DS will point to it on entry.\r
-;\r
-; For all routines, the AX, BX, CX, DX, ES and FLAGS registers\r
-; will not be preserved, while the DS, BP, SI and DI registers\r
-; will be preserved.\r
-;\r
-; Unless specifically noted, All Parameters are assumed to be\r
-; "PASSED BY VALUE". That is, the actual value is placed on\r
-; the stack. When a reference is passed it is assumed to be\r
-; a near pointer to a variable in the DGROUP segment.\r
-;\r
-; Routines that return a single 16-Bit integer value will\r
-; return that value in the AX register.\r
-;\r
-; This code will *NOT* run on an 8086/8088 because 80286+\r
-; specific instructions are used. If you have an 8088/86\r
-; and VGA, you can buy an 80386-40 motherboard for about\r
-; $160 and move into the 90's.\r
-;\r
-; This code is reasonably optimized: Most drawing loops have\r
-; been unrolled once and memory references are minimized by\r
-; keeping stuff in registers when possible.\r
-;\r
-; Error Trapping varies by Routine. No Clipping is performed\r
-; so the caller should verify that all coordinates are valid.\r
-;\r
-; Several Macros are used to simplify common 2 or 3 instruction\r
-; sequences. Several Single letter Text Constants also\r
-; simplify common assembler expressions like "WORD PTR".\r
-;\r
-; ------------------ Mode X Variations ------------------\r
-;\r
-; Mode # Screen Size Max Pages Aspect Ratio (X:Y)\r
-;\r
-; 0 320 x 200 4 Pages 1.2:1\r
-; 1 320 x 400 2 Pages 2.4:1\r
-; 2 360 x 200 3 Pages 1.35:1\r
-; 3 360 x 400 1 Page 2.7:1\r
-; 4 320 x 240 3 Pages 1:1\r
-; 5 320 x 480 1 Page 2:1\r
-; 6 360 x 240 3 Pages 1.125:1\r
-; 7 360 x 480 1 Page 2.25:1\r
-;\r
-; -------------------- The Legal Stuff ------------------\r
-;\r
-; No warranty, either written or implied, is made as to\r
-; the accuracy and usability of this code product. Use\r
-; at your own risk. Batteries not included. Pepperoni\r
-; and extra cheese available for an additional charge.\r
-;\r
-; ----------------------- The Author --------------------\r
-;\r
-; Matt Pritchard is a paid programmer who'd rather be\r
-; writing games. He can be reached at: P.O. Box 140264,\r
-; Irving, TX 75014 USA. Michael Abrash is a living\r
-; god, who now works for Bill Gates (Microsoft).\r
-;\r
-; -------------------- Revision History -----------------\r
-; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI\r
-; SET_MODEX now saves SI\r
-; 5-3-93: v1.04 - added LOAD_DAC_REGISTERS and\r
-; READ_DAC_REGISTERS. Expanded CLR Macro\r
-; to handle multiple registers\r
-;\r
-\r
- PAGE 255, 132\r
-\r
- .MODEL Huge\r
- ;.286\r
-\r
- ; ===== MACROS =====\r
-\r
- ; Macro to OUT a 16 bit value to an I/O port\r
-\r
-OUT_16 MACRO Register, Value\r
- IFDIFI <Register>, <DX> ; If DX not setup\r
- MOV DX, Register ; then Select Register\r
- ENDIF\r
- IFDIFI <Value>, <AX> ; If AX not setup\r
- MOV AX, Value ; then Get Data Value\r
- ENDIF\r
- OUT DX, AX ; Set I/O Register(s)\r
-ENDM\r
-\r
- ; Macro to OUT a 8 bit value to an I/O Port\r
-\r
-OUT_8 MACRO Register, Value\r
- IFDIFI <Register>, <DX> ; If DX not setup\r
- MOV DX, Register ; then Select Register\r
- ENDIF\r
- IFDIFI <Value>, <AL> ; If AL not Setup\r
- MOV AL, Value ; then Get Data Value\r
- ENDIF\r
- OUT DX, AL ; Set I/O Register\r
-ENDM\r
-\r
- ; macros to PUSH and POP multiple registers\r
-\r
-; PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
-; IFNB <R1>\r
-; PUSH R1 ; Save R1\r
-; PUSHx R2, R3, R4, R5, R6, R7, R8\r
-; ENDIF\r
-; ENDM\r
-;\r
-; POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8\r
-; IFNB <R1>\r
-; POP R1 ; Restore R1\r
-; POPx R2, R3, R4, R5, R6, R7, R8\r
-; ENDIF\r
-; ENDM\r
-\r
- ; Macro to Clear Registers to 0\r
-\r
-; CLR MACRO Register, R2, R3, R4;, R5, R6\r
-; IFNB <Register>\r
-; XOR Register, Register ; Set Register = 0\r
-; CLR R2, R3, R4;, R5, R6\r
-; ENDIF\r
-; ENDM\r
-\r
- ; Macros to Decrement Counter & Jump on Condition\r
-\r
-LOOPx MACRO Register, Destination\r
- DEC Register ; Counter--\r
- JNZ Destination ; Jump if not 0\r
-ENDM\r
-\r
-LOOPjz MACRO Register, Destination\r
- DEC Register ; Counter--\r
- JZ Destination ; Jump if 0\r
-ENDM\r
-\r
-\r
- ; ===== General Constants =====\r
-\r
- False EQU 0\r
- True EQU -1\r
- nil EQU 0\r
-\r
- b EQU BYTE PTR\r
- w EQU WORD PTR\r
- d EQU DWORD PTR\r
- o EQU OFFSET\r
- f EQU FAR PTR\r
- s EQU SHORT\r
- ?x1 EQU <?>\r
-\r
- ; ===== VGA Register Values =====\r
-\r
- VGA_Segment EQU 0A000h ; Vga Memory Segment\r
-\r
- ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller\r
- GC_Index EQU 03CEh ; VGA Graphics Controller\r
- SC_Index EQU 03C4h ; VGA Sequencer Controller\r
- SC_Data EQU 03C5h ; VGA Sequencer Data Port\r
- CRTC_Index EQU 03D4h ; VGA CRT Controller\r
- CRTC_Data EQU 03D5h ; VGA CRT Controller Data\r
- MISC_OUTPUT EQU 03C2h ; VGA Misc Register\r
- INPUT_1 EQU 03DAh ; Input Status #1 Register\r
-\r
- DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register\r
- DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register\r
- PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W\r
-\r
- PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg\r
- MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg\r
- READ_MAP EQU 004h ; GC Index: Read Map Register\r
- START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi\r
- START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo\r
-\r
- MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1\r
- MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1\r
- ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes\r
-\r
- CHAIN4_OFF EQU 00604h ; Chain 4 mode Off\r
- ASYNC_RESET EQU 00100h ; (A)synchronous Reset\r
- SEQU_RESTART EQU 00300h ; Sequencer Restart\r
-\r
- LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches\r
- LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU\r
-\r
- VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit\r
- PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane #\r
- ALL_PLANES EQU 0Fh ; All Bit Planes Selected\r
- CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data\r
-\r
- GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set\r
- ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer\r
- ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer\r
-\r
- ; Constants Specific for these routines\r
-\r
- NUM_MODES EQU 8 ; # of Mode X Variations\r
-\r
- ; Specific Mode Data Table format...\r
-\r
-Mode_Data_Table STRUC\r
- M_MiscR DB ? ; Value of MISC_OUTPUT register\r
- M_Pages DB ? ; Maximum Possible # of pages\r
- M_XSize DW ? ; X Size Displayed on screen\r
- M_YSize DW ? ; Y Size Displayed on screen\r
- M_XMax DW ? ; Maximum Possible X Size\r
- M_YMax DW ? ; Maximum Possible Y Size\r
- M_CRTC DW ? ; Table of CRTC register values\r
-Mode_Data_Table ENDS\r
-\r
- ; ===== DGROUP STORAGE NEEDED (42 BYTES) =====\r
-\r
- .DATA?\r
-\r
-SCREEN_WIDTH DW 0 ; Width of a line in Bytes\r
-SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels\r
-\r
-LAST_PAGE DW 0 ; # of Display Pages\r
-PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page\r
-\r
-PAGE_SIZE DW 0 ; Size of Page in Addr Bytes\r
-\r
-DISPLAY_PAGE DW 0 ; Page # currently displayed\r
-ACTIVE_PAGE DW 0 ; Page # currently active\r
-\r
-CURRENT_PAGE DW 0 ; Offset of current Page\r
-CURRENT_SEGMENT DW 0 ; Segment of VGA memory\r
-\r
-CURRENT_XOFFSET DW 0 ; Current Display X Offset\r
-CURRENT_YOFFSET DW 0 ; Current Display Y Offset\r
-\r
-CURRENT_MOFFSET DW 0 ; Current Start Offset\r
-\r
-MAX_XOFFSET DW 0 ; Current Display X Offset\r
-MAX_YOFFSET DW 0 ; Current Display Y Offset\r
-\r
-CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127\r
-CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255\r
-\r
- .CODE\r
-\r
- ; ===== DATA TABLES =====\r
-\r
- ; Data Tables, Put in Code Segment for Easy Access\r
- ; (Like when all the other Segment Registers are in\r
- ; use!!) and reduced DGROUP requirements...\r
-\r
- ; Bit Mask Tables for Left/Right/Character Masks\r
-\r
-Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H\r
-\r
-Right_Clip_Mask DB 01H, 03H, 07H, 0FH\r
-\r
- ; Bit Patterns for converting character fonts\r
-\r
-Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH\r
- DB 01H,09H,05H,0DH,03H,0BH,07H,0FH\r
-\r
- ; CRTC Register Values for Various Configurations\r
-\r
-MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes\r
- DW 04009H ; Cell Height (1 Scan Line)\r
- DW 00014H ; Dword Mode off\r
- DW 0E317H ; turn on Byte Mode\r
- DW nil ; End of CRTC Data for 400/480 Line Mode\r
-\r
-MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes\r
- DW 04109H ; Cell Height (2 Scan Lines)\r
- DW 00014H ; Dword Mode off\r
- DW 0E317H ; turn on Byte Mode\r
- DW nil ; End of CRTC Data for 200/240 Line Mode\r
-\r
-MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels\r
- DW 05F00H ; Horz total\r
- DW 04F01H ; Horz Displayed\r
- DW 05002H ; Start Horz Blanking\r
- DW 08203H ; End Horz Blanking\r
- DW 05404H ; Start H Sync\r
- DW 08005H ; End H Sync\r
- DW nil ; End of CRTC Data for 320 Horz pixels\r
-\r
-MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels\r
- DW 06B00H ; Horz total\r
- DW 05901H ; Horz Displayed\r
- DW 05A02H ; Start Horz Blanking\r
- DW 08E03H ; End Horz Blanking\r
- DW 05E04H ; Start H Sync\r
- DW 08A05H ; End H Sync\r
- DW nil ; End of CRTC Data for 360 Horz pixels\r
-\r
-MODE_200_Tall:\r
-MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes\r
- DW 0BF06H ; Vertical Total\r
- DW 01F07H ; Overflow\r
- DW 09C10H ; V Sync Start\r
- DW 08E11H ; V Sync End/Prot Cr0 Cr7\r
- DW 08F12H ; Vertical Displayed\r
- DW 09615H ; V Blank Start\r
- DW 0B916H ; V Blank End\r
- DW nil ; End of CRTC Data for 200/400 Lines\r
-\r
-MODE_240_Tall:\r
-MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes\r
- DW 00D06H ; Vertical Total\r
- DW 03E07H ; Overflow\r
- DW 0EA10H ; V Sync Start\r
- DW 08C11H ; V Sync End/Prot Cr0 Cr7\r
- DW 0DF12H ; Vertical Displayed\r
- DW 0E715H ; V Blank Start\r
- DW 00616H ; V Blank End\r
- DW nil ; End of CRTC Data for 240/480 Lines\r
-\r
- ; Table of Display Mode Tables\r
-\r
-MODE_TABLE:\r
- DW o MODE_320x200, o MODE_320x400\r
- DW o MODE_360x200, o MODE_360x400\r
- DW o MODE_320x240, o MODE_320x480\r
- DW o MODE_360x240, o MODE_360x480\r
-\r
- ; Table of Display Mode Components\r
-\r
-MODE_320x200: ; Data for 320 by 200 Pixels\r
-\r
- DB 063h ; 400 scan Lines & 25 Mhz Clock\r
- DB 4 ; Maximum of 4 Pages\r
- DW 320, 200 ; Displayed Pixels (X,Y)\r
- DW 1302, 816 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_320_Wide, o MODE_200_Tall\r
- DW o MODE_Double_Line, nil\r
-\r
-MODE_320x400: ; Data for 320 by 400 Pixels\r
-\r
- DB 063h ; 400 scan Lines & 25 Mhz Clock\r
- DB 2 ; Maximum of 2 Pages\r
- DW 320, 400 ; Displayed Pixels X,Y\r
- DW 648, 816 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_320_Wide, o MODE_400_Tall\r
- DW o MODE_Single_Line, nil\r
-\r
-MODE_360x240: ; Data for 360 by 240 Pixels\r
-\r
- DB 0E7h ; 480 scan Lines & 28 Mhz Clock\r
- DB 3 ; Maximum of 3 Pages\r
- DW 360, 240 ; Displayed Pixels X,Y\r
- DW 1092, 728 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_360_Wide, o MODE_240_Tall\r
- DW o MODE_Double_Line , nil\r
-\r
-MODE_360x480: ; Data for 360 by 480 Pixels\r
-\r
- DB 0E7h ; 480 scan Lines & 28 Mhz Clock\r
- DB 1 ; Only 1 Page Possible\r
- DW 360, 480 ; Displayed Pixels X,Y\r
- DW 544, 728 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_360_Wide, o MODE_480_Tall\r
- DW o MODE_Single_Line , nil\r
-\r
-MODE_320x240: ; Data for 320 by 240 Pixels\r
-\r
- DB 0E3h ; 480 scan Lines & 25 Mhz Clock\r
- DB 3 ; Maximum of 3 Pages\r
- DW 320, 240 ; Displayed Pixels X,Y\r
- DW 1088, 818 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_320_Wide, o MODE_240_Tall\r
- DW o MODE_Double_Line, nil\r
-\r
-MODE_320x480: ; Data for 320 by 480 Pixels\r
-\r
- DB 0E3h ; 480 scan Lines & 25 Mhz Clock\r
- DB 1 ; Only 1 Page Possible\r
- DW 320, 480 ; Displayed Pixels X,Y\r
- DW 540, 818 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_320_WIDE, o MODE_480_Tall\r
- DW o MODE_Single_Line, nil\r
-\r
-MODE_360x200: ; Data for 360 by 200 Pixels\r
-\r
- DB 067h ; 400 scan Lines & 28 Mhz Clock\r
- DB 3 ; Maximum of 3 Pages\r
- DW 360, 200 ; Displayed Pixels (X,Y)\r
- DW 1302, 728 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_360_Wide, MODE_200_Tall\r
- DW o MODE_Double_Line, nil\r
-\r
-MODE_360x400: ; Data for 360 by 400 Pixels\r
-\r
- DB 067h ; 400 scan Lines & 28 Mhz Clock\r
- DB 1 ; Maximum of 1 Pages\r
- DW 360, 400 ; Displayed Pixels X,Y\r
- DW 648, 816 ; Max Possible X and Y Sizes\r
-\r
- DW o MODE_360_Wide, MODE_400_Tall\r
- DW o MODE_Single_Line, nil\r
-\r
-\r
- ; ===== MODE X SETUP ROUTINES =====\r
-\r
-;======================================================\r
-;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%)\r
-;======================================================\r
-;\r
-; Sets Up the specified version of Mode X. Allows for\r
-; the setup of multiple video pages, and a virtual\r
-; screen which can be larger than the displayed screen\r
-; (which can then be scrolled a pixel at a time)\r
-;\r
-; ENTRY: ModeType = Desired Screen Resolution (0-7)\r
-;\r
-; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio\r
-; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio\r
-; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio\r
-; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio\r
-; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio\r
-; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio\r
-; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio\r
-; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio\r
-;\r
-; MaxXpos = The Desired Virtual Screen Width\r
-; MaxYpos = The Desired Virtual Screen Height\r
-; Pages = The Desired # of Video Pages\r
-;\r
-; EXIT: AX = Success Flag: >0 = Failure / 0 = Success\r
-;\r
-\r
-SVM_STACK STRUC\r
- SVM_Table DW ? ; Offset of Mode Info Table\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DD ? ; Caller\r
- SVM_Pages DW ? ; # of Screen Pages desired\r
- SVM_Ysize DW ? ; Vertical Screen Size Desired\r
- SVM_Xsize DW ? ; Horizontal Screen Size Desired\r
- SVM_Mode DW ? ; Display Resolution Desired\r
-SVM_STACK ENDS\r
-\r
- PUBLIC SET_VGA_MODEX\r
-\r
-SET_VGA_MODEX PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- SUB SP, 2 ; Allocate workspace\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- ; Check Legality of Mode Request....\r
-\r
- MOV BX, [BP].SVM_Mode ; Get Requested Mode #\r
- CMP BX, NUM_MODES ; Is it 0..7?\r
- JAE @SVM_BadModeSetup1 ; If Not, Error out\r
-\r
- SHL BX, 1 ; Scale BX\r
- MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info\r
- MOV [BP].SVM_Table, SI ; Save ptr for later use\r
-\r
- ; Check # of Requested Display Pages\r
-\r
- MOV CX, [BP].SVM_Pages ; Get # of Requested Pages\r
- ;CLR CH ; Set Hi Word = 0!\r
- mov ch,0 ; Set Hi Word = 0!\r
- CMP CL, CS:[SI].M_Pages ; Check # Pages for mode\r
- JA @SVM_BadModeSetup2 ; Report Error if too Many Pages\r
- JCXZ @SVM_BadModeSetup3 ; Report Error if 0 Pages\r
-\r
- ; Check Validity of X Size\r
-\r
- AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0\r
-\r
- MOV AX, [BP].SVM_XSize ; Get Logical Screen Width\r
- CMP AX, CS:[SI].M_XSize ; Check against Displayed X\r
- JB @SVM_BadModeSetup4 ; Report Error if too small\r
- CMP AX, CS:[SI].M_XMax ; Check against Max X\r
- JA @SVM_BadModeSetup5 ; Report Error if too big\r
-\r
- ; Check Validity of Y Size\r
-\r
- MOV BX, [BP].SVM_YSize ; Get Logical Screen Height\r
- CMP BX, CS:[SI].M_YSize ; Check against Displayed Y\r
- JB @SVM_BadModeSetup6 ; Report Error if too small\r
- CMP BX, CS:[SI].M_YMax ; Check against Max Y\r
- JA @SVM_BadModeSetup7 ; Report Error if too big\r
-\r
- ; Enough memory to Fit it all?\r
-\r
- SHR AX, 1 ; # of Bytes:Line = XSize/4\r
- SHR AX, 1 ; # of Bytes:Line = XSize/4\r
- MUL CX ; AX = Bytes/Line * Pages\r
- MUL BX ; DX:AX = Total VGA mem needed\r
- JNO @SVM_Continue ; Exit if Total Size > 256K\r
-\r
- DEC DX ; Was it Exactly 256K???\r
- OR DX, AX ; (DX = 1, AX = 0000)\r
- JZ @SVM_Continue ; if so, it's valid...\r
-\r
- jmp @SVM_Continue;0000\r
-\r
-@SVM_BadModeSetup:\r
- mov ax,8 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-@SVM_BadModeSetup1:\r
- mov ax,1 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-@SVM_BadModeSetup2:\r
- mov ax,2 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-@SVM_BadModeSetup3:\r
- mov ax,3 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-@SVM_BadModeSetup4:\r
- mov ax,4 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-@SVM_BadModeSetup5:\r
- mov ax,5 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-@SVM_BadModeSetup6:\r
- mov ax,6 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-@SVM_BadModeSetup7:\r
- mov ax,7 ; Return Value = False\r
- JMP @SVM_Exit ; Normal Exit\r
-\r
-@SVM_Continue:\r
-\r
- MOV AX, 13H ; Start with Mode 13H\r
- INT 10H ; Let BIOS Set Mode\r
-\r
- OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode\r
- OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset\r
- OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size\r
- OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ...\r
-\r
- OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register\r
- INC DX ; Point to Data\r
- IN AL, DX ; Get Value, Bit 7 = Protect\r
- AND AL, 7FH ; Mask out Write Protect\r
- OUT DX, AL ; And send it back\r
-\r
- MOV DX, CRTC_INDEX ; Vga Crtc Registers\r
- ADD SI, M_CRTC ; SI -> CRTC Parameter Data\r
-\r
- ; Load Tables of CRTC Parameters from List of Tables\r
-\r
-@SVM_Setup_Table:\r
-\r
- MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl\r
- ADD SI, 2 ; Point to next Ptr Entry\r
- OR DI, DI ; A nil Ptr means that we have\r
- JZ @SVM_Set_Data ; finished CRTC programming\r
-\r
-@SVM_Setup_CRTC:\r
- MOV AX, CS:[DI] ; Get CRTC Data from Table\r
- ADD DI, 2 ; Advance Pointer\r
- OR AX, AX ; At End of Data Table?\r
- JZ @SVM_Setup_Table ; If so, Exit & get next Table\r
-\r
- OUT DX, AX ; Reprogram VGA CRTC reg\r
- JMP s @SVM_Setup_CRTC ; Process Next Table Entry\r
-\r
- ; Initialize Page & Scroll info, DI = 0\r
-\r
-@SVM_Set_Data:\r
- MOV DISPLAY_PAGE, DI ; Display Page = 0\r
- MOV ACTIVE_PAGE, DI ; Active Page = 0\r
- MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0\r
- MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0\r
- MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0\r
- MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0\r
-\r
- MOV AX, VGA_SEGMENT ; Segment for VGA memory\r
- MOV CURRENT_SEGMENT, AX ; Save for Future LES's\r
-\r
- ; Set Logical Screen Width, X Scroll and Our Data\r
-\r
- MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info\r
- MOV AX, [BP].SVM_Xsize ; Get Display Width\r
-\r
- MOV CX, AX ; CX = Logical Width\r
- SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value\r
- MOV MAX_XOFFSET, CX ; Set Maximum X Scroll\r
-\r
- SHR AX, 1 ; Bytes = Pixels / 4\r
- SHR AX, 1 ; Bytes = Pixels / 4\r
- MOV SCREEN_WIDTH, AX ; Save Width in Pixels\r
-\r
- SHR AX, 1 ; Offset Value = Bytes / 2\r
- MOV AH, 13h ; CRTC Offset Register Index\r
- XCHG AL, AH ; Switch format for OUT\r
- OUT DX, AX ; Set VGA CRTC Offset Reg\r
-\r
- ; Setup Data table, Y Scroll, Misc for Other Routines\r
-\r
- MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height\r
-\r
- MOV CX, AX ; CX = Logical Height\r
- SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value\r
- MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll\r
-\r
- MOV SCREEN_HEIGHT, AX ; Save Height in Pixels\r
- MUL SCREEN_WIDTH ; AX = Page Size in Bytes,\r
- MOV PAGE_SIZE, AX ; Save Page Size\r
-\r
- MOV CX, [BP].SVM_Pages ; Get # of Pages\r
- MOV LAST_PAGE, CX ; Save # of Pages\r
-\r
- mov bx,0 ; Page # = 0\r
- MOV DX, BX ; Page 0 Offset = 0\r
-\r
-@SVM_Set_Pages:\r
-\r
- MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset\r
- ADD BX, 2 ; Page#++\r
- ADD DX, AX ; Compute Addr of Next Page\r
- LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set\r
-\r
- ; Clear VGA Memory\r
-\r
- OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes\r
- LES DI, d CURRENT_PAGE ; -> Start of VGA memory\r
-\r
- mov ax,0 ; AX = 0\r
- CLD ; Block Xfer Forwards\r
- MOV CX, 8000H ; 32K * 4 * 2 = 256K\r
- REP STOSW ; Clear dat memory!\r
-\r
- ; Setup Font Pointers\r
-\r
- MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127\r
- MOV AX, GET_CHAR_PTR ; Service to Get Pointer\r
- INT 10h ; Call VGA BIOS\r
-\r
- MOV CHARSET_LOW, BP ; Save Char Set Offset\r
- MOV CHARSET_LOW+2, ES ; Save Char Set Segment\r
-\r
- MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255\r
- MOV AX, GET_CHAR_PTR ; Service to Get Pointer\r
- INT 10h ; Call VGA BIOS\r
-\r
- MOV CHARSET_HI, BP ; Save Char Set Offset\r
- MOV CHARSET_HI+2, ES ; Save Char Set Segment\r
-\r
- MOV AX, True ; Return Success Code\r
-\r
-@SVM_EXIT:\r
- ADD SP, 2 ; Deallocate workspace\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 8 ; Exit & Clean Up Stack\r
-\r
-SET_VGA_MODEX ENDP\r
-\r
-\r
-;==================\r
-;SET_MODEX% (Mode%)\r
-;==================\r
-;\r
-; Quickie Mode Set - Sets Up Mode X to Default Configuration\r
-;\r
-; ENTRY: ModeType = Desired Screen Resolution (0-7)\r
-; (See SET_VGA_MODEX for list)\r
-;\r
-; EXIT: AX = Success Flag: 0 = Failure / -1= Success\r
-;\r
-\r
-SM_STACK STRUC\r
- DW ?,? ; BP, SI\r
- DD ? ; Caller\r
- SM_Mode DW ? ; Desired Screen Resolution\r
-SM_STACK ENDS\r
-\r
- PUBLIC SET_MODEX\r
-\r
-SET_MODEX PROC FAR\r
-\r
- ;PUSHx BP, SI ; Preserve Important registers\r
- push bp\r
- push si\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- mov ax,0 ; Assume Failure\r
- MOV BX, [BP].SM_Mode ; Get Desired Mode #\r
- CMP BX, NUM_MODES ; Is it a Valid Mode #?\r
- JAE @SMX_Exit ; If Not, don't Bother\r
-\r
- PUSH BX ; Push Mode Parameter\r
-\r
- SHL BX, 1 ; Scale BX to word Index\r
- MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info\r
-\r
- PUSH CS:[SI].M_XSize ; Push Default X Size\r
- PUSH CS:[SI].M_Ysize ; Push Default Y size\r
- MOV AL, CS:[SI].M_Pages ; Get Default # of Pages\r
- mov ah,0 ; Hi Byte = 0\r
- PUSH AX ; Push # Pages\r
-\r
- CALL f SET_VGA_MODEX ; Set up Mode X!\r
-\r
-@SMX_Exit:\r
- ;POPx SI, BP ; Restore Registers\r
- pop si\r
- pop bp\r
- RET 2 ; Exit & Clean Up Stack\r
-\r
-SET_MODEX ENDP\r
-\r
-\r
- ; ===== BASIC GRAPHICS PRIMITIVES =====\r
-\r
-;============================\r
-;CLEAR_VGA_SCREEN (ColorNum%)\r
-;============================\r
-;\r
-; Clears the active display page\r
-;\r
-; ENTRY: ColorNum = Color Value to fill the page with\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-CVS_STACK STRUC\r
- DW ?,? ; DI, BP\r
- DD ? ; Caller\r
- CVS_COLOR DB ?,? ; Color to Set Screen to\r
-CVS_STACK ENDS\r
-\r
- PUBLIC CLEAR_VGA_SCREEN\r
-\r
-CLEAR_VGA_SCREEN PROC FAR\r
-\r
- ;PUSHx BP, DI ; Preserve Important Registers\r
- push bp\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
-\r
- MOV AL, [BP].CVS_COLOR ; Get Color\r
- MOV AH, AL ; Copy for Word Write\r
- CLD ; Block fill Forwards\r
-\r
- MOV CX, PAGE_SIZE ; Get Size of Page\r
- SHR CX, 1 ; Divide by 2 for Words\r
- REP STOSW ; Block Fill VGA memory\r
-\r
- ;POPx DI, BP ; Restore Saved Registers\r
- pop di\r
- pop bp\r
- RET 2 ; Exit & Clean Up Stack\r
-\r
-CLEAR_VGA_SCREEN ENDP\r
-\r
-\r
-;===================================\r
-;SET_POINT (Xpos%, Ypos%, ColorNum%)\r
-;===================================\r
-;\r
-; Plots a single Pixel on the active display page\r
-;\r
-; ENTRY: Xpos = X position to plot pixel at\r
-; Ypos = Y position to plot pixel at\r
-; ColorNum = Color to plot pixel with\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-SP_STACK STRUC\r
- DW ?,? ; BP, DI\r
- DD ? ; Caller\r
- SETP_Color DB ?,? ; Color of Point to Plot\r
- SETP_Ypos DW ? ; Y pos of Point to Plot\r
- SETP_Xpos DW ? ; X pos of Point to Plot\r
-SP_STACK ENDS\r
-\r
- PUBLIC SET_POINT\r
-\r
-SET_POINT PROC FAR\r
-\r
- ;PUSHx BP, DI ; Preserve Registers\r
- push bp\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
-\r
- MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel\r
- MUL SCREEN_WIDTH ; Get Offset to Start of Line\r
-\r
- MOV BX, [BP].SETP_Xpos ; Get Xpos\r
- MOV CX, BX ; Copy to extract Plane # from\r
- SHR BX, 1 ; X offset (Bytes) = Xpos/4\r
- SHR BX, 1 ; X offset (Bytes) = Xpos/4\r
- ADD BX, AX ; Offset = Width*Ypos + Xpos/4\r
-\r
- MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register\r
- AND CL, PLANE_BITS ; Get Plane Bits\r
- SHL AH, CL ; Get Plane Select Value\r
- OUT_16 SC_Index, AX ; Select Plane\r
-\r
- MOV AL,[BP].SETP_Color ; Get Pixel Color\r
- MOV ES:[DI+BX], AL ; Draw Pixel\r
-\r
- ;POPx DI, BP ; Restore Saved Registers\r
- pop di\r
- pop bp\r
- RET 6 ; Exit and Clean up Stack\r
-\r
-SET_POINT ENDP\r
-\r
-\r
-;==========================\r
-;READ_POINT% (Xpos%, Ypos%)\r
-;==========================\r
-;\r
-; Read the color of a pixel from the Active Display Page\r
-;\r
-; ENTRY: Xpos = X position of pixel to read\r
-; Ypos = Y position of pixel to read\r
-;\r
-; EXIT: AX = Color of Pixel at (Xpos, Ypos)\r
-;\r
-\r
-RP_STACK STRUC\r
- DW ?,? ; BP, DI\r
- DD ? ; Caller\r
- RP_Ypos DW ? ; Y pos of Point to Read\r
- RP_Xpos DW ? ; X pos of Point to Read\r
-RP_STACK ENDS\r
-\r
- PUBLIC READ_POINT\r
-\r
-READ_POINT PROC FAR\r
-\r
- ;PUSHx BP, DI ; Preserve Registers\r
- push bp\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
-\r
- MOV AX, [BP].RP_Ypos ; Get Line # of Pixel\r
- MUL SCREEN_WIDTH ; Get Offset to Start of Line\r
-\r
- MOV BX, [BP].RP_Xpos ; Get Xpos\r
- MOV CX, BX\r
- SHR BX, 1 ; X offset (Bytes) = Xpos/4\r
- SHR BX, 1 ; X offset (Bytes) = Xpos/4\r
- ADD BX, AX ; Offset = Width*Ypos + Xpos/4\r
-\r
- MOV AL, READ_MAP ; GC Read Mask Register\r
- MOV AH, CL ; Get Xpos\r
- AND AH, PLANE_BITS ; & mask out Plane #\r
- OUT_16 GC_INDEX, AX ; Select Plane to read in\r
-\r
- mov ah,0 ; Clear Return Value Hi byte\r
- MOV AL, ES:[DI+BX] ; Get Color of Pixel\r
-\r
- ;POPx DI, BP ; Restore Saved Registers\r
- pop di\r
- pop bp\r
- RET 4 ; Exit and Clean up Stack\r
-\r
-READ_POINT ENDP\r
-\r
-\r
-;======================================================\r
-;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)\r
-;======================================================\r
-;\r
-; Fills a rectangular block on the active display Page\r
-;\r
-; ENTRY: Xpos1 = Left X position of area to fill\r
-; Ypos1 = Top Y position of area to fill\r
-; Xpos2 = Right X position of area to fill\r
-; Ypos2 = Bottom Y position of area to fill\r
-; ColorNum = Color to fill area with\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-FB_STACK STRUC\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- FB_Color DB ?,? ; Fill Color\r
- FB_Ypos2 DW ? ; Y pos of Lower Right Pixel\r
- FB_Xpos2 DW ? ; X pos of Lower Right Pixel\r
- FB_Ypos1 DW ? ; Y pos of Upper Left Pixel\r
- FB_Xpos1 DW ? ; X pos of Upper Left Pixel\r
-FB_STACK ENDS\r
-\r
- PUBLIC FILL_BLOCK\r
-\r
-FILL_BLOCK PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
- CLD ; Direction Flag = Forward\r
-\r
- OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select\r
-\r
- ; Validate Pixel Coordinates\r
- ; If necessary, Swap so X1 <= X2, Y1 <= Y2\r
-\r
- MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2?\r
- MOV BX, [BP].FB_Ypos2 ; BX = Y2\r
- CMP AX, BX\r
- JLE @FB_NOSWAP1\r
-\r
- MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1\r
- XCHG AX, BX ; on stack for future use\r
-\r
-@FB_NOSWAP1:\r
- SUB BX, AX ; Get Y width\r
- INC BX ; Add 1 to avoid 0 value\r
- MOV [BP].FB_Ypos2, BX ; Save in Ypos2\r
-\r
- MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line\r
- ADD DI, AX ; DI = Start of Line Y1\r
-\r
- MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2\r
- MOV BX, [BP].FB_Xpos2 ;\r
- CMP AX, BX\r
- JLE @FB_NOSWAP2 ; Skip Ahead if Ok\r
-\r
- MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2\r
- XCHG AX, BX ; on stack for future use\r
-\r
- ; All our Input Values are in order, Now determine\r
- ; How many full "bands" 4 pixels wide (aligned) there\r
- ; are, and if there are partial bands (<4 pixels) on\r
- ; the left and right edges.\r
-\r
-@FB_NOSWAP2:\r
- MOV DX, AX ; DX = X1 (Pixel Position)\r
- SHR DX, 1 ; DX/4 = Bytes into Line\r
- SHR DX, 1 ; DX/4 = Bytes into Line\r
- ADD DI, DX ; DI = Addr of Upper-Left Corner\r
-\r
- MOV CX, BX ; CX = X2 (Pixel Position)\r
- SHR CX, 1 ; CX/4 = Bytes into Line\r
- SHR CX, 1 ; CX/4 = Bytes into Line\r
-\r
- CMP DX, CX ; Start and end in same band?\r
- JNE @FB_NORMAL ; if not, check for l & r edges\r
- JMP @FB_ONE_BAND_ONLY ; if so, then special processing\r
-\r
-@FB_NORMAL:\r
- SUB CX, DX ; CX = # bands -1\r
- MOV SI, AX ; SI = PLANE#(X1)\r
- AND SI, PLANE_BITS ; if Left edge is aligned then\r
- JZ @FB_L_PLANE_FLUSH ; no special processing..\r
-\r
- ; Draw "Left Edge" vertical strip of 1-3 pixels...\r
-\r
- OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask\r
-\r
- MOV SI, DI ; SI = Copy of Start Addr (UL)\r
-\r
- MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw\r
- MOV AL, [BP].FB_Color ; Get Fill Color\r
- MOV BX, SCREEN_WIDTH ; Get Vertical increment Value\r
-\r
-@FB_LEFT_LOOP:\r
- MOV ES:[SI], AL ; Fill in Left Edge Pixels\r
- ADD SI, BX ; Point to Next Line (Below)\r
- LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn\r
-\r
- MOV ES:[SI], AL ; Fill in Left Edge Pixels\r
- ADD SI, BX ; Point to Next Line (Below)\r
- LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn\r
-\r
-@FB_LEFT_CONT:\r
-\r
- INC DI ; Point to Middle (or Right) Block\r
- DEC CX ; Reset CX instead of JMP @FB_RIGHT\r
-\r
-@FB_L_PLANE_FLUSH:\r
- INC CX ; Add in Left band to middle block\r
-\r
- ; DI = Addr of 1st middle Pixel (band) to fill\r
- ; CX = # of Bands to fill -1\r
-\r
-@FB_RIGHT:\r
- MOV SI, [BP].FB_Xpos2 ; Get Xpos2\r
- AND SI, PLANE_BITS ; Get Plane values\r
- CMP SI, 0003 ; Plane = 3?\r
- JE @FB_R_EDGE_FLUSH ; Hey, add to middle\r
-\r
- ; Draw "Right Edge" vertical strip of 1-3 pixels...\r
-\r
- OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask\r
-\r
- MOV SI, DI ; Get Addr of Left Edge\r
- ADD SI, CX ; Add Width-1 (Bands)\r
- DEC SI ; To point to top of Right Edge\r
-\r
- MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw\r
- MOV AL, [BP].FB_Color ; Get Fill Color\r
- MOV BX, SCREEN_WIDTH ; Get Vertical increment Value\r
-\r
-@FB_RIGHT_LOOP:\r
- MOV ES:[SI], AL ; Fill in Right Edge Pixels\r
- ADD SI, BX ; Point to Next Line (Below)\r
- LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn\r
-\r
- MOV ES:[SI], AL ; Fill in Right Edge Pixels\r
- ADD SI, BX ; Point to Next Line (Below)\r
- LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn\r
-\r
-@FB_RIGHT_CONT:\r
-\r
- DEC CX ; Minus 1 for Middle bands\r
- JZ @FB_EXIT ; Uh.. no Middle bands...\r
-\r
-@FB_R_EDGE_FLUSH:\r
-\r
- ; DI = Addr of Upper Left block to fill\r
- ; CX = # of Bands to fill in (width)\r
-\r
- OUT_8 SC_Data, ALL_PLANES ; Write to All Planes\r
-\r
- MOV DX, SCREEN_WIDTH ; DX = DI Increment\r
- SUB DX, CX ; = Screen_Width-# Planes Filled\r
-\r
- MOV BX, CX ; BX = Quick Refill for CX\r
- MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill\r
- MOV AL, [BP].FB_Color ; Get Fill Color\r
-\r
-@FB_MIDDLE_LOOP:\r
- REP STOSB ; Fill in entire line\r
-\r
- MOV CX, BX ; Recharge CX (Line Width)\r
- ADD DI, DX ; Point to start of Next Line\r
- LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn\r
-\r
- JMP s @FB_EXIT ; Outa here\r
-\r
-@FB_ONE_BAND_ONLY:\r
- MOV SI, AX ; Get Left Clip Mask, Save X1\r
- AND SI, PLANE_BITS ; Mask out Row #\r
- MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask\r
- MOV SI, BX ; Get Right Clip Mask, Save X2\r
- AND SI, PLANE_BITS ; Mask out Row #\r
- AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte\r
-\r
- OUT_8 SC_Data, AL ; Clip For Left & Right Masks\r
-\r
- MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw\r
- MOV AL, [BP].FB_Color ; Get Fill Color\r
- MOV BX, SCREEN_WIDTH ; Get Vertical increment Value\r
-\r
-@FB_ONE_LOOP:\r
- MOV ES:[DI], AL ; Fill in Pixels\r
- ADD DI, BX ; Point to Next Line (Below)\r
- LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn\r
-\r
- MOV ES:[DI], AL ; Fill in Pixels\r
- ADD DI, BX ; Point to Next Line (Below)\r
- LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn\r
-\r
-@FB_EXIT:\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 10 ; Exit and Clean up Stack\r
-\r
-FILL_BLOCK ENDP\r
-\r
-\r
-;=====================================================\r
-;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)\r
-;=====================================================\r
-;\r
-; Draws a Line on the active display page\r
-;\r
-; ENTRY: Xpos1 = X position of first point on line\r
-; Ypos1 = Y position of first point on line\r
-; Xpos2 = X position of last point on line\r
-; Ypos2 = Y position of last point on line\r
-; ColorNum = Color to draw line with\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-DL_STACK STRUC\r
- DW ?x1 ; DI, SI, BP\r
- DW ?x1 ; DI, SI, BP\r
- DW ?x1 ; DI, SI, BP\r
- DD ? ; Caller\r
- DL_ColorF DB ?,? ; Line Draw Color\r
- DL_Ypos2 DW ? ; Y pos of last point\r
- DL_Xpos2 DW ? ; X pos of last point\r
- DL_Ypos1 DW ? ; Y pos of first point\r
- DL_Xpos1 DW ? ; X pos of first point\r
-DL_STACK ENDS\r
-\r
- PUBLIC DRAW_LINE\r
-\r
-DRAW_LINE PROC FAR\r
-\r
- ;PUSHx BP, SI, DI ; Preserve Important Registers\r
- push bp\r
- push si\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
- CLD ; Direction Flag = Forward\r
-\r
- OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select\r
- MOV CH, [BP].DL_ColorF ; Save Line Color in CH\r
-\r
- ; Check Line Type\r
-\r
- MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2?\r
- MOV DI, [BP].DL_Xpos2 ; DX = X2\r
- CMP SI, DI ; Is X1 < X2\r
- JE @DL_VLINE ; If X1=X2, Draw Vertical Line\r
- JL @DL_NOSWAP1 ; If X1 < X2, don't swap\r
-\r
- XCHG SI, DI ; X2 IS > X1, SO SWAP THEM\r
-\r
-@DL_NOSWAP1:\r
-\r
- ; SI = X1, DI = X2\r
-\r
- MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2?\r
- CMP AX, [BP].DL_Ypos2 ; Y1 = Y2?\r
- JE @DL_HORZ ; If so, Draw a Horizontal Line\r
-\r
- JMP @DL_BREZHAM ; Diagonal line... go do it...\r
-\r
- ; This Code draws a Horizontal Line in Mode X where:\r
- ; SI = X1, DI = X2, and AX = Y1/Y2\r
-\r
-@DL_HORZ:\r
-\r
- MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width\r
- MOV DX, AX ; CX = Line offset into Page\r
-\r
- MOV AX, SI ; Get Left edge, Save X1\r
- AND SI, PLANE_BITS ; Mask out Row #\r
- MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask\r
- MOV CX, DI ; Get Right edge, Save X2\r
- AND DI, PLANE_BITS ; Mask out Row #\r
- MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte\r
-\r
- SHR AX, 1 ; Get X1 Byte # (=X1/4)\r
- SHR CX, 1 ; Get X2 Byte # (=X2/4)\r
- SHR AX, 1 ; Get X1 Byte # (=X1/4)\r
- SHR CX, 1 ; Get X2 Byte # (=X2/4)\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
- ADD DI, DX ; Point to Start of Line\r
- ADD DI, AX ; Point to Pixel X1\r
-\r
- SUB CX, AX ; CX = # Of Bands (-1) to set\r
- JNZ @DL_LONGLN ; jump if longer than one segment\r
-\r
- AND BL, BH ; otherwise, merge clip masks\r
-\r
-@DL_LONGLN:\r
-\r
- OUT_8 SC_Data, BL ; Set the Left Clip Mask\r
-\r
- MOV AL, [BP].DL_ColorF ; Get Line Color\r
- MOV BL, AL ; BL = Copy of Line Color\r
- STOSB ; Set Left (1-4) Pixels\r
-\r
- JCXZ @DL_EXIT ; Done if only one Line Segment\r
-\r
- DEC CX ; CX = # of Middle Segments\r
- JZ @DL_XRSEG ; If no middle segments....\r
-\r
- ; Draw Middle Segments\r
-\r
- OUT_8 DX, ALL_PLANES ; Write to ALL Planes\r
-\r
- MOV AL, BL ; Get Color from BL\r
- REP STOSB ; Draw Middle (4 Pixel) Segments\r
-\r
-@DL_XRSEG:\r
- OUT_8 DX, BH ; Select Planes for Right Clip Mask\r
- MOV AL, BL ; Get Color Value\r
- STOSB ; Draw Right (1-4) Pixels\r
-\r
- JMP s @DL_EXIT ; We Are Done...\r
-\r
-\r
- ; This Code Draws A Vertical Line. On entry:\r
- ; CH = Line Color, SI & DI = X1\r
-\r
-@DL_VLINE:\r
-\r
- MOV AX, [BP].DL_Ypos1 ; AX = Y1\r
- MOV SI, [BP].DL_Ypos2 ; SI = Y2\r
- CMP AX, SI ; Is Y1 < Y2?\r
- JLE @DL_NOSWAP2 ; if so, Don't Swap them\r
-\r
- XCHG AX, SI ; Ok, NOW Y1 < Y2\r
-\r
-@DL_NOSWAP2:\r
-\r
- SUB SI, AX ; SI = Line Height (Y2-Y1+1)\r
- INC SI\r
-\r
- ; AX = Y1, DI = X1, Get offset into Page into AX\r
-\r
- MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width\r
- MOV DX, DI ; Copy Xpos into DX\r
- SHR DI, 1 ; DI = Xpos/4\r
- SHR DI, 1 ; DI = Xpos/4\r
- ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
- ADD DI, AX ; Point to Pixel X1, Y1\r
-\r
- ;Select Plane\r
-\r
- MOV CL, DL ; CL = Save X1\r
- AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #)\r
- MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1\r
- SHL AH, CL ; Change to Correct Plane #\r
- OUT_16 SC_Index, AX ; Select Plane\r
-\r
- MOV AL, CH ; Get Saved Color\r
- MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By\r
-\r
-@DL_VLoop:\r
- MOV ES:[DI], AL ; Draw Single Pixel\r
- ADD DI, BX ; Point to Next Line\r
- LOOPjz SI, @DL_EXIT ; Lines--, Exit if done\r
-\r
- MOV ES:[DI], AL ; Draw Single Pixel\r
- ADD DI, BX ; Point to Next Line\r
- LOOPx SI, @DL_VLoop ; Lines--, Loop until Done\r
-\r
-@DL_EXIT:\r
-\r
- JMP @DL_EXIT2 ; Done!\r
-\r
- ; This code Draws a diagonal line in Mode X\r
-\r
-@DL_BREZHAM:\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
-\r
- MOV AX, [BP].DL_Ypos1 ; get Y1 value\r
- MOV BX, [BP].DL_Ypos2 ; get Y2 value\r
- MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos\r
-\r
- CMP BX, AX ; Y2-Y1 is?\r
- JNC @DL_DeltaYOK ; if Y2>=Y1 then goto...\r
-\r
- XCHG BX, AX ; Swap em...\r
- MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos\r
-\r
-@DL_DeltaYOK:\r
- MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1\r
-\r
- ADD DI, AX ; DI -> Start of Line Y1 on Page\r
- MOV AX, CX ; AX = Xpos (X1)\r
- SHR AX, 1 ; /4 = Byte Offset into Line\r
- SHR AX, 1 ; /4 = Byte Offset into Line\r
- ADD DI, AX ; DI = Starting pos (X1,Y1)\r
-\r
- MOV AL, 11h ; Staring Mask\r
- AND CL, PLANE_BITS ; Get Plane #\r
- SHL AL, CL ; and shift into place\r
- MOV AH, [BP].DL_ColorF ; Color in Hi Bytes\r
-\r
- PUSH AX ; Save Mask,Color...\r
-\r
- MOV AH, AL ; Plane # in AH\r
- MOV AL, MAP_MASK ; Select Plane Register\r
- OUT_16 SC_Index, AX ; Select initial plane\r
-\r
- MOV AX, [BP].DL_Xpos1 ; get X1 value\r
- MOV BX, [BP].DL_Ypos1 ; get Y1 value\r
- MOV CX, [BP].DL_Xpos2 ; get X2 value\r
- MOV DX, [BP].DL_Ypos2 ; get Y2 value\r
-\r
- MOV BP, SCREEN_WIDTH ; Use BP for Line width to\r
- ; to avoid extra memory access\r
-\r
- SUB DX, BX ; figure Delta_Y\r
- JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1\r
-\r
- ADD BX, DX ; put Y2 into Y1\r
- NEG DX ; abs(Delta_Y)\r
- XCHG AX, CX ; and exchange X1 and X2\r
-\r
-@DL_DeltaYOK2:\r
- MOV BX, 08000H ; seed for fraction accumulator\r
-\r
- SUB CX, AX ; figure Delta_X\r
- JC @DL_DrawLeft ; if negative, go left\r
-\r
- JMP @DL_DrawRight ; Draw Line that slopes right\r
-\r
-@DL_DrawLeft:\r
-\r
- NEG CX ; abs(Delta_X)\r
-\r
- CMP CX, DX ; is Delta_X < Delta_Y?\r
- JB @DL_SteepLeft ; yes, so go do steep line\r
- ; (Delta_Y iterations)\r
-\r
- ; Draw a Shallow line to the left in Mode X\r
-\r
-@DL_ShallowLeft:\r
- mov ax,0 ; zero low word of Delta_Y * 10000h\r
- SUB AX, DX ; DX:AX <- DX * 0FFFFh\r
- SBB DX, 0 ; include carry\r
- DIV CX ; divide by Delta_X\r
-\r
- MOV SI, BX ; SI = Accumulator\r
- MOV BX, AX ; BX = Add fraction\r
- POP AX ; Get Color, Bit mask\r
- MOV DX, SC_Data ; Sequence controller data register\r
- INC CX ; Inc Delta_X so we can unroll loop\r
-\r
- ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...\r
-\r
-@DL_SLLLoop:\r
- MOV ES:[DI], AH ; set first pixel, plane data set up\r
- LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done\r
-\r
- ADD SI, BX ; add numerator to accumulator\r
- JNC @DL_SLLL2nc ; move down on carry\r
-\r
- ADD DI, BP ; Move Down one line...\r
-\r
-@DL_SLLL2nc:\r
- DEC DI ; Left one addr\r
- ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
- CMP AL, 87h ; wrap?, if AL <88 then Carry set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
-\r
- MOV ES:[DI], AH ; set pixel\r
- LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done\r
-\r
- ADD SI, BX ; add numerator to accumulator,\r
- JNC @DL_SLLL3nc ; move down on carry\r
-\r
- ADD DI, BP ; Move Down one line...\r
-\r
-@DL_SLLL3nc: ; Now move left a pixel...\r
- DEC DI ; Left one addr\r
- ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
- CMP AL, 87h ; Wrap?, if AL <88 then Carry set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
- JMP s @DL_SLLLoop ; loop until done\r
-\r
-@DL_SLLExit:\r
- JMP @DL_EXIT2 ; and exit\r
-\r
- ; Draw a steep line to the left in Mode X\r
-\r
-@DL_SteepLeft:\r
- mov ax,0 ; zero low word of Delta_Y * 10000h\r
- XCHG DX, CX ; Delta_Y switched with Delta_X\r
- DIV CX ; divide by Delta_Y\r
-\r
- MOV SI, BX ; SI = Accumulator\r
- MOV BX, AX ; BX = Add Fraction\r
- POP AX ; Get Color, Bit mask\r
- MOV DX, SC_Data ; Sequence controller data register\r
- INC CX ; Inc Delta_Y so we can unroll loop\r
-\r
- ; Loop (x2) to Draw Pixels, Move Down, and Maybe left\r
-\r
-@DL_STLLoop:\r
-\r
- MOV ES:[DI], AH ; set first pixel\r
- LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done\r
-\r
- ADD SI, BX ; add numerator to accumulator\r
- JNC @DL_STLnc2 ; No carry, just move down!\r
-\r
- DEC DI ; Move Left one addr\r
- ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
- CMP AL, 87h ; Wrap?, if AL <88 then Carry set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
-\r
-@DL_STLnc2:\r
- ADD DI, BP ; advance to next line.\r
-\r
- MOV ES:[DI], AH ; set pixel\r
- LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done\r
-\r
- ADD SI, BX ; add numerator to accumulator\r
- JNC @DL_STLnc3 ; No carry, just move down!\r
-\r
- DEC DI ; Move Left one addr\r
- ROR AL, 1 ; Move Left one plane, back on 0 1 2\r
- CMP AL, 87h ; Wrap?, if AL <88 then Carry set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
-\r
-@DL_STLnc3:\r
- ADD DI, BP ; advance to next line.\r
- JMP s @DL_STLLoop ; Loop until done\r
-\r
-@DL_STLExit:\r
- JMP @DL_EXIT2 ; and exit\r
-\r
- ; Draw a line that goes to the Right...\r
-\r
-@DL_DrawRight:\r
- CMP CX, DX ; is Delta_X < Delta_Y?\r
- JB @DL_SteepRight ; yes, so go do steep line\r
- ; (Delta_Y iterations)\r
-\r
- ; Draw a Shallow line to the Right in Mode X\r
-\r
-@DL_ShallowRight:\r
- mov ax,0 ; zero low word of Delta_Y * 10000h\r
- SUB AX, DX ; DX:AX <- DX * 0FFFFh\r
- SBB DX, 0 ; include carry\r
- DIV CX ; divide by Delta_X\r
-\r
- MOV SI, BX ; SI = Accumulator\r
- MOV BX, AX ; BX = Add Fraction\r
- POP AX ; Get Color, Bit mask\r
- MOV DX, SC_Data ; Sequence controller data register\r
- INC CX ; Inc Delta_X so we can unroll loop\r
-\r
- ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...\r
-\r
-@DL_SLRLoop:\r
- MOV ES:[DI], AH ; set first pixel, mask is set up\r
- LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..\r
-\r
- ADD SI, BX ; add numerator to accumulator\r
- JNC @DL_SLR2nc ; don't move down if carry not set\r
-\r
- ADD DI, BP ; Move Down one line...\r
-\r
-@DL_SLR2nc: ; Now move right a pixel...\r
- ROL AL, 1 ; Move Right one addr if Plane = 0\r
- CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
-\r
- MOV ES:[DI], AH ; set pixel\r
- LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..\r
-\r
- ADD SI, BX ; add numerator to accumulator\r
- JNC @DL_SLR3nc ; don't move down if carry not set\r
-\r
- ADD DI, BP ; Move Down one line...\r
-\r
-@DL_SLR3nc:\r
- ROL AL, 1 ; Move Right one addr if Plane = 0\r
- CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
- JMP s @DL_SLRLoop ; loop till done\r
-\r
-@DL_SLRExit:\r
- JMP @DL_EXIT2 ; and exit\r
-\r
- ; Draw a Steep line to the Right in Mode X\r
-\r
-@DL_SteepRight:\r
- mov ax,0 ; zero low word of Delta_Y * 10000h\r
- XCHG DX, CX ; Delta_Y switched with Delta_X\r
- DIV CX ; divide by Delta_Y\r
-\r
- MOV SI, BX ; SI = Accumulator\r
- MOV BX, AX ; BX = Add Fraction\r
- POP AX ; Get Color, Bit mask\r
- MOV DX, SC_Data ; Sequence controller data register\r
- INC CX ; Inc Delta_Y so we can unroll loop\r
-\r
- ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right\r
-\r
-@STRLoop:\r
- MOV ES:[DI], AH ; set first pixel, mask is set up\r
- LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done\r
-\r
- ADD SI, BX ; add numerator to accumulator\r
- JNC @STRnc2 ; if no carry then just go down...\r
-\r
- ROL AL, 1 ; Move Right one addr if Plane = 0\r
- CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
-\r
-@STRnc2:\r
- ADD DI, BP ; advance to next line.\r
-\r
- MOV ES:[DI], AH ; set pixel\r
- LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done\r
-\r
- ADD SI, BX ; add numerator to accumulator\r
- JNC @STRnc3 ; if no carry then just go down...\r
-\r
- ROL AL, 1 ; Move Right one addr if Plane = 0\r
- CMP AL, 12h ; Wrap? if AL >12 then Carry not set\r
- ADC DI, 0 ; Adjust Address: DI = DI + Carry\r
- OUT DX, AL ; Set up New Bit Plane mask\r
-\r
-@STRnc3:\r
- ADD DI, BP ; advance to next line.\r
- JMP s @STRLoop ; loop till done\r
-\r
-@DL_EXIT2:\r
- ;POPx DI, SI, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop bp\r
- RET 10 ; Exit and Clean up Stack\r
-\r
-DRAW_LINE ENDP\r
-\r
-\r
- ; ===== DAC COLOR REGISTER ROUTINES =====\r
-\r
-;=================================================\r
-;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)\r
-;=================================================\r
-;\r
-; Sets a single (RGB) Vga Palette Register\r
-;\r
-; ENTRY: Register = The DAC # to modify (0-255)\r
-; Red = The new Red Intensity (0-63)\r
-; Green = The new Green Intensity (0-63)\r
-; Blue = The new Blue Intensity (0-63)\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-SDR_STACK STRUC\r
- DW ? ; BP\r
- DD ? ; Caller\r
- SDR_Blue DB ?,? ; Blue Data Value\r
- SDR_Green DB ?,? ; Green Data Value\r
- SDR_Red DB ?,? ; Red Data Value\r
- SDR_Register DB ?,? ; Palette Register #\r
-SDR_STACK ENDS\r
-\r
- PUBLIC SET_DAC_REGISTER\r
-\r
-SET_DAC_REGISTER PROC FAR\r
-\r
- PUSH BP ; Save BP\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- ; Select which DAC Register to modify\r
-\r
- OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register\r
-\r
- MOV DX, PEL_DATA_REG ; Dac Data Register\r
- OUT_8 DX, [BP].SDR_Red ; Set Red Intensity\r
- OUT_8 DX, [BP].SDR_Green ; Set Green Intensity\r
- OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity\r
-\r
- POP BP ; Restore Registers\r
- RET 8 ; Exit & Clean Up Stack\r
-\r
-SET_DAC_REGISTER ENDP\r
-\r
-;====================================================\r
-;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)\r
-;====================================================\r
-;\r
-; Reads the RGB Values of a single Vga Palette Register\r
-;\r
-; ENTRY: Register = The DAC # to read (0-255)\r
-; Red = Offset to Red Variable in DS\r
-; Green = Offset to Green Variable in DS\r
-; Blue = Offset to Blue Variable in DS\r
-;\r
-; EXIT: The values of the integer variables Red,\r
-; Green, and Blue are set to the values\r
-; taken from the specified DAC register.\r
-;\r
-\r
-GDR_STACK STRUC\r
- DW ? ; BP\r
- DD ? ; Caller\r
- GDR_Blue DW ? ; Addr of Blue Data Value in DS\r
- GDR_Green DW ? ; Addr of Green Data Value in DS\r
- GDR_Red DW ? ; Addr of Red Data Value in DS\r
- GDR_Register DB ?,? ; Palette Register #\r
-GDR_STACK ENDS\r
-\r
- PUBLIC GET_DAC_REGISTER\r
-\r
-GET_DAC_REGISTER PROC FAR\r
-\r
- PUSH BP ; Save BP\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- ; Select which DAC Register to read in\r
-\r
- OUT_8 DAC_READ_ADDR, [BP].GDR_Register\r
-\r
- MOV DX, PEL_DATA_REG ; Dac Data Register\r
- mov ax,0 ; Clear AX\r
-\r
- IN AL, DX ; Read Red Value\r
- MOV BX, [BP].GDR_Red ; Get Address of Red%\r
- MOV [BX], AX ; *Red% = AX\r
-\r
- IN AL, DX ; Read Green Value\r
- MOV BX, [BP].GDR_Green ; Get Address of Green%\r
- MOV [BX], AX ; *Green% = AX\r
-\r
- IN AL, DX ; Read Blue Value\r
- MOV BX, [BP].GDR_Blue ; Get Address of Blue%\r
- MOV [BX], AX ; *Blue% = AX\r
-\r
- POP BP ; Restore Registers\r
- RET 8 ; Exit & Clean Up Stack\r
-\r
-GET_DAC_REGISTER ENDP\r
-\r
-\r
-;===========================================================\r
-;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%)\r
-;===========================================================\r
-;\r
-; Sets a Block of Vga Palette Registers\r
-;\r
-; ENTRY: PalData = Far Pointer to Block of palette data\r
-; StartReg = First Register # in range to set (0-255)\r
-; EndReg = Last Register # in Range to set (0-255)\r
-; Sync = Wait for Vertical Retrace Flag (Boolean)\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-; NOTES: PalData is a linear array of 3 byte Palette values\r
-; in the order: Red (0-63), Green (0-63), Blue (0-63)\r
-;\r
-\r
-LDR_STACK STRUC\r
- DW ?x1 ; BP, DS, SI\r
- DW ?x1 ; BP, DS, SI\r
- DW ?x1 ; BP, DS, SI\r
- DD ? ; Caller\r
- LDR_Sync DW ? ; Vertical Sync Flag\r
- LDR_EndReg DB ?,? ; Last Register #\r
- LDR_StartReg DB ?,? ; First Register #\r
- LDR_PalData DD ? ; Far Ptr to Palette Data\r
-LDR_STACK ENDS\r
-\r
- PUBLIC LOAD_DAC_REGISTERS\r
-\r
-LOAD_DAC_REGISTERS PROC FAR\r
-\r
- ;PUSHx BP, DS, SI ; Save Registers\r
- push bp\r
- push ds\r
- push si\r
- mov BP, SP ; Set up Stack Frame\r
-\r
- mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag\r
- or AX, AX ; is Sync Flag = 0?\r
- jz @LDR_Load ; if so, skip call\r
-\r
- call f SYNC_DISPLAY ; wait for vsync\r
-\r
- ; Determine register #'s, size to copy, etc\r
-\r
-@LDR_Load:\r
-\r
- lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data\r
- mov DX, DAC_WRITE_ADDR ; DAC register # selector\r
-\r
- mov ax,0, BX ; Clear for byte loads\r
- mov AL, [BP].LDR_StartReg ; Get Start Register\r
- mov BL, [BP].LDR_EndReg ; Get End Register\r
-\r
- sub BX, AX ; BX = # of DAC registers -1\r
- inc BX ; BX = # of DAC registers\r
- mov CX, BX ; CX = # of DAC registers\r
- add CX, BX ; CX = " " * 2\r
- add CX, BX ; CX = " " * 3\r
- cld ; Block OUTs forward\r
- out DX, AL ; set up correct register #\r
-\r
- ; Load a block of DAC Registers\r
-\r
- mov DX, PEL_DATA_REG ; Dac Data Register\r
-\r
- ;rep outsb ; block set DAC registers\r
-\r
- ;POPx SI, DS, BP ; Restore Registers\r
- pop si\r
- pop ds\r
- pop bp\r
- ret 10 ; Exit & Clean Up Stack\r
-\r
-LOAD_DAC_REGISTERS ENDP\r
-\r
-\r
-;====================================================\r
-;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%)\r
-;====================================================\r
-;\r
-; Reads a Block of Vga Palette Registers\r
-;\r
-; ENTRY: PalData = Far Pointer to block to store palette data\r
-; StartReg = First Register # in range to read (0-255)\r
-; EndReg = Last Register # in Range to read (0-255)\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-; NOTES: PalData is a linear array of 3 byte Palette values\r
-; in the order: Red (0-63), Green (0-63), Blue (0-63)\r
-;\r
-\r
-RDR_STACK STRUC\r
- DW ?x1 ; BP, ES, DI\r
- DW ?x1 ; BP, ES, DI\r
- DW ?x1 ; BP, ES, DI\r
- DD ? ; Caller\r
- RDR_EndReg DB ?,? ; Last Register #\r
- RDR_StartReg DB ?,? ; First Register #\r
- RDR_PalData DD ? ; Far Ptr to Palette Data\r
-RDR_STACK ENDS\r
-\r
- PUBLIC READ_DAC_REGISTERS\r
-\r
-READ_DAC_REGISTERS PROC FAR\r
-\r
- ;PUSHx BP, ES, DI ; Save Registers\r
- push bp\r
- push es\r
- push di\r
- mov BP, SP ; Set up Stack Frame\r
-\r
- ; Determine register #'s, size to copy, etc\r
-\r
- les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer\r
- mov DX, DAC_READ_ADDR ; DAC register # selector\r
-\r
- mov ax,0, BX ; Clear for byte loads\r
- mov AL, [BP].RDR_StartReg ; Get Start Register\r
- mov BL, [BP].RDR_EndReg ; Get End Register\r
-\r
- sub BX, AX ; BX = # of DAC registers -1\r
- inc BX ; BX = # of DAC registers\r
- mov CX, BX ; CX = # of DAC registers\r
- add CX, BX ; CX = " " * 2\r
- add CX, BX ; CX = " " * 3\r
- cld ; Block INs forward\r
-\r
- ; Read a block of DAC Registers\r
-\r
- out DX, AL ; set up correct register #\r
- mov DX, PEL_DATA_REG ; Dac Data Register\r
-\r
- ;rep insb ; block read DAC registers\r
-\r
- ;POPx DI, ES, BP ; Restore Registers\r
- pop di\r
- pop es\r
- pop bp\r
- ret 8 ; Exit & Clean Up Stack\r
-\r
-READ_DAC_REGISTERS ENDP\r
-\r
-\r
- ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====\r
-\r
-;=========================\r
-;SET_ACTIVE_PAGE (PageNo%)\r
-;=========================\r
-;\r
-; Sets the active display Page to be used for future drawing\r
-;\r
-; ENTRY: PageNo = Display Page to make active\r
-; (values: 0 to Number of Pages - 1)\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-SAP_STACK STRUC\r
- DW ? ; BP\r
- DD ? ; Caller\r
- SAP_Page DW ? ; Page # for Drawing\r
-SAP_STACK ENDS\r
-\r
- PUBLIC SET_ACTIVE_PAGE\r
-\r
-SET_ACTIVE_PAGE PROC FAR\r
-\r
- PUSH BP ; Preserve Registers\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- MOV BX, [BP].SAP_Page ; Get Desired Page #\r
- CMP BX, LAST_PAGE ; Is Page # Valid?\r
- JAE @SAP_Exit ; IF Not, Do Nothing\r
-\r
- MOV ACTIVE_PAGE, BX ; Set Active Page #\r
-\r
- SHL BX, 1 ; Scale Page # to Word\r
- MOV AX, PAGE_ADDR[BX] ; Get offset to Page\r
-\r
- MOV CURRENT_PAGE, AX ; And set for future LES's\r
-\r
-@SAP_Exit:\r
- POP BP ; Restore Registers\r
- RET 2 ; Exit and Clean up Stack\r
-\r
-SET_ACTIVE_PAGE ENDP\r
-\r
-\r
-;================\r
-;GET_ACTIVE_PAGE%\r
-;================\r
-;\r
-; Returns the Video Page # currently used for Drawing\r
-;\r
-; ENTRY: No Parameters are passed\r
-;\r
-; EXIT: AX = Current Video Page used for Drawing\r
-;\r
-\r
- PUBLIC GET_ACTIVE_PAGE\r
-\r
-GET_ACTIVE_PAGE PROC FAR\r
-\r
- MOV AX, ACTIVE_PAGE ; Get Active Page #\r
- RET ; Exit and Clean up Stack\r
-\r
-GET_ACTIVE_PAGE ENDP\r
-\r
-\r
-;===============================\r
-;SET_DISPLAY_PAGE (DisplayPage%)\r
-;===============================\r
-;\r
-; Sets the currently visible display page.\r
-; When called this routine syncronizes the display\r
-; to the vertical blank.\r
-;\r
-; ENTRY: PageNo = Display Page to show on the screen\r
-; (values: 0 to Number of Pages - 1)\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-SDP_STACK STRUC\r
- DW ? ; BP\r
- DD ? ; Caller\r
- SDP_Page DW ? ; Page # to Display...\r
-SDP_STACK ENDS\r
-\r
- PUBLIC SET_DISPLAY_PAGE\r
-\r
-SET_DISPLAY_PAGE PROC FAR\r
-\r
- PUSH BP ; Preserve Registers\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- MOV BX, [BP].SDP_Page ; Get Desired Page #\r
- CMP BX, LAST_PAGE ; Is Page # Valid?\r
- JAE @SDP_Exit ; IF Not, Do Nothing\r
-\r
- MOV DISPLAY_PAGE, BX ; Set Display Page #\r
-\r
- SHL BX, 1 ; Scale Page # to Word\r
- MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page\r
- ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling\r
-\r
- ; Wait if we are currently in a Vertical Retrace\r
-\r
- MOV DX, INPUT_1 ; Input Status #1 Register\r
-\r
-@DP_WAIT0:\r
- IN AL, DX ; Get VGA status\r
- AND AL, VERT_RETRACE ; In Display mode yet?\r
- JNZ @DP_WAIT0 ; If Not, wait for it\r
-\r
- ; Set the Start Display Address to the new page\r
-\r
- MOV DX, CRTC_Index ; We Change the VGA Sequencer\r
-\r
- MOV AL, START_DISP_LO ; Display Start Low Register\r
- MOV AH, CL ; Low 8 Bits of Start Addr\r
- OUT DX, AX ; Set Display Addr Low\r
-\r
- MOV AL, START_DISP_HI ; Display Start High Register\r
- MOV AH, CH ; High 8 Bits of Start Addr\r
- OUT DX, AX ; Set Display Addr High\r
-\r
- ; Wait for a Vertical Retrace to smooth out things\r
-\r
- MOV DX, INPUT_1 ; Input Status #1 Register\r
-\r
-@DP_WAIT1:\r
- IN AL, DX ; Get VGA status\r
- AND AL, VERT_RETRACE ; Vertical Retrace Start?\r
- JZ @DP_WAIT1 ; If Not, wait for it\r
-\r
- ; Now Set Display Starting Address\r
-\r
-\r
-@SDP_Exit:\r
- POP BP ; Restore Registers\r
- RET 2 ; Exit and Clean up Stack\r
-\r
-SET_DISPLAY_PAGE ENDP\r
-\r
-\r
-;=================\r
-;GET_DISPLAY_PAGE%\r
-;=================\r
-;\r
-; Returns the Video Page # currently displayed\r
-;\r
-; ENTRY: No Parameters are passed\r
-;\r
-; EXIT: AX = Current Video Page being displayed\r
-;\r
-\r
- PUBLIC GET_DISPLAY_PAGE\r
-\r
-GET_DISPLAY_PAGE PROC FAR\r
-\r
- MOV AX, DISPLAY_PAGE ; Get Display Page #\r
- RET ; Exit & Clean Up Stack\r
-\r
-GET_DISPLAY_PAGE ENDP\r
-\r
-\r
-;=======================================\r
-;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)\r
-;=======================================\r
-;\r
-; Since a Logical Screen can be larger than the Physical\r
-; Screen, Scrolling is possible. This routine sets the\r
-; Upper Left Corner of the Screen to the specified Pixel.\r
-; Also Sets the Display page to simplify combined page\r
-; flipping and scrolling. When called this routine\r
-; syncronizes the display to the vertical blank.\r
-;\r
-; ENTRY: DisplayPage = Display Page to show on the screen\r
-; Xpos = # of pixels to shift screen right\r
-; Ypos = # of lines to shift screen down\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-SW_STACK STRUC\r
- DW ? ; BP\r
- DD ? ; Caller\r
- SW_Ypos DW ? ; Y pos of UL Screen Corner\r
- SW_Xpos DW ? ; X pos of UL Screen Corner\r
- SW_Page DW ? ; (new) Display Page\r
-SW_STACK ENDS\r
-\r
- PUBLIC SET_WINDOW\r
-\r
-SET_WINDOW PROC FAR\r
-\r
- PUSH BP ; Preserve Registers\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- ; Check if our Scroll Offsets are Valid\r
-\r
- MOV BX, [BP].SW_Page ; Get Desired Page #\r
- CMP BX, LAST_PAGE ; Is Page # Valid?\r
- JAE @SW_Exit ; IF Not, Do Nothing\r
-\r
- MOV AX, [BP].SW_Ypos ; Get Desired Y Offset\r
- CMP AX, MAX_YOFFSET ; Is it Within Limits?\r
- JA @SW_Exit ; if not, exit\r
-\r
- MOV CX, [BP].SW_Xpos ; Get Desired X Offset\r
- CMP CX, MAX_XOFFSET ; Is it Within Limits?\r
- JA @SW_Exit ; if not, exit\r
-\r
- ; Compute proper Display start address to use\r
-\r
- MUL SCREEN_WIDTH ; AX = YOffset * Line Width\r
- SHR CX, 1 ; CX / 4 = Bytes into Line\r
- SHR CX, 1 ; CX / 4 = Bytes into Line\r
- ADD AX, CX ; AX = Offset of Upper Left Pixel\r
-\r
- MOV CURRENT_MOFFSET, AX ; Save Offset Info\r
-\r
- MOV DISPLAY_PAGE, BX ; Set Current Page #\r
- SHL BX, 1 ; Scale Page # to Word\r
- ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page\r
- MOV BX, AX ; BX = Desired Display Start\r
-\r
- MOV DX, INPUT_1 ; Input Status #1 Register\r
-\r
- ; Wait if we are currently in a Vertical Retrace\r
-\r
-@SW_WAIT0:\r
- IN AL, DX ; Get VGA status\r
- AND AL, VERT_RETRACE ; In Display mode yet?\r
- JNZ @SW_WAIT0 ; If Not, wait for it\r
-\r
- ; Set the Start Display Address to the new window\r
-\r
- MOV DX, CRTC_Index ; We Change the VGA Sequencer\r
- MOV AL, START_DISP_LO ; Display Start Low Register\r
- MOV AH, BL ; Low 8 Bits of Start Addr\r
- OUT DX, AX ; Set Display Addr Low\r
-\r
- MOV AL, START_DISP_HI ; Display Start High Register\r
- MOV AH, BH ; High 8 Bits of Start Addr\r
- OUT DX, AX ; Set Display Addr High\r
-\r
- ; Wait for a Vertical Retrace to smooth out things\r
-\r
- MOV DX, INPUT_1 ; Input Status #1 Register\r
-\r
-@SW_WAIT1:\r
- IN AL, DX ; Get VGA status\r
- AND AL, VERT_RETRACE ; Vertical Retrace Start?\r
- JZ @SW_WAIT1 ; If Not, wait for it\r
-\r
- ; Now Set the Horizontal Pixel Pan values\r
-\r
- OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register\r
-\r
- MOV AX, [BP].SW_Xpos ; Get Desired X Offset\r
- AND AL, 03 ; Get # of Pixels to Pan (0-3)\r
- SHL AL, 1 ; Shift for 256 Color Mode\r
- OUT DX, AL ; Fine tune the display!\r
-\r
-@SW_Exit:\r
- POP BP ; Restore Saved Registers\r
- RET 6 ; Exit and Clean up Stack\r
-\r
-SET_WINDOW ENDP\r
-\r
-\r
-;=============\r
-;GET_X_OFFSET%\r
-;=============\r
-;\r
-; Returns the X coordinate of the Pixel currently display\r
-; in the upper left corner of the display\r
-;\r
-; ENTRY: No Parameters are passed\r
-;\r
-; EXIT: AX = Current Horizontal Scroll Offset\r
-;\r
-\r
- PUBLIC GET_X_OFFSET\r
-\r
-GET_X_OFFSET PROC FAR\r
-\r
- MOV AX, CURRENT_XOFFSET ; Get current horz offset\r
- RET ; Exit & Clean Up Stack\r
-\r
-GET_X_OFFSET ENDP\r
-\r
-\r
-;=============\r
-;GET_Y_OFFSET%\r
-;=============\r
-;\r
-; Returns the Y coordinate of the Pixel currently display\r
-; in the upper left corner of the display\r
-;\r
-; ENTRY: No Parameters are passed\r
-;\r
-; EXIT: AX = Current Vertical Scroll Offset\r
-;\r
-\r
- PUBLIC GET_Y_OFFSET\r
-\r
-GET_Y_OFFSET PROC FAR\r
-\r
- MOV AX, CURRENT_YOFFSET ; Get current vertical offset\r
- RET ; Exit & Clean Up Stack\r
-\r
-GET_Y_OFFSET ENDP\r
-\r
-\r
-;============\r
-;SYNC_DISPLAY\r
-;============\r
-;\r
-; Pauses the computer until the next Vertical Retrace starts\r
-;\r
-; ENTRY: No Parameters are passed\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
- PUBLIC SYNC_DISPLAY\r
-\r
-SYNC_DISPLAY PROC FAR\r
-\r
- MOV DX, INPUT_1 ; Input Status #1 Register\r
-\r
- ; Wait for any current retrace to end\r
-\r
-@SD_WAIT0:\r
- IN AL, DX ; Get VGA status\r
- AND AL, VERT_RETRACE ; In Display mode yet?\r
- JNZ @SD_WAIT0 ; If Not, wait for it\r
-\r
- ; Wait for the start of the next vertical retrace\r
-\r
-@SD_WAIT1:\r
- IN AL, DX ; Get VGA status\r
- AND AL, VERT_RETRACE ; Vertical Retrace Start?\r
- JZ @SD_WAIT1 ; If Not, wait for it\r
-\r
- RET ; Exit & Clean Up Stack\r
-\r
-SYNC_DISPLAY ENDP\r
-\r
-\r
- ; ===== TEXT DISPLAY ROUTINES =====\r
-\r
-;==================================================\r
-;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)\r
-;==================================================\r
-;\r
-; Draws an ASCII Text Character using the currently selected\r
-; 8x8 font on the active display page. It would be a simple\r
-; exercise to make this routine process variable height fonts.\r
-;\r
-; ENTRY: CharNum = ASCII character # to draw\r
-; Xpos = X position to draw Character at\r
-; Ypos = Y position of to draw Character at\r
-; ColorF = Color to draw text character in\r
-; ColorB = Color to set background to\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-GPC_STACK STRUC\r
- GPC_Width DW ? ; Screen Width-1\r
- GPC_Lines DB ?,? ; Scan lines to Decode\r
- GPC_T_SETS DW ? ; Saved Charset Segment\r
- GPC_T_SETO DW ? ; Saved Charset Offset\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- GPC_ColorB DB ?,? ; Background Color\r
- GPC_ColorF DB ?,? ; Text Color\r
- GPC_Ypos DW ? ; Y Position to Print at\r
- GPC_Xpos DW ? ; X position to Print at\r
- GPC_Char DB ?,? ; Character to Print\r
-GPC_STACK ENDS\r
-\r
- PUBLIC GPRINTC\r
-\r
-GPRINTC PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- SUB SP, 8 ; Allocate WorkSpace on Stack\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
-\r
- MOV AX, SCREEN_WIDTH ; Get Logical Line Width\r
- MOV BX, AX ; BX = Screen Width\r
- DEC BX ; = Screen Width-1\r
- MOV [BP].GPC_Width, BX ; Save for later use\r
-\r
- MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width\r
- ADD DI, AX ; DI -> Start of Line Ypos\r
-\r
- MOV AX, [BP].GPC_Xpos ; Get Xpos of Character\r
- MOV CX, AX ; Save Copy of Xpos\r
- SHR AX, 1 ; Bytes into Line = Xpos/4\r
- SHR AX, 1 ; Bytes into Line = Xpos/4\r
- ADD DI, AX ; DI -> (Xpos, Ypos)\r
-\r
- ;Get Source ADDR of Character Bit Map & Save\r
-\r
- MOV AL, [BP].GPC_Char ; Get Character #\r
- TEST AL, 080h ; Is Hi Bit Set?\r
- JZ @GPC_LowChar ; Nope, use low char set ptr\r
-\r
- AND AL, 07Fh ; Mask Out Hi Bit\r
- MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset\r
- MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment\r
- JMP s @GPC_Set_Char ; Go Setup Character Ptr\r
-\r
-@GPC_LowChar:\r
-\r
- MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset\r
- MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment\r
-\r
-@GPC_Set_Char:\r
- MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack\r
-\r
- MOV AH, 0 ; Valid #'s are 0..127\r
- SHL AX, 1 ; * 8 Bytes Per Bitmap\r
- SHL AX, 1 ; * 8 Bytes Per Bitmap\r
- SHL AX, 1 ; * 8 Bytes Per Bitmap\r
- ADD BX, AX ; BX = Offset of Selected char\r
- MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack\r
-\r
- AND CX, PLANE_BITS ; Get Plane #\r
- MOV CH, ALL_PLANES ; Get Initial Plane mask\r
- SHL CH, CL ; And shift into position\r
- AND CH, ALL_PLANES ; And mask to lower nibble\r
-\r
- MOV AL, 04 ; 4-Plane # = # of initial\r
- SUB AL, CL ; shifts to align bit mask\r
- MOV CL, AL ; Shift Count for SHL\r
-\r
- ;Get segment of character map\r
-\r
- OUT_8 SC_Index, MAP_MASK ; Setup Plane selections\r
- INC DX ; DX -> SC_Data\r
-\r
- MOV AL, 08 ; 8 Lines to Process\r
- MOV [BP].GPC_Lines, AL ; Save on Stack\r
-\r
- MOV DS, [BP].GPC_T_SETS ; Point to character set\r
-\r
-@GPC_DECODE_CHAR_BYTE:\r
-\r
- MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String\r
-\r
- MOV BH, [SI] ; Get Bit Map\r
- INC SI ; Point to Next Line\r
- MOV [BP].GPC_T_SETO, SI ; And save new Pointer...\r
-\r
- mov ax,0 ; Clear AX\r
-\r
- ;mov bl,0 ; Clear BL\r
- mov bl,0\r
- ROL BX, CL ; BL holds left edge bits\r
- MOV SI, BX ; Use as Table Index\r
- AND SI, CHAR_BITS ; Get Low Bits\r
- MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
- JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set\r
-\r
- MOV AH, [BP].GPC_ColorF ; Get Foreground Color\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
-@GPC_NO_LEFT1BITS:\r
- XOR AL, CH ; Invert mask for Background\r
- JZ @GPC_NO_LEFT0BITS ; Hey, no need for this\r
-\r
- MOV AH, [BP].GPC_ColorB ; Get background Color\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
- ;Now Do Middle/Last Band\r
-\r
-@GPC_NO_LEFT0BITS:\r
- INC DI ; Point to next Byte\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
-\r
- MOV SI, BX ; Make Lookup Pointer\r
- AND SI, CHAR_BITS ; Get Low Bits\r
- MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
- JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set\r
-\r
- MOV AH, [BP].GPC_ColorF ; Get Foreground Color\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
-@GPC_NO_MIDDLE1BITS:\r
- XOR AL, ALL_PLANES ; Invert mask for Background\r
- JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this\r
-\r
- MOV AH, [BP].GPC_ColorB ; Get background Color\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
-@GPC_NO_MIDDLE0BITS:\r
- XOR CH, ALL_PLANES ; Invert Clip Mask\r
- CMP CL, 4 ; Aligned by 4?\r
- JZ @GPC_NEXT_LINE ; If so, Exit now..\r
-\r
- INC DI ; Point to next Byte\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
-\r
- MOV SI, BX ; Make Lookup Pointer\r
- AND SI, CHAR_BITS ; Get Low Bits\r
- MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
- JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set\r
-\r
- MOV AH, [BP].GPC_ColorF ; Get Foreground Color\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
-@GPC_NO_RIGHT1BITS:\r
-\r
- XOR AL, CH ; Invert mask for Background\r
- JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this\r
-\r
- MOV AH, [BP].GPC_ColorB ; Get background Color\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
-@GPC_NO_RIGHT0BITS:\r
- DEC DI ; Adjust for Next Line Advance\r
-\r
-@GPC_NEXT_LINE:\r
- ADD DI, [BP].GPC_Width ; Point to Next Line\r
- XOR CH, CHAR_BITS ; Flip the Clip mask back\r
-\r
- DEC [BP].GPC_Lines ; Count Down Lines\r
- JZ @GPC_EXIT ; Ok... Done!\r
-\r
- JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey!\r
-\r
-@GPC_EXIT:\r
- ADD SP, 08 ; Deallocate stack workspace\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 10 ; Exit and Clean up Stack\r
-\r
-GPRINTC ENDP\r
-\r
-\r
-;==========================================\r
-;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)\r
-;==========================================\r
-;\r
-; Transparently draws an ASCII Text Character using the\r
-; currently selected 8x8 font on the active display page.\r
-;\r
-; ENTRY: CharNum = ASCII character # to draw\r
-; Xpos = X position to draw Character at\r
-; Ypos = Y position of to draw Character at\r
-; ColorF = Color to draw text character in\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-TGP_STACK STRUC\r
- TGP_Width DW ? ; Screen Width-1\r
- TGP_Lines DB ?,? ; Scan lines to Decode\r
- TGP_T_SETS DW ? ; Saved Charset Segment\r
- TGP_T_SETO DW ? ; Saved Charset Offset\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- TGP_ColorF DB ?,? ; Text Color\r
- TGP_Ypos DW ? ; Y Position to Print at\r
- TGP_Xpos DW ? ; X position to Print at\r
- TGP_Char DB ?,? ; Character to Print\r
-TGP_STACK ENDS\r
-\r
- PUBLIC TGPRINTC\r
-\r
-TGPRINTC PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- SUB SP, 8 ; Allocate WorkSpace on Stack\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
-\r
- MOV AX, SCREEN_WIDTH ; Get Logical Line Width\r
- MOV BX, AX ; BX = Screen Width\r
- DEC BX ; = Screen Width-1\r
- MOV [BP].TGP_Width, BX ; Save for later use\r
-\r
- MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width\r
- ADD DI, AX ; DI -> Start of Line Ypos\r
-\r
- MOV AX, [BP].TGP_Xpos ; Get Xpos of Character\r
- MOV CX, AX ; Save Copy of Xpos\r
- SHR AX, 1 ; Bytes into Line = Xpos/4\r
- SHR AX, 1 ; Bytes into Line = Xpos/4\r
- ADD DI, AX ; DI -> (Xpos, Ypos)\r
-\r
- ;Get Source ADDR of Character Bit Map & Save\r
-\r
- MOV AL, [BP].TGP_Char ; Get Character #\r
- TEST AL, 080h ; Is Hi Bit Set?\r
- JZ @TGP_LowChar ; Nope, use low char set ptr\r
-\r
- AND AL, 07Fh ; Mask Out Hi Bit\r
- MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset\r
- MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment\r
- JMP s @TGP_Set_Char ; Go Setup Character Ptr\r
-\r
-@TGP_LowChar:\r
-\r
- MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset\r
- MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment\r
-\r
-@TGP_Set_Char:\r
- MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack\r
-\r
- MOV AH, 0 ; Valid #'s are 0..127\r
- SHL AX, 1 ; * 8 Bytes Per Bitmap\r
- SHL AX, 1 ; * 8 Bytes Per Bitmap\r
- SHL AX, 1 ; * 8 Bytes Per Bitmap\r
- ADD BX, AX ; BX = Offset of Selected char\r
- MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack\r
-\r
- AND CX, PLANE_BITS ; Get Plane #\r
- MOV CH, ALL_PLANES ; Get Initial Plane mask\r
- SHL CH, CL ; And shift into position\r
- AND CH, ALL_PLANES ; And mask to lower nibble\r
-\r
- MOV AL, 04 ; 4-Plane # = # of initial\r
- SUB AL, CL ; shifts to align bit mask\r
- MOV CL, AL ; Shift Count for SHL\r
-\r
- ;Get segment of character map\r
-\r
- OUT_8 SC_Index, MAP_MASK ; Setup Plane selections\r
- INC DX ; DX -> SC_Data\r
-\r
- MOV AL, 08 ; 8 Lines to Process\r
- MOV [BP].TGP_Lines, AL ; Save on Stack\r
-\r
- MOV DS, [BP].TGP_T_SETS ; Point to character set\r
-\r
-@TGP_DECODE_CHAR_BYTE:\r
-\r
- MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String\r
-\r
- MOV BH, [SI] ; Get Bit Map\r
- INC SI ; Point to Next Line\r
- MOV [BP].TGP_T_SETO, SI ; And save new Pointer...\r
-\r
- MOV AH, [BP].TGP_ColorF ; Get Foreground Color\r
-\r
- mov bl,0 ; Clear BL\r
- ROL BX, CL ; BL holds left edge bits\r
- MOV SI, BX ; Use as Table Index\r
- AND SI, CHAR_BITS ; Get Low Bits\r
- MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
- JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set\r
-\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
- ;Now Do Middle/Last Band\r
-\r
-@TGP_NO_LEFT1BITS:\r
-\r
- INC DI ; Point to next Byte\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
-\r
- MOV SI, BX ; Make Lookup Pointer\r
- AND SI, CHAR_BITS ; Get Low Bits\r
- MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
- JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set\r
-\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
-@TGP_NO_MIDDLE1BITS:\r
- XOR CH, ALL_PLANES ; Invert Clip Mask\r
- CMP CL, 4 ; Aligned by 4?\r
- JZ @TGP_NEXT_LINE ; If so, Exit now..\r
-\r
- INC DI ; Point to next Byte\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
- ROL BX, 1 ; Shift 4 bits\r
-\r
- MOV SI, BX ; Make Lookup Pointer\r
- AND SI, CHAR_BITS ; Get Low Bits\r
- MOV AL, Char_Plane_Data[SI] ; Get Mask in AL\r
- JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set\r
-\r
- OUT DX, AL ; Set up Screen Mask\r
- MOV ES:[DI], AH ; Write Foreground color\r
-\r
-@TGP_NO_RIGHT1BITS:\r
-\r
- DEC DI ; Adjust for Next Line Advance\r
-\r
-@TGP_NEXT_LINE:\r
- ADD DI, [BP].TGP_Width ; Point to Next Line\r
- XOR CH, CHAR_BITS ; Flip the Clip mask back\r
-\r
- DEC [BP].TGP_Lines ; Count Down Lines\r
- JZ @TGP_EXIT ; Ok... Done!\r
-\r
- JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey!\r
-\r
-@TGP_EXIT:\r
- ADD SP, 08 ; Deallocate stack workspace\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 8 ; Exit and Clean up Stack\r
-\r
-TGPRINTC ENDP\r
-\r
-\r
-;===============================================================\r
-;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)\r
-;===============================================================\r
-;\r
-; Routine to quickly Print a null terminated ASCII string on the\r
-; active display page up to a maximum length.\r
-;\r
-; ENTRY: String = Far Pointer to ASCII string to print\r
-; MaxLen = # of characters to print if no null found\r
-; Xpos = X position to draw Text at\r
-; Ypos = Y position of to draw Text at\r
-; ColorF = Color to draw text in\r
-; ColorB = Color to set background to\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-PS_STACK STRUC\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- PS_ColorB DW ? ; Background Color\r
- PS_ColorF DW ? ; Text Color\r
- PS_Ypos DW ? ; Y Position to Print at\r
- PS_Xpos DW ? ; X position to Print at\r
- PS_Len DW ? ; Maximum Length of string to print\r
- PS_Text DW ?,? ; Far Ptr to Text String\r
-PS_STACK ENDS\r
-\r
- PUBLIC PRINT_STR\r
-\r
-PRINT_STR PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
-@PS_Print_It:\r
-\r
- MOV CX, [BP].PS_Len ; Get Remaining text Length\r
- JCXZ @PS_Exit ; Exit when out of text\r
-\r
- LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text\r
- MOV AL, ES:[DI] ; AL = Text Character\r
- AND AX, 00FFh ; Clear High Word\r
- JZ @PS_Exit ; Exit if null character\r
-\r
- DEC [BP].PS_Len ; Remaining Text length--\r
- INC [BP].PS_Text ; Point to Next text char\r
-\r
- ; Set up Call to GPRINTC\r
-\r
- PUSH AX ; Set Character Parameter\r
- MOV BX, [BP].PS_Xpos ; Get Xpos\r
- PUSH BX ; Set Xpos Parameter\r
- ADD BX, 8 ; Advance 1 Char to Right\r
- MOV [BP].PS_Xpos, BX ; Save for next time through\r
-\r
- MOV BX, [BP].PS_Ypos ; Get Ypos\r
- PUSH BX ; Set Ypos Parameter\r
-\r
- MOV BX, [BP].PS_ColorF ; Get Text Color\r
- PUSH BX ; Set ColorF Parameter\r
-\r
- MOV BX, [BP].PS_ColorB ; Get Background Color\r
- PUSH BX ; Set ColorB Parameter\r
-\r
- CALL f GPRINTC ; Print Character!\r
- JMP s @PS_Print_It ; Process next character\r
-\r
-@PS_Exit:\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 14 ; Exit and Clean up Stack\r
-\r
-PRINT_STR ENDP\r
-\r
-\r
-;================================================================\r
-;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)\r
-;================================================================\r
-;\r
-; Routine to quickly transparently Print a null terminated ASCII\r
-; string on the active display page up to a maximum length.\r
-;\r
-; ENTRY: String = Far Pointer to ASCII string to print\r
-; MaxLen = # of characters to print if no null found\r
-; Xpos = X position to draw Text at\r
-; Ypos = Y position of to draw Text at\r
-; ColorF = Color to draw text in\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-TPS_STACK STRUC\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- TPS_ColorF DW ? ; Text Color\r
- TPS_Ypos DW ? ; Y Position to Print at\r
- TPS_Xpos DW ? ; X position to Print at\r
- TPS_Len DW ? ; Maximum Length of string to print\r
- TPS_Text DW ?,? ; Far Ptr to Text String\r
-TPS_STACK ENDS\r
-\r
- PUBLIC TPRINT_STR\r
-\r
-TPRINT_STR PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
-@TPS_Print_It:\r
-\r
- MOV CX, [BP].TPS_Len ; Get Remaining text Length\r
- JCXZ @TPS_Exit ; Exit when out of text\r
-\r
- LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text\r
- MOV AL, ES:[DI] ; AL = Text Character\r
- AND AX, 00FFh ; Clear High Word\r
- JZ @TPS_Exit ; Exit if null character\r
-\r
- DEC [BP].TPS_Len ; Remaining Text length--\r
- INC [BP].TPS_Text ; Point to Next text char\r
-\r
- ; Set up Call to TGPRINTC\r
-\r
- PUSH AX ; Set Character Parameter\r
- MOV BX, [BP].TPS_Xpos ; Get Xpos\r
- PUSH BX ; Set Xpos Parameter\r
- ADD BX, 8 ; Advance 1 Char to Right\r
- MOV [BP].TPS_Xpos, BX ; Save for next time through\r
-\r
- MOV BX, [BP].TPS_Ypos ; Get Ypos\r
- PUSH BX ; Set Ypos Parameter\r
-\r
- MOV BX, [BP].TPS_ColorF ; Get Text Color\r
- PUSH BX ; Set ColorF Parameter\r
-\r
- CALL f TGPRINTC ; Print Character!\r
- JMP s @TPS_Print_It ; Process next character\r
-\r
-@TPS_Exit:\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 12 ; Exit and Clean up Stack\r
-\r
-TPRINT_STR ENDP\r
-\r
-\r
-;===========================================\r
-;SET_DISPLAY_FONT(SEG FontData, FontNumber%)\r
-;===========================================\r
-;\r
-; Allows the user to specify their own font data for\r
-; wither the lower or upper 128 characters.\r
-;\r
-; ENTRY: FontData = Far Pointer to Font Bitmaps\r
-; FontNumber = Which half of set this is\r
-; = 0, Lower 128 characters\r
-; = 1, Upper 128 characters\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-SDF_STACK STRUC\r
- DW ? ; BP\r
- DD ? ; Caller\r
- SDF_Which DW ? ; Hi Table/Low Table Flag\r
- SDF_Font DD ? ; Far Ptr to Font Table\r
-SDF_STACK ENDS\r
-\r
- PUBLIC SET_DISPLAY_FONT\r
-\r
-SET_DISPLAY_FONT PROC FAR\r
-\r
- PUSH BP ; Preserve Registers\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, [BP].SDF_Font ; Get Far Ptr to Font\r
-\r
- MOV SI, o CHARSET_LOW ; Assume Lower 128 chars\r
- TEST [BP].SDF_Which, 1 ; Font #1 selected?\r
- JZ @SDF_Set_Font ; If not, skip ahead\r
-\r
- MOV SI, o CHARSET_HI ; Ah, really it's 128-255\r
-\r
-@SDF_Set_Font:\r
- MOV [SI], DI ; Set Font Pointer Offset\r
- MOV [SI+2], ES ; Set Font Pointer Segment\r
-\r
- POP BP ; Restore Registers\r
- RET 6 ; We are Done.. Outa here\r
-\r
-SET_DISPLAY_FONT ENDP\r
-\r
-\r
- ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====\r
-\r
-;======================================================\r
-;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)\r
-;======================================================\r
-;\r
-; Draws a variable sized Graphics Bitmap such as a\r
-; picture or an Icon on the current Display Page in\r
-; Mode X. The Bitmap is stored in a linear byte array\r
-; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)\r
-; This is the same linear manner as mode 13h graphics.\r
-;\r
-; ENTRY: Image = Far Pointer to Bitmap Data\r
-; Xpos = X position to Place Upper Left pixel at\r
-; Ypos = Y position to Place Upper Left pixel at\r
-; Width = Width of the Bitmap in Pixels\r
-; Height = Height of the Bitmap in Pixels\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-DB_STACK STRUC\r
- DB_LineO DW ? ; Offset to Next Line\r
- DB_PixCount DW ? ; (Minimum) # of Pixels/Line\r
- DB_Start DW ? ; Addr of Upper Left Pixel\r
- DB_PixSkew DW ? ; # of bytes to Adjust EOL\r
- DB_SkewFlag DW ? ; Extra Pix on Plane Flag\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- DB_Height DW ? ; Height of Bitmap in Pixels\r
- DB_Width DW ? ; Width of Bitmap in Pixels\r
- DB_Ypos DW ? ; Y position to Draw Bitmap at\r
- DB_Xpos DW ? ; X position to Draw Bitmap at\r
- DB_Image DD ? ; Far Pointer to Graphics Bitmap\r
-DB_STACK ENDS\r
-\r
- PUBLIC DRAW_BITMAP\r
-\r
-DRAW_BITMAP PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- SUB SP, 10 ; Allocate workspace\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
- CLD ; Direction Flag = Forward\r
-\r
- MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos\r
- MUL SCREEN_WIDTH ; AX = Offset to Line Ypos\r
-\r
- MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos\r
- MOV CL, BL ; Save Plane # in CL\r
- SHR BX, 1 ; Xpos/4 = Offset Into Line\r
- SHR BX, 1 ; Xpos/4 = Offset Into Line\r
-\r
- ADD DI, AX ; ES:DI -> Start of Line\r
- ADD DI, BX ; ES:DI -> Upper Left Pixel\r
- MOV [BP].DB_Start, DI ; Save Starting Addr\r
-\r
- ; Compute line to line offset\r
-\r
- MOV BX, [BP].DB_Width ; Get Width of Image\r
- MOV DX, BX ; Save Copy in DX\r
- SHR BX, 1 ; /4 = width in bands\r
- SHR BX, 1 ; /4 = width in bands\r
- MOV AX, SCREEN_WIDTH ; Get Screen Width\r
- SUB AX, BX ; - (Bitmap Width/4)\r
-\r
- MOV [BP].DB_LineO, AX ; Save Line Width offset\r
- MOV [BP].DB_PixCount, BX ; Minimum # pix to copy\r
-\r
- AND DX, PLANE_BITS ; Get "partial band" size (0-3)\r
- MOV [BP].DB_PixSkew, DX ; Also End of Line Skew\r
- MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count\r
-\r
- AND CX, PLANE_BITS ; CL = Starting Plane #\r
- MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select\r
- SHL AH, CL ; Select correct Plane\r
- OUT_16 SC_Index, AX ; Select Plane...\r
- MOV BH, AH ; BH = Saved Plane Mask\r
- MOV BL, 4 ; BL = Planes to Copy\r
-\r
-@DB_COPY_PLANE:\r
-\r
- LDS SI, [BP].DB_Image ; DS:SI-> Source Image\r
- MOV DX, [BP].DB_Height ; # of Lines to Copy\r
- MOV DI, [BP].DB_Start ; ES:DI-> Dest pos\r
-\r
-@DB_COPY_LINE:\r
- MOV CX, [BP].DB_PixCount ; Min # to copy\r
-\r
- TEST CL, 0FCh ; 16+PixWide?\r
- JZ @DB_COPY_REMAINDER ; Nope...\r
-\r
- ; Pixel Copy loop has been unrolled to x4\r
-\r
-@DB_COPY_LOOP:\r
- MOVSB ; Copy Bitmap Pixel\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- MOVSB ; Copy Bitmap Pixel\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- MOVSB ; Copy Bitmap Pixel\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- MOVSB ; Copy Bitmap Pixel\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
-\r
- SUB CL, 4 ; Pixels to Copy=-4\r
- TEST CL, 0FCh ; 4+ Pixels Left?\r
- JNZ @DB_COPY_LOOP ; if so, do another block\r
-\r
-@DB_COPY_REMAINDER:\r
- JCXZ @DB_NEXT_LINE ; Any Pixels left on line\r
-\r
-@DB_COPY2:\r
- MOVSB ; Copy Bitmap Pixel\r
- ADD SI,3 ; Skip to Next Byte in same plane\r
- LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done\r
-\r
-@DB_NEXT_LINE:\r
-\r
- ; any Partial Pixels? (some planes only)\r
-\r
- OR CX, [BP].DB_SkewFlag ; Get Skew Count\r
- JZ @DB_NEXT2 ; if no partial pixels\r
-\r
- MOVSB ; Copy Bitmap Pixel\r
- DEC DI ; Back up to align\r
- DEC SI ; Back up to align\r
-\r
-@DB_NEXT2:\r
- ADD SI, [BP].DB_PixSkew ; Adjust Skew\r
- ADD DI, [BP].DB_LineO ; Set to Next Display Line\r
- LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more\r
-\r
- ; Copy Next Plane....\r
-\r
- DEC BL ; Planes to Go--\r
- JZ @DB_Exit ; Hey! We are done\r
-\r
- ROL BH, 1 ; Next Plane in line...\r
- OUT_8 SC_Data, BH ; Select Plane\r
-\r
- CMP AL, 12h ; Carry Set if AL=11h\r
- ADC [BP].DB_Start, 0 ; Screen Addr =+Carry\r
- INC w [BP].DB_Image ; Start @ Next Byte\r
-\r
- SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew\r
- ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1\r
-\r
- JMP s @DB_COPY_PLANE ; Go Copy the Next Plane\r
-\r
-@DB_Exit:\r
- ADD SP, 10 ; Deallocate workspace\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 12 ; Exit and Clean up Stack\r
-\r
-DRAW_BITMAP ENDP\r
-\r
-\r
-;=======================================================\r
-;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)\r
-;=======================================================\r
-;\r
-; Transparently Draws a variable sized Graphics Bitmap\r
-; such as a picture or an Icon on the current Display Page\r
-; in Mode X. Pixels with a value of 0 are not drawn,\r
-; leaving the previous "background" contents intact.\r
-;\r
-; The Bitmap format is the same as for the DRAW_BITMAP function.\r
-;\r
-; ENTRY: Image = Far Pointer to Bitmap Data\r
-; Xpos = X position to Place Upper Left pixel at\r
-; Ypos = Y position to Place Upper Left pixel at\r
-; Width = Width of the Bitmap in Pixels\r
-; Height = Height of the Bitmap in Pixels\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-TB_STACK STRUC\r
- TB_LineO DW ? ; Offset to Next Line\r
- TB_PixCount DW ? ; (Minimum) # of Pixels/Line\r
- TB_Start DW ? ; Addr of Upper Left Pixel\r
- TB_PixSkew DW ? ; # of bytes to Adjust EOL\r
- TB_SkewFlag DW ? ; Extra Pix on Plane Flag\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- TB_Height DW ? ; Height of Bitmap in Pixels\r
- TB_Width DW ? ; Width of Bitmap in Pixels\r
- TB_Ypos DW ? ; Y position to Draw Bitmap at\r
- TB_Xpos DW ? ; X position to Draw Bitmap at\r
- TB_Image DD ? ; Far Pointer to Graphics Bitmap\r
-TB_STACK ENDS\r
-\r
- PUBLIC TDRAW_BITMAP\r
-\r
-TDRAW_BITMAP PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- SUB SP, 10 ; Allocate workspace\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- LES DI, d CURRENT_PAGE ; Point to Active VGA Page\r
- CLD ; Direction Flag = Forward\r
-\r
- MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos\r
- MUL SCREEN_WIDTH ; AX = Offset to Line Ypos\r
-\r
- MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos\r
- MOV CL, BL ; Save Plane # in CL\r
- SHR BX, 1 ; Xpos/4 = Offset Into Line\r
- SHR BX, 1 ; Xpos/4 = Offset Into Line\r
-\r
- ADD DI, AX ; ES:DI -> Start of Line\r
- ADD DI, BX ; ES:DI -> Upper Left Pixel\r
- MOV [BP].TB_Start, DI ; Save Starting Addr\r
-\r
- ; Compute line to line offset\r
-\r
- MOV BX, [BP].TB_Width ; Get Width of Image\r
- MOV DX, BX ; Save Copy in DX\r
- SHR BX, 1 ; /4 = width in bands\r
- SHR BX, 1 ; /4 = width in bands\r
- MOV AX, SCREEN_WIDTH ; Get Screen Width\r
- SUB AX, BX ; - (Bitmap Width/4)\r
-\r
- MOV [BP].TB_LineO, AX ; Save Line Width offset\r
- MOV [BP].TB_PixCount, BX ; Minimum # pix to copy\r
-\r
- AND DX, PLANE_BITS ; Get "partial band" size (0-3)\r
- MOV [BP].TB_PixSkew, DX ; Also End of Line Skew\r
- MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count\r
-\r
- AND CX, PLANE_BITS ; CL = Starting Plane #\r
- MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select\r
- SHL AH, CL ; Select correct Plane\r
- OUT_16 SC_Index, AX ; Select Plane...\r
- MOV BH, AH ; BH = Saved Plane Mask\r
- MOV BL, 4 ; BL = Planes to Copy\r
-\r
-@TB_COPY_PLANE:\r
-\r
- LDS SI, [BP].TB_Image ; DS:SI-> Source Image\r
- MOV DX, [BP].TB_Height ; # of Lines to Copy\r
- MOV DI, [BP].TB_Start ; ES:DI-> Dest pos\r
-\r
- ; Here AH is set with the value to be considered\r
- ; "Transparent". It can be changed!\r
-\r
- MOV AH, 0 ; Value to Detect 0\r
-\r
-@TB_COPY_LINE:\r
- MOV CX, [BP].TB_PixCount ; Min # to copy\r
-\r
- TEST CL, 0FCh ; 16+PixWide?\r
- JZ @TB_COPY_REMAINDER ; Nope...\r
-\r
- ; Pixel Copy loop has been unrolled to x4\r
-\r
-@TB_COPY_LOOP:\r
- LODSB ; Get Pixel Value in AL\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- CMP AL, AH ; It is "Transparent"?\r
- JE @TB_SKIP_01 ; Skip ahead if so\r
- MOV ES:[DI], AL ; Copy Pixel to VGA screen\r
-\r
-@TB_SKIP_01:\r
- LODSB ; Get Pixel Value in AL\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- CMP AL, AH ; It is "Transparent"?\r
- JE @TB_SKIP_02 ; Skip ahead if so\r
- MOV ES:[DI+1], AL ; Copy Pixel to VGA screen\r
-\r
-@TB_SKIP_02:\r
- LODSB ; Get Pixel Value in AL\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- CMP AL, AH ; It is "Transparent"?\r
- JE @TB_SKIP_03 ; Skip ahead if so\r
- MOV ES:[DI+2], AL ; Copy Pixel to VGA screen\r
-\r
-@TB_SKIP_03:\r
- LODSB ; Get Pixel Value in AL\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- CMP AL, AH ; It is "Transparent"?\r
- JE @TB_SKIP_04 ; Skip ahead if so\r
- MOV ES:[DI+3], AL ; Copy Pixel to VGA screen\r
-\r
-@TB_SKIP_04:\r
- ADD DI, 4 ; Adjust Pixel Write Location\r
- SUB CL, 4 ; Pixels to Copy=-4\r
- TEST CL, 0FCh ; 4+ Pixels Left?\r
- JNZ @TB_COPY_LOOP ; if so, do another block\r
-\r
-@TB_COPY_REMAINDER:\r
- JCXZ @TB_NEXT_LINE ; Any Pixels left on line\r
-\r
-@TB_COPY2:\r
- LODSB ; Get Pixel Value in AL\r
- ADD SI, 3 ; Skip to Next Byte in same plane\r
- CMP AL, AH ; It is "Transparent"?\r
- JE @TB_SKIP_05 ; Skip ahead if so\r
- MOV ES:[DI], AL ; Copy Pixel to VGA screen\r
-\r
-@TB_SKIP_05:\r
- INC DI ; Advance Dest Addr\r
- LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done\r
-\r
-@TB_NEXT_LINE:\r
-\r
- ; any Partial Pixels? (some planes only)\r
-\r
- OR CX, [BP].TB_SkewFlag ; Get Skew Count\r
- JZ @TB_NEXT2 ; if no partial pixels\r
-\r
- LODSB ; Get Pixel Value in AL\r
- DEC SI ; Backup to Align\r
- CMP AL, AH ; It is "Transparent"?\r
- JE @TB_NEXT2 ; Skip ahead if so\r
- MOV ES:[DI], AL ; Copy Pixel to VGA screen\r
-\r
-@TB_NEXT2:\r
- ADD SI, [BP].TB_PixSkew ; Adjust Skew\r
- ADD DI, [BP].TB_LineO ; Set to Next Display Line\r
- LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More\r
-\r
- ;Copy Next Plane....\r
-\r
- DEC BL ; Planes to Go--\r
- JZ @TB_Exit ; Hey! We are done\r
-\r
- ROL BH, 1 ; Next Plane in line...\r
- OUT_8 SC_Data, BH ; Select Plane\r
-\r
- CMP AL, 12h ; Carry Set if AL=11h\r
- ADC [BP].TB_Start, 0 ; Screen Addr =+Carry\r
- INC w [BP].TB_Image ; Start @ Next Byte\r
-\r
- SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew\r
- ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1\r
-\r
- JMP @TB_COPY_PLANE ; Go Copy the next Plane\r
-\r
-@TB_Exit:\r
- ADD SP, 10 ; Deallocate workspace\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 12 ; Exit and Clean up Stack\r
-\r
-TDRAW_BITMAP ENDP\r
-\r
-\r
- ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====\r
-\r
-;==================================\r
-;COPY_PAGE (SourcePage%, DestPage%)\r
-;==================================\r
-;\r
-; Duplicate on display page onto another\r
-;\r
-; ENTRY: SourcePage = Display Page # to Duplicate\r
-; DestPage = Display Page # to hold copy\r
-;\r
-; EXIT: No meaningful values returned\r
-;\r
-\r
-CP_STACK STRUC\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- CP_DestP DW ? ; Page to hold copied image\r
- CP_SourceP DW ? ; Page to Make copy from\r
-CP_STACK ENDS\r
-\r
- PUBLIC COPY_PAGE\r
-\r
-COPY_PAGE PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- MOV BP, SP ; Set up Stack Frame\r
- CLD ; Block Xfer Forwards\r
-\r
- ; Make sure Page #'s are valid\r
-\r
- MOV AX, [BP].CP_SourceP ; Get Source Page #\r
- CMP AX, LAST_PAGE ; is it > Max Page #?\r
- JAE @CP_Exit ; if so, abort\r
-\r
- MOV BX, [BP].CP_DestP ; Get Destination Page #\r
- CMP BX, LAST_PAGE ; is it > Max Page #?\r
- JAE @CP_Exit ; if so, abort\r
-\r
- CMP AX, BX ; Pages #'s the same?\r
- JE @CP_Exit ; if so, abort\r
-\r
- ; Setup DS:SI and ES:DI to Video Pages\r
-\r
- SHL BX, 1 ; Scale index to Word\r
- MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page\r
-\r
- MOV BX, AX ; Index to Source page\r
- SHL BX, 1 ; Scale index to Word\r
- MOV SI, PAGE_ADDR[BX] ; Offset to Source Page\r
-\r
- MOV CX, PAGE_SIZE ; Get size of Page\r
- MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment\r
- MOV ES, AX ; ES:DI -> Dest Page\r
- MOV DS, AX ; DS:SI -> Source Page\r
-\r
- ; Setup VGA registers for Mem to Mem copy\r
-\r
- OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on\r
- OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes\r
-\r
- ; Note.. Do *NOT* use MOVSW or MOVSD - they will\r
- ; Screw with the latches which are 8 bits x 4\r
-\r
- REP MOVSB ; Copy entire Page!\r
-\r
- ; Reset VGA for normal memory access\r
-\r
- OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off\r
-\r
-@CP_Exit:\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 4 ; Exit and Clean up Stack\r
-\r
-COPY_PAGE ENDP\r
-\r
-\r
-;==========================================================================\r
-;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)\r
-;==========================================================================\r
-;\r
-; Copies a Bitmap Image from one Display Page to Another\r
-; This Routine is Limited to copying Images with the same\r
-; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4)\r
-; Copying an Image to the Same Page is supported, but results\r
-; may be defined when the when the rectangular areas\r
-; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) -\r
-; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...\r
-; No Paramter checking to done to insure that\r
-; X2 >= X1 and Y2 >= Y1. Be Careful...\r
-;\r
-; ENTRY: SourcePage = Display Page # with Source Image\r
-; X1 = Upper Left Xpos of Source Image\r
-; Y1 = Upper Left Ypos of Source Image\r
-; X2 = Lower Right Xpos of Source Image\r
-; Y2 = Lower Right Ypos of Source Image\r
-; DestPage = Display Page # to copy Image to\r
-; DestX1 = Xpos to Copy UL Corner of Image to\r
-; DestY1 = Ypos to Copy UL Corner of Image to\r
-;\r
-; EXIT: AX = Success Flag: 0 = Failure / -1= Success\r
-;\r
-\r
-CB_STACK STRUC\r
- CB_Height DW ? ; Height of Image in Lines\r
- CB_Width DW ? ; Width of Image in "bands"\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DI, SI, DS, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DW ?x1 ; DS, DI, SI, BP\r
- DD ? ; Caller\r
- CB_DestY1 DW ? ; Destination Ypos\r
- CB_DestX1 DW ? ; Destination Xpos\r
- CB_DestP DW ? ; Page to Copy Bitmap To\r
- CB_Y2 DW ? ; LR Ypos of Image\r
- CB_X2 DW ? ; LR Xpos of Image\r
- CB_Y1 DW ? ; UL Ypos of Image\r
- CB_X1 DW ? ; UL Xpos of Image\r
- CB_SourceP DW ? ; Page containing Source Bitmap\r
-CB_STACK ENDS\r
-\r
- PUBLIC COPY_BITMAP\r
-\r
-COPY_BITMAP PROC FAR\r
-\r
- ;PUSHx BP, DS, SI, DI ; Preserve Important Registers\r
- push bp\r
- push ds\r
- push si\r
- push di\r
- SUB SP, 4 ; Allocate WorkSpace on Stack\r
- MOV BP, SP ; Set up Stack Frame\r
-\r
- ; Prep Registers (and keep jumps short!)\r
-\r
- MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram\r
- CLD ; Block Xfer Forwards\r
-\r
- ; Make sure Parameters are valid\r
-\r
- MOV BX, [BP].CB_SourceP ; Get Source Page #\r
- CMP BX, LAST_PAGE ; is it > Max Page #?\r
- JAE @CB_Abort ; if so, abort\r
-\r
- MOV CX, [BP].CB_DestP ; Get Destination Page #\r
- CMP CX, LAST_PAGE ; is it > Max Page #?\r
- JAE @CB_Abort ; if so, abort\r
-\r
- MOV AX, [BP].CB_X1 ; Get Source X1\r
- XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1\r
- AND AX, PLANE_BITS ; Check Plane Bits\r
- JNZ @CB_Abort ; They should cancel out\r
-\r
- ; Setup for Copy processing\r
-\r
- OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select\r
- OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on\r
-\r
- ; Compute Info About Images, Setup ES:SI & ES:DI\r
-\r
- MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines\r
- SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1\r
- INC AX ; (add 1 since were not 0 based)\r
- MOV [BP].CB_Height, AX ; Save on Stack for later use\r
-\r
- MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels\r
- MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1\r
- SHR AX, 1 ; Get X2 Band (X2 / 4)\r
- SHR DX, 1 ; Get X1 Band (X1 / 4)\r
- SHR AX, 1 ; Get X2 Band (X2 / 4)\r
- SHR DX, 1 ; Get X1 Band (X1 / 4)\r
- SUB AX, DX ; AX = # of Bands - 1\r
- INC AX ; AX = # of Bands\r
- MOV [BP].CB_Width, AX ; Save on Stack for later use\r
-\r
- SHL BX, 1 ; Scale Source Page to Word\r
- MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page\r
- MOV AX, [BP].CB_Y1 ; Get Source Y1 Line\r
- MUL SCREEN_WIDTH ; AX = Offset to Line Y1\r
- ADD SI, AX ; SI = Offset to Line Y1\r
- MOV AX, [BP].CB_X1 ; Get Source X1\r
- SHR AX, 1 ; X1 / 4 = Byte offset\r
- SHR AX, 1 ; X1 / 4 = Byte offset\r
- ADD SI, AX ; SI = Byte Offset to (X1,Y1)\r
-\r
- MOV BX, CX ; Dest Page Index to BX\r
- SHL BX, 1 ; Scale Source Page to Word\r
- MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page\r
- MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line\r
- MUL SCREEN_WIDTH ; AX = Offset to Line Y1\r
- ADD DI, AX ; DI = Offset to Line Y1\r
- MOV AX, [BP].CB_DestX1 ; Get Dest X1\r
- SHR AX, 1 ; X1 / 4 = Byte offset\r
- SHR AX, 1 ; X1 / 4 = Byte offset\r
- ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1)\r
-\r
- MOV CX, [BP].CB_Width ; CX = Width of Image (Bands)\r
- DEC CX ; CX = 1?\r
- JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band\r
-\r
- MOV BX, [BP].CB_X1 ; Get Source X1\r
- AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?)\r
- JZ @CB_Check_Right ; if so, check right alignment\r
- JNZ @CB_Left_Band ; not aligned? well..\r
-\r
-@CB_Abort:\r
- mov ax,0 ; Return False (Failure)\r
- JMP @CB_Exit ; and Finish Up\r
-\r
- ; Copy when Left & Right Clip Masks overlap...\r
-\r
-@CB_Only_One_Band:\r
- MOV BX, [BP].CB_X1 ; Get Left Clip Mask\r
- AND BX, PLANE_BITS ; Mask out Row #\r
- MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask\r
- MOV BX, [BP].CB_X2 ; Get Right Clip Mask\r
- AND BX, PLANE_BITS ; Mask out Row #\r
- AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte\r
-\r
- OUT_8 SC_Data, AL ; Clip For Left & Right Masks\r
-\r
- MOV CX, [BP].CB_Height ; CX = # of Lines to Copy\r
- MOV DX, SCREEN_WIDTH ; DX = Width of Screen\r
- mov bx,0 ; BX = Offset into Image\r
-\r
-@CB_One_Loop:\r
- MOV AL, ES:[SI+BX] ; Load Latches\r
- MOV ES:[DI+BX], AL ; Unload Latches\r
- ADD BX, DX ; Advance Offset to Next Line\r
- LOOPjz CX, @CB_One_Done ; Exit Loop if Finished\r
-\r
- MOV AL, ES:[SI+BX] ; Load Latches\r
- MOV ES:[DI+BX], AL ; Unload Latches\r
- ADD BX, DX ; Advance Offset to Next Line\r
- LOOPx CX, @CB_One_Loop ; Loop until Finished\r
-\r
-@CB_One_Done:\r
- JMP @CB_Finish ; Outa Here!\r
-\r
- ; Copy Left Edge of Bitmap\r
-\r
-@CB_Left_Band:\r
-\r
- OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask\r
-\r
- MOV CX, [BP].CB_Height ; CX = # of Lines to Copy\r
- MOV DX, SCREEN_WIDTH ; DX = Width of Screen\r
- mov bx,0 ; BX = Offset into Image\r
-\r
-@CB_Left_Loop:\r
- MOV AL, ES:[SI+BX] ; Load Latches\r
- MOV ES:[DI+BX], AL ; Unload Latches\r
- ADD BX, DX ; Advance Offset to Next Line\r
- LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished\r
-\r
- MOV AL, ES:[SI+BX] ; Load Latches\r
- MOV ES:[DI+BX], AL ; Unload Latches\r
- ADD BX, DX ; Advance Offset to Next Line\r
- LOOPx CX, @CB_Left_Loop ; Loop until Finished\r
-\r
-@CB_Left_Done:\r
- INC DI ; Move Dest Over 1 band\r
- INC SI ; Move Source Over 1 band\r
- DEC [BP].CB_Width ; Band Width--\r
-\r
- ; Determine if Right Edge of Bitmap needs special copy\r
-\r
-@CB_Check_Right:\r
- MOV BX, [BP].CB_X2 ; Get Source X2\r
- AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?)\r
- CMP BL, 03h ; Plane = 3?\r
- JE @CB_Copy_Middle ; Copy the Middle then!\r
-\r
- ; Copy Right Edge of Bitmap\r
-\r
-@CB_Right_Band:\r
-\r
- OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask\r
-\r
- DEC [BP].CB_Width ; Band Width--\r
- MOV CX, [BP].CB_Height ; CX = # of Lines to Copy\r
- MOV DX, SCREEN_WIDTH ; DX = Width of Screen\r
- MOV BX, [BP].CB_Width ; BX = Offset to Right Edge\r
-\r
-@CB_Right_Loop:\r
- MOV AL, ES:[SI+BX] ; Load Latches\r
- MOV ES:[DI+BX], AL ; Unload Latches\r
- ADD BX, DX ; Advance Offset to Next Line\r
- LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished\r
-\r
- MOV AL, ES:[SI+BX] ; Load Latches\r
- MOV ES:[DI+BX], AL ; Unload Latches\r
- ADD BX, DX ; Advance Offset to Next Line\r
- LOOPx CX, @CB_Right_Loop ; Loop until Finished\r
-\r
-@CB_Right_Done:\r
-\r
- ; Copy the Main Block of the Bitmap\r
-\r
-@CB_Copy_Middle:\r
-\r
- MOV CX, [BP].CB_Width ; Get Width Remaining\r
- JCXZ @CB_Finish ; Exit if Done\r
-\r
- OUT_8 SC_Data, ALL_PLANES ; Copy all Planes\r
-\r
- MOV DX, SCREEN_WIDTH ; Get Width of Screen minus\r
- SUB DX, CX ; Image width (for Adjustment)\r
- MOV AX, [BP].CB_Height ; AX = # of Lines to Copy\r
- MOV BX, CX ; BX = Quick REP reload count\r
- MOV CX, ES ; Move VGA Segment\r
- MOV DS, CX ; Into DS\r
-\r
- ; Actual Copy Loop. REP MOVSB does the work\r
-\r
-@CB_Middle_Copy:\r
- MOV CX, BX ; Recharge Rep Count\r
- REP MOVSB ; Move Bands\r
- LOOPjz AX, @CB_Finish ; Exit Loop if Finished\r
-\r
- ADD SI, DX ; Adjust DS:SI to Next Line\r
- ADD DI, DX ; Adjust ES:DI to Next Line\r
-\r
- MOV CX, BX ; Recharge Rep Count\r
- REP MOVSB ; Move Bands\r
-\r
- ADD SI, DX ; Adjust DS:SI to Next Line\r
- ADD DI, DX ; Adjust ES:DI to Next Line\r
- LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done\r
-\r
-@CB_Finish:\r
- OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on\r
-\r
-@CB_Exit:\r
- ADD SP, 04 ; Deallocate stack workspace\r
- ;POPx DI, SI, DS, BP ; Restore Saved Registers\r
- pop di\r
- pop si\r
- pop ds\r
- pop bp\r
- RET 16 ; Exit and Clean up Stack\r
-\r
-COPY_BITMAP ENDP\r
-\r
- END ; End of Code Segment\r