1 ;========================================================
\r
2 ; MODEX.ASM - A Complete Mode X Library
\r
4 ; Version 1.04 Release, 3 May 1993, By Matt Pritchard
\r
5 ; With considerable input from Michael Abrash
\r
7 ; The following information is donated to the public domain in
\r
8 ; the hopes that save other programmers much frustration.
\r
10 ; If you do use this code in a product, it would be nice if
\r
11 ; you include a line like "Mode X routines by Matt Pritchard"
\r
14 ; =========================================================
\r
16 ; All of this code is designed to be assembled with MASM 5.10a
\r
17 ; but TASM 3.0 could be used as well.
\r
19 ; The routines contained are designed for use in a MEDIUM model
\r
20 ; program. All Routines are FAR, and is assumed that a DGROUP
\r
21 ; data segment exists and that DS will point to it on entry.
\r
23 ; For all routines, the AX, BX, CX, DX, ES and FLAGS registers
\r
24 ; will not be preserved, while the DS, BP, SI and DI registers
\r
25 ; will be preserved.
\r
27 ; Unless specifically noted, All Parameters are assumed to be
\r
28 ; "PASSED BY VALUE". That is, the actual value is placed on
\r
29 ; the stack. When a reference is passed it is assumed to be
\r
30 ; a near pointer to a variable in the DGROUP segment.
\r
32 ; Routines that return a single 16-Bit integer value will
\r
33 ; return that value in the AX register.
\r
35 ; This code will *NOT* run on an 8086/8088 because 80286+
\r
36 ; specific instructions are used. If you have an 8088/86
\r
37 ; and VGA, you can buy an 80386-40 motherboard for about
\r
38 ; $160 and move into the 90's.
\r
40 ; This code is reasonably optimized: Most drawing loops have
\r
41 ; been unrolled once and memory references are minimized by
\r
42 ; keeping stuff in registers when possible.
\r
44 ; Error Trapping varies by Routine. No Clipping is performed
\r
45 ; so the caller should verify that all coordinates are valid.
\r
47 ; Several Macros are used to simplify common 2 or 3 instruction
\r
48 ; sequences. Several Single letter Text Constants also
\r
49 ; simplify common assembler expressions like "WORD PTR".
\r
51 ; ------------------ Mode X Variations ------------------
\r
53 ; Mode # Screen Size Max Pages Aspect Ratio (X:Y)
\r
55 ; 0 320 x 200 4 Pages 1.2:1
\r
56 ; 1 320 x 400 2 Pages 2.4:1
\r
57 ; 2 360 x 200 3 Pages 1.35:1
\r
58 ; 3 360 x 400 1 Page 2.7:1
\r
59 ; 4 320 x 240 3 Pages 1:1
\r
60 ; 5 320 x 480 1 Page 2:1
\r
61 ; 6 360 x 240 3 Pages 1.125:1
\r
62 ; 7 360 x 480 1 Page 2.25:1
\r
64 ; -------------------- The Legal Stuff ------------------
\r
66 ; No warranty, either written or implied, is made as to
\r
67 ; the accuracy and usability of this code product. Use
\r
68 ; at your own risk. Batteries not included. Pepperoni
\r
69 ; and extra cheese available for an additional charge.
\r
71 ; ----------------------- The Author --------------------
\r
73 ; Matt Pritchard is a paid programmer who'd rather be
\r
74 ; writing games. He can be reached at: P.O. Box 140264,
\r
75 ; Irving, TX 75014 USA. Michael Abrash is a living
\r
76 ; god, who now works for Bill Gates (Microsoft).
\r
78 ; -------------------- Revision History -----------------
\r
79 ; 4-12-93: v1.02 - SET_POINT & READ_POINT now saves DI
\r
80 ; SET_MODEX now saves SI
\r
81 ; 5-3-93: v1.04 - added LOAD_DAC_REGISTERS and
\r
82 ; READ_DAC_REGISTERS. Expanded CLR Macro
\r
83 ; to handle multiple registers
\r
91 ; ===== MACROS =====
\r
93 ; Macro to OUT a 16 bit value to an I/O port
\r
95 OUT_16 MACRO Register, Value
\r
96 IFDIFI <Register>, <DX> ; If DX not setup
\r
97 MOV DX, Register ; then Select Register
\r
99 IFDIFI <Value>, <AX> ; If AX not setup
\r
100 MOV AX, Value ; then Get Data Value
\r
102 OUT DX, AX ; Set I/O Register(s)
\r
105 ; Macro to OUT a 8 bit value to an I/O Port
\r
107 OUT_8 MACRO Register, Value
\r
108 IFDIFI <Register>, <DX> ; If DX not setup
\r
109 MOV DX, Register ; then Select Register
\r
111 IFDIFI <Value>, <AL> ; If AL not Setup
\r
112 MOV AL, Value ; then Get Data Value
\r
114 OUT DX, AL ; Set I/O Register
\r
117 ; macros to PUSH and POP multiple registers
\r
119 ; PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8
\r
121 ; PUSH R1 ; Save R1
\r
122 ; PUSHx R2, R3, R4, R5, R6, R7, R8
\r
126 ; POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8
\r
128 ; POP R1 ; Restore R1
\r
129 ; POPx R2, R3, R4, R5, R6, R7, R8
\r
133 ; Macro to Clear Registers to 0
\r
135 ; CLR MACRO Register, R2, R3, R4;, R5, R6
\r
137 ; XOR Register, Register ; Set Register = 0
\r
138 ; CLR R2, R3, R4;, R5, R6
\r
142 ; Macros to Decrement Counter & Jump on Condition
\r
144 LOOPx MACRO Register, Destination
\r
145 DEC Register ; Counter--
\r
146 JNZ Destination ; Jump if not 0
\r
149 LOOPjz MACRO Register, Destination
\r
150 DEC Register ; Counter--
\r
151 JZ Destination ; Jump if 0
\r
155 ; ===== General Constants =====
\r
169 ; ===== VGA Register Values =====
\r
171 VGA_Segment EQU 0A000h ; Vga Memory Segment
\r
173 ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller
\r
174 GC_Index EQU 03CEh ; VGA Graphics Controller
\r
175 SC_Index EQU 03C4h ; VGA Sequencer Controller
\r
176 SC_Data EQU 03C5h ; VGA Sequencer Data Port
\r
177 CRTC_Index EQU 03D4h ; VGA CRT Controller
\r
178 CRTC_Data EQU 03D5h ; VGA CRT Controller Data
\r
179 MISC_OUTPUT EQU 03C2h ; VGA Misc Register
\r
180 INPUT_1 EQU 03DAh ; Input Status #1 Register
\r
182 DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register
\r
183 DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register
\r
184 PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W
\r
186 PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg
\r
187 MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg
\r
188 READ_MAP EQU 004h ; GC Index: Read Map Register
\r
189 START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi
\r
190 START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo
\r
192 MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1
\r
193 MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1
\r
194 ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes
\r
196 CHAIN4_OFF EQU 00604h ; Chain 4 mode Off
\r
197 ASYNC_RESET EQU 00100h ; (A)synchronous Reset
\r
198 SEQU_RESTART EQU 00300h ; Sequencer Restart
\r
200 LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches
\r
201 LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU
\r
203 VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit
\r
204 PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane #
\r
205 ALL_PLANES EQU 0Fh ; All Bit Planes Selected
\r
206 CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data
\r
208 GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set
\r
209 ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer
\r
210 ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer
\r
212 ; Constants Specific for these routines
\r
214 NUM_MODES EQU 8 ; # of Mode X Variations
\r
216 ; Specific Mode Data Table format...
\r
218 Mode_Data_Table STRUC
\r
219 M_MiscR DB ? ; Value of MISC_OUTPUT register
\r
220 M_Pages DB ? ; Maximum Possible # of pages
\r
221 M_XSize DW ? ; X Size Displayed on screen
\r
222 M_YSize DW ? ; Y Size Displayed on screen
\r
223 M_XMax DW ? ; Maximum Possible X Size
\r
224 M_YMax DW ? ; Maximum Possible Y Size
\r
225 M_CRTC DW ? ; Table of CRTC register values
\r
226 Mode_Data_Table ENDS
\r
228 ; ===== DGROUP STORAGE NEEDED (42 BYTES) =====
\r
232 SCREEN_WIDTH DW 0 ; Width of a line in Bytes
\r
233 SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels
\r
235 LAST_PAGE DW 0 ; # of Display Pages
\r
236 PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page
\r
238 PAGE_SIZE DW 0 ; Size of Page in Addr Bytes
\r
240 DISPLAY_PAGE DW 0 ; Page # currently displayed
\r
241 ACTIVE_PAGE DW 0 ; Page # currently active
\r
243 CURRENT_PAGE DW 0 ; Offset of current Page
\r
244 CURRENT_SEGMENT DW 0 ; Segment of VGA memory
\r
246 CURRENT_XOFFSET DW 0 ; Current Display X Offset
\r
247 CURRENT_YOFFSET DW 0 ; Current Display Y Offset
\r
249 CURRENT_MOFFSET DW 0 ; Current Start Offset
\r
251 MAX_XOFFSET DW 0 ; Current Display X Offset
\r
252 MAX_YOFFSET DW 0 ; Current Display Y Offset
\r
254 CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127
\r
255 CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255
\r
259 ; ===== DATA TABLES =====
\r
261 ; Data Tables, Put in Code Segment for Easy Access
\r
262 ; (Like when all the other Segment Registers are in
\r
263 ; use!!) and reduced DGROUP requirements...
\r
265 ; Bit Mask Tables for Left/Right/Character Masks
\r
267 Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H
\r
269 Right_Clip_Mask DB 01H, 03H, 07H, 0FH
\r
271 ; Bit Patterns for converting character fonts
\r
273 Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH
\r
274 DB 01H,09H,05H,0DH,03H,0BH,07H,0FH
\r
276 ; CRTC Register Values for Various Configurations
\r
278 MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes
\r
279 DW 04009H ; Cell Height (1 Scan Line)
\r
280 DW 00014H ; Dword Mode off
\r
281 DW 0E317H ; turn on Byte Mode
\r
282 DW nil ; End of CRTC Data for 400/480 Line Mode
\r
284 MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes
\r
285 DW 04109H ; Cell Height (2 Scan Lines)
\r
286 DW 00014H ; Dword Mode off
\r
287 DW 0E317H ; turn on Byte Mode
\r
288 DW nil ; End of CRTC Data for 200/240 Line Mode
\r
290 MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels
\r
291 DW 05F00H ; Horz total
\r
292 DW 04F01H ; Horz Displayed
\r
293 DW 05002H ; Start Horz Blanking
\r
294 DW 08203H ; End Horz Blanking
\r
295 DW 05404H ; Start H Sync
\r
296 DW 08005H ; End H Sync
\r
297 DW nil ; End of CRTC Data for 320 Horz pixels
\r
299 MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels
\r
300 DW 06B00H ; Horz total
\r
301 DW 05901H ; Horz Displayed
\r
302 DW 05A02H ; Start Horz Blanking
\r
303 DW 08E03H ; End Horz Blanking
\r
304 DW 05E04H ; Start H Sync
\r
305 DW 08A05H ; End H Sync
\r
306 DW nil ; End of CRTC Data for 360 Horz pixels
\r
309 MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes
\r
310 DW 0BF06H ; Vertical Total
\r
311 DW 01F07H ; Overflow
\r
312 DW 09C10H ; V Sync Start
\r
313 DW 08E11H ; V Sync End/Prot Cr0 Cr7
\r
314 DW 08F12H ; Vertical Displayed
\r
315 DW 09615H ; V Blank Start
\r
316 DW 0B916H ; V Blank End
\r
317 DW nil ; End of CRTC Data for 200/400 Lines
\r
320 MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes
\r
321 DW 00D06H ; Vertical Total
\r
322 DW 03E07H ; Overflow
\r
323 DW 0EA10H ; V Sync Start
\r
324 DW 08C11H ; V Sync End/Prot Cr0 Cr7
\r
325 DW 0DF12H ; Vertical Displayed
\r
326 DW 0E715H ; V Blank Start
\r
327 DW 00616H ; V Blank End
\r
328 DW nil ; End of CRTC Data for 240/480 Lines
\r
330 ; Table of Display Mode Tables
\r
333 DW o MODE_320x200, o MODE_320x400
\r
334 DW o MODE_360x200, o MODE_360x400
\r
335 DW o MODE_320x240, o MODE_320x480
\r
336 DW o MODE_360x240, o MODE_360x480
\r
338 ; Table of Display Mode Components
\r
340 MODE_320x200: ; Data for 320 by 200 Pixels
\r
342 DB 063h ; 400 scan Lines & 25 Mhz Clock
\r
343 DB 4 ; Maximum of 4 Pages
\r
344 DW 320, 200 ; Displayed Pixels (X,Y)
\r
345 DW 1302, 816 ; Max Possible X and Y Sizes
\r
347 DW o MODE_320_Wide, o MODE_200_Tall
\r
348 DW o MODE_Double_Line, nil
\r
350 MODE_320x400: ; Data for 320 by 400 Pixels
\r
352 DB 063h ; 400 scan Lines & 25 Mhz Clock
\r
353 DB 2 ; Maximum of 2 Pages
\r
354 DW 320, 400 ; Displayed Pixels X,Y
\r
355 DW 648, 816 ; Max Possible X and Y Sizes
\r
357 DW o MODE_320_Wide, o MODE_400_Tall
\r
358 DW o MODE_Single_Line, nil
\r
360 MODE_360x240: ; Data for 360 by 240 Pixels
\r
362 DB 0E7h ; 480 scan Lines & 28 Mhz Clock
\r
363 DB 3 ; Maximum of 3 Pages
\r
364 DW 360, 240 ; Displayed Pixels X,Y
\r
365 DW 1092, 728 ; Max Possible X and Y Sizes
\r
367 DW o MODE_360_Wide, o MODE_240_Tall
\r
368 DW o MODE_Double_Line , nil
\r
370 MODE_360x480: ; Data for 360 by 480 Pixels
\r
372 DB 0E7h ; 480 scan Lines & 28 Mhz Clock
\r
373 DB 1 ; Only 1 Page Possible
\r
374 DW 360, 480 ; Displayed Pixels X,Y
\r
375 DW 544, 728 ; Max Possible X and Y Sizes
\r
377 DW o MODE_360_Wide, o MODE_480_Tall
\r
378 DW o MODE_Single_Line , nil
\r
380 MODE_320x240: ; Data for 320 by 240 Pixels
\r
382 DB 0E3h ; 480 scan Lines & 25 Mhz Clock
\r
383 DB 3 ; Maximum of 3 Pages
\r
384 DW 320, 240 ; Displayed Pixels X,Y
\r
385 DW 1088, 818 ; Max Possible X and Y Sizes
\r
387 DW o MODE_320_Wide, o MODE_240_Tall
\r
388 DW o MODE_Double_Line, nil
\r
390 MODE_320x480: ; Data for 320 by 480 Pixels
\r
392 DB 0E3h ; 480 scan Lines & 25 Mhz Clock
\r
393 DB 1 ; Only 1 Page Possible
\r
394 DW 320, 480 ; Displayed Pixels X,Y
\r
395 DW 540, 818 ; Max Possible X and Y Sizes
\r
397 DW o MODE_320_WIDE, o MODE_480_Tall
\r
398 DW o MODE_Single_Line, nil
\r
400 MODE_360x200: ; Data for 360 by 200 Pixels
\r
402 DB 067h ; 400 scan Lines & 28 Mhz Clock
\r
403 DB 3 ; Maximum of 3 Pages
\r
404 DW 360, 200 ; Displayed Pixels (X,Y)
\r
405 DW 1302, 728 ; Max Possible X and Y Sizes
\r
407 DW o MODE_360_Wide, MODE_200_Tall
\r
408 DW o MODE_Double_Line, nil
\r
410 MODE_360x400: ; Data for 360 by 400 Pixels
\r
412 DB 067h ; 400 scan Lines & 28 Mhz Clock
\r
413 DB 1 ; Maximum of 1 Pages
\r
414 DW 360, 400 ; Displayed Pixels X,Y
\r
415 DW 648, 816 ; Max Possible X and Y Sizes
\r
417 DW o MODE_360_Wide, MODE_400_Tall
\r
418 DW o MODE_Single_Line, nil
\r
421 ; ===== MODE X SETUP ROUTINES =====
\r
423 ;======================================================
\r
424 ;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%)
\r
425 ;======================================================
\r
427 ; Sets Up the specified version of Mode X. Allows for
\r
428 ; the setup of multiple video pages, and a virtual
\r
429 ; screen which can be larger than the displayed screen
\r
430 ; (which can then be scrolled a pixel at a time)
\r
432 ; ENTRY: ModeType = Desired Screen Resolution (0-7)
\r
434 ; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio
\r
435 ; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio
\r
436 ; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio
\r
437 ; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio
\r
438 ; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio
\r
439 ; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio
\r
440 ; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio
\r
441 ; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio
\r
443 ; MaxXpos = The Desired Virtual Screen Width
\r
444 ; MaxYpos = The Desired Virtual Screen Height
\r
445 ; Pages = The Desired # of Video Pages
\r
447 ; EXIT: AX = Success Flag: >0 = Failure / 0 = Success
\r
451 SVM_Table DW ? ; Offset of Mode Info Table
\r
452 DW ?x1 ; DI, SI, DS, BP
\r
453 DW ?x1 ; DI, SI, DS, BP
\r
454 DW ?x1 ; DI, SI, DS, BP
\r
455 DW ?x1 ; DI, SI, DS, BP
\r
457 SVM_Pages DW ? ; # of Screen Pages desired
\r
458 SVM_Ysize DW ? ; Vertical Screen Size Desired
\r
459 SVM_Xsize DW ? ; Horizontal Screen Size Desired
\r
460 SVM_Mode DW ? ; Display Resolution Desired
\r
463 PUBLIC SET_VGA_MODEX
\r
465 SET_VGA_MODEX PROC FAR
\r
467 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
472 SUB SP, 2 ; Allocate workspace
\r
473 MOV BP, SP ; Set up Stack Frame
\r
475 ; Check Legality of Mode Request....
\r
477 MOV BX, [BP].SVM_Mode ; Get Requested Mode #
\r
478 CMP BX, NUM_MODES ; Is it 0..7?
\r
479 JAE @SVM_BadModeSetup1 ; If Not, Error out
\r
481 SHL BX, 1 ; Scale BX
\r
482 MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info
\r
483 MOV [BP].SVM_Table, SI ; Save ptr for later use
\r
485 ; Check # of Requested Display Pages
\r
487 MOV CX, [BP].SVM_Pages ; Get # of Requested Pages
\r
488 ;CLR CH ; Set Hi Word = 0!
\r
489 mov ch,0 ; Set Hi Word = 0!
\r
490 CMP CL, CS:[SI].M_Pages ; Check # Pages for mode
\r
491 JA @SVM_BadModeSetup2 ; Report Error if too Many Pages
\r
492 JCXZ @SVM_BadModeSetup3 ; Report Error if 0 Pages
\r
494 ; Check Validity of X Size
\r
496 AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0
\r
498 MOV AX, [BP].SVM_XSize ; Get Logical Screen Width
\r
499 CMP AX, CS:[SI].M_XSize ; Check against Displayed X
\r
500 JB @SVM_BadModeSetup4 ; Report Error if too small
\r
501 CMP AX, CS:[SI].M_XMax ; Check against Max X
\r
502 JA @SVM_BadModeSetup5 ; Report Error if too big
\r
504 ; Check Validity of Y Size
\r
506 MOV BX, [BP].SVM_YSize ; Get Logical Screen Height
\r
507 CMP BX, CS:[SI].M_YSize ; Check against Displayed Y
\r
508 JB @SVM_BadModeSetup6 ; Report Error if too small
\r
509 CMP BX, CS:[SI].M_YMax ; Check against Max Y
\r
510 JA @SVM_BadModeSetup7 ; Report Error if too big
\r
512 ; Enough memory to Fit it all?
\r
514 SHR AX, 1 ; # of Bytes:Line = XSize/4
\r
515 SHR AX, 1 ; # of Bytes:Line = XSize/4
\r
516 MUL CX ; AX = Bytes/Line * Pages
\r
517 MUL BX ; DX:AX = Total VGA mem needed
\r
518 JNO @SVM_Continue ; Exit if Total Size > 256K
\r
520 DEC DX ; Was it Exactly 256K???
\r
521 OR DX, AX ; (DX = 1, AX = 0000)
\r
522 JZ @SVM_Continue ; if so, it's valid...
\r
524 @SVM_BadModeSetup1:
\r
525 mov ax,1 ; Return Value = False
\r
526 JMP @SVM_Exit ; Normal Exit
\r
527 @SVM_BadModeSetup2:
\r
528 mov ax,2 ; Return Value = False
\r
529 JMP @SVM_Exit ; Normal Exit
\r
530 @SVM_BadModeSetup3:
\r
531 mov ax,3 ; Return Value = False
\r
532 JMP @SVM_Exit ; Normal Exit
\r
533 @SVM_BadModeSetup4:
\r
534 mov ax,4 ; Return Value = False
\r
535 JMP @SVM_Exit ; Normal Exit
\r
536 @SVM_BadModeSetup5:
\r
537 mov ax,5 ; Return Value = False
\r
538 JMP @SVM_Exit ; Normal Exit
\r
539 @SVM_BadModeSetup6:
\r
540 mov ax,6 ; Return Value = False
\r
541 JMP @SVM_Exit ; Normal Exit
\r
542 @SVM_BadModeSetup7:
\r
543 mov ax,7 ; Return Value = False
\r
544 JMP @SVM_Exit ; Normal Exit
\r
548 MOV AX, 13H ; Start with Mode 13H
\r
549 INT 10H ; Let BIOS Set Mode
\r
551 OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode
\r
552 OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset
\r
553 OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size
\r
554 OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ...
\r
556 OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register
\r
557 INC DX ; Point to Data
\r
558 IN AL, DX ; Get Value, Bit 7 = Protect
\r
559 AND AL, 7FH ; Mask out Write Protect
\r
560 OUT DX, AL ; And send it back
\r
562 MOV DX, CRTC_INDEX ; Vga Crtc Registers
\r
563 ADD SI, M_CRTC ; SI -> CRTC Parameter Data
\r
565 ; Load Tables of CRTC Parameters from List of Tables
\r
569 MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl
\r
570 ADD SI, 2 ; Point to next Ptr Entry
\r
571 OR DI, DI ; A nil Ptr means that we have
\r
572 JZ @SVM_Set_Data ; finished CRTC programming
\r
575 MOV AX, CS:[DI] ; Get CRTC Data from Table
\r
576 ADD DI, 2 ; Advance Pointer
\r
577 OR AX, AX ; At End of Data Table?
\r
578 JZ @SVM_Setup_Table ; If so, Exit & get next Table
\r
580 OUT DX, AX ; Reprogram VGA CRTC reg
\r
581 JMP s @SVM_Setup_CRTC ; Process Next Table Entry
\r
583 ; Initialize Page & Scroll info, DI = 0
\r
586 MOV DISPLAY_PAGE, DI ; Display Page = 0
\r
587 MOV ACTIVE_PAGE, DI ; Active Page = 0
\r
588 MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0
\r
589 MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0
\r
590 MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0
\r
591 MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0
\r
593 MOV AX, VGA_SEGMENT ; Segment for VGA memory
\r
594 MOV CURRENT_SEGMENT, AX ; Save for Future LES's
\r
596 ; Set Logical Screen Width, X Scroll and Our Data
\r
598 MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info
\r
599 MOV AX, [BP].SVM_Xsize ; Get Display Width
\r
601 MOV CX, AX ; CX = Logical Width
\r
602 SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value
\r
603 MOV MAX_XOFFSET, CX ; Set Maximum X Scroll
\r
605 SHR AX, 1 ; Bytes = Pixels / 4
\r
606 SHR AX, 1 ; Bytes = Pixels / 4
\r
607 MOV SCREEN_WIDTH, AX ; Save Width in Pixels
\r
609 SHR AX, 1 ; Offset Value = Bytes / 2
\r
610 MOV AH, 13h ; CRTC Offset Register Index
\r
611 XCHG AL, AH ; Switch format for OUT
\r
612 OUT DX, AX ; Set VGA CRTC Offset Reg
\r
614 ; Setup Data table, Y Scroll, Misc for Other Routines
\r
616 MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height
\r
618 MOV CX, AX ; CX = Logical Height
\r
619 SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value
\r
620 MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll
\r
622 MOV SCREEN_HEIGHT, AX ; Save Height in Pixels
\r
623 MUL SCREEN_WIDTH ; AX = Page Size in Bytes,
\r
624 MOV PAGE_SIZE, AX ; Save Page Size
\r
626 MOV CX, [BP].SVM_Pages ; Get # of Pages
\r
627 MOV LAST_PAGE, CX ; Save # of Pages
\r
629 mov bx,0 ; Page # = 0
\r
630 MOV DX, BX ; Page 0 Offset = 0
\r
634 MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset
\r
635 ADD BX, 2 ; Page#++
\r
636 ADD DX, AX ; Compute Addr of Next Page
\r
637 LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set
\r
641 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
642 LES DI, d CURRENT_PAGE ; -> Start of VGA memory
\r
645 CLD ; Block Xfer Forwards
\r
646 MOV CX, 8000H ; 32K * 4 * 2 = 256K
\r
647 REP STOSW ; Clear dat memory!
\r
649 ; Setup Font Pointers
\r
651 MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127
\r
652 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
653 INT 10h ; Call VGA BIOS
\r
655 MOV CHARSET_LOW, BP ; Save Char Set Offset
\r
656 MOV CHARSET_LOW+2, ES ; Save Char Set Segment
\r
658 MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255
\r
659 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
660 INT 10h ; Call VGA BIOS
\r
662 MOV CHARSET_HI, BP ; Save Char Set Offset
\r
663 MOV CHARSET_HI+2, ES ; Save Char Set Segment
\r
665 MOV AX, True ; Return Success Code
\r
668 ADD SP, 2 ; Deallocate workspace
\r
669 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
674 RET 8 ; Exit & Clean Up Stack
\r
679 ;==================
\r
680 ;SET_MODEX% (Mode%)
\r
681 ;==================
\r
683 ; Quickie Mode Set - Sets Up Mode X to Default Configuration
\r
685 ; ENTRY: ModeType = Desired Screen Resolution (0-7)
\r
686 ; (See SET_VGA_MODEX for list)
\r
688 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
694 SM_Mode DW ? ; Desired Screen Resolution
\r
701 ;PUSHx BP, SI ; Preserve Important registers
\r
704 MOV BP, SP ; Set up Stack Frame
\r
706 mov ax,0 ; Assume Failure
\r
707 MOV BX, [BP].SM_Mode ; Get Desired Mode #
\r
708 CMP BX, NUM_MODES ; Is it a Valid Mode #?
\r
709 JAE @SMX_Exit ; If Not, don't Bother
\r
711 PUSH BX ; Push Mode Parameter
\r
713 SHL BX, 1 ; Scale BX to word Index
\r
714 MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info
\r
716 PUSH CS:[SI].M_XSize ; Push Default X Size
\r
717 PUSH CS:[SI].M_Ysize ; Push Default Y size
\r
718 MOV AL, CS:[SI].M_Pages ; Get Default # of Pages
\r
719 mov ah,0 ; Hi Byte = 0
\r
720 PUSH AX ; Push # Pages
\r
722 CALL f SET_VGA_MODEX ; Set up Mode X!
\r
725 ;POPx SI, BP ; Restore Registers
\r
728 RET 2 ; Exit & Clean Up Stack
\r
733 ; ===== BASIC GRAPHICS PRIMITIVES =====
\r
735 ;============================
\r
736 ;CLEAR_VGA_SCREEN (ColorNum%)
\r
737 ;============================
\r
739 ; Clears the active display page
\r
741 ; ENTRY: ColorNum = Color Value to fill the page with
\r
743 ; EXIT: No meaningful values returned
\r
749 CVS_COLOR DB ?,? ; Color to Set Screen to
\r
752 PUBLIC CLEAR_VGA_SCREEN
\r
754 CLEAR_VGA_SCREEN PROC FAR
\r
756 ;PUSHx BP, DI ; Preserve Important Registers
\r
759 MOV BP, SP ; Set up Stack Frame
\r
761 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
762 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
764 MOV AL, [BP].CVS_COLOR ; Get Color
\r
765 MOV AH, AL ; Copy for Word Write
\r
766 CLD ; Block fill Forwards
\r
768 MOV CX, PAGE_SIZE ; Get Size of Page
\r
769 SHR CX, 1 ; Divide by 2 for Words
\r
770 REP STOSW ; Block Fill VGA memory
\r
772 ;POPx DI, BP ; Restore Saved Registers
\r
775 RET 2 ; Exit & Clean Up Stack
\r
777 CLEAR_VGA_SCREEN ENDP
\r
780 ;===================================
\r
781 ;SET_POINT (Xpos%, Ypos%, ColorNum%)
\r
782 ;===================================
\r
784 ; Plots a single Pixel on the active display page
\r
786 ; ENTRY: Xpos = X position to plot pixel at
\r
787 ; Ypos = Y position to plot pixel at
\r
788 ; ColorNum = Color to plot pixel with
\r
790 ; EXIT: No meaningful values returned
\r
796 SETP_Color DB ?,? ; Color of Point to Plot
\r
797 SETP_Ypos DW ? ; Y pos of Point to Plot
\r
798 SETP_Xpos DW ? ; X pos of Point to Plot
\r
805 ;PUSHx BP, DI ; Preserve Registers
\r
808 MOV BP, SP ; Set up Stack Frame
\r
810 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
812 MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel
\r
813 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
815 MOV BX, [BP].SETP_Xpos ; Get Xpos
\r
816 MOV CX, BX ; Copy to extract Plane # from
\r
817 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
818 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
819 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
821 MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register
\r
822 AND CL, PLANE_BITS ; Get Plane Bits
\r
823 SHL AH, CL ; Get Plane Select Value
\r
824 OUT_16 SC_Index, AX ; Select Plane
\r
826 MOV AL,[BP].SETP_Color ; Get Pixel Color
\r
827 MOV ES:[DI+BX], AL ; Draw Pixel
\r
829 ;POPx DI, BP ; Restore Saved Registers
\r
832 RET 6 ; Exit and Clean up Stack
\r
837 ;==========================
\r
838 ;READ_POINT% (Xpos%, Ypos%)
\r
839 ;==========================
\r
841 ; Read the color of a pixel from the Active Display Page
\r
843 ; ENTRY: Xpos = X position of pixel to read
\r
844 ; Ypos = Y position of pixel to read
\r
846 ; EXIT: AX = Color of Pixel at (Xpos, Ypos)
\r
852 RP_Ypos DW ? ; Y pos of Point to Read
\r
853 RP_Xpos DW ? ; X pos of Point to Read
\r
858 READ_POINT PROC FAR
\r
860 ;PUSHx BP, DI ; Preserve Registers
\r
863 MOV BP, SP ; Set up Stack Frame
\r
865 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
867 MOV AX, [BP].RP_Ypos ; Get Line # of Pixel
\r
868 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
870 MOV BX, [BP].RP_Xpos ; Get Xpos
\r
872 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
873 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
874 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
876 MOV AL, READ_MAP ; GC Read Mask Register
\r
877 MOV AH, CL ; Get Xpos
\r
878 AND AH, PLANE_BITS ; & mask out Plane #
\r
879 OUT_16 GC_INDEX, AX ; Select Plane to read in
\r
881 mov ah,0 ; Clear Return Value Hi byte
\r
882 MOV AL, ES:[DI+BX] ; Get Color of Pixel
\r
884 ;POPx DI, BP ; Restore Saved Registers
\r
887 RET 4 ; Exit and Clean up Stack
\r
892 ;======================================================
\r
893 ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
894 ;======================================================
\r
896 ; Fills a rectangular block on the active display Page
\r
898 ; ENTRY: Xpos1 = Left X position of area to fill
\r
899 ; Ypos1 = Top Y position of area to fill
\r
900 ; Xpos2 = Right X position of area to fill
\r
901 ; Ypos2 = Bottom Y position of area to fill
\r
902 ; ColorNum = Color to fill area with
\r
904 ; EXIT: No meaningful values returned
\r
908 DW ?x1 ; DS, DI, SI, BP
\r
909 DW ?x1 ; DS, DI, SI, BP
\r
910 DW ?x1 ; DS, DI, SI, BP
\r
911 DW ?x1 ; DS, DI, SI, BP
\r
913 FB_Color DB ?,? ; Fill Color
\r
914 FB_Ypos2 DW ? ; Y pos of Lower Right Pixel
\r
915 FB_Xpos2 DW ? ; X pos of Lower Right Pixel
\r
916 FB_Ypos1 DW ? ; Y pos of Upper Left Pixel
\r
917 FB_Xpos1 DW ? ; X pos of Upper Left Pixel
\r
922 FILL_BLOCK PROC FAR
\r
924 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
929 MOV BP, SP ; Set up Stack Frame
\r
931 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
932 CLD ; Direction Flag = Forward
\r
934 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
936 ; Validate Pixel Coordinates
\r
937 ; If necessary, Swap so X1 <= X2, Y1 <= Y2
\r
939 MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2?
\r
940 MOV BX, [BP].FB_Ypos2 ; BX = Y2
\r
944 MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1
\r
945 XCHG AX, BX ; on stack for future use
\r
948 SUB BX, AX ; Get Y width
\r
949 INC BX ; Add 1 to avoid 0 value
\r
950 MOV [BP].FB_Ypos2, BX ; Save in Ypos2
\r
952 MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line
\r
953 ADD DI, AX ; DI = Start of Line Y1
\r
955 MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2
\r
956 MOV BX, [BP].FB_Xpos2 ;
\r
958 JLE @FB_NOSWAP2 ; Skip Ahead if Ok
\r
960 MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2
\r
961 XCHG AX, BX ; on stack for future use
\r
963 ; All our Input Values are in order, Now determine
\r
964 ; How many full "bands" 4 pixels wide (aligned) there
\r
965 ; are, and if there are partial bands (<4 pixels) on
\r
966 ; the left and right edges.
\r
969 MOV DX, AX ; DX = X1 (Pixel Position)
\r
970 SHR DX, 1 ; DX/4 = Bytes into Line
\r
971 SHR DX, 1 ; DX/4 = Bytes into Line
\r
972 ADD DI, DX ; DI = Addr of Upper-Left Corner
\r
974 MOV CX, BX ; CX = X2 (Pixel Position)
\r
975 SHR CX, 1 ; CX/4 = Bytes into Line
\r
976 SHR CX, 1 ; CX/4 = Bytes into Line
\r
978 CMP DX, CX ; Start and end in same band?
\r
979 JNE @FB_NORMAL ; if not, check for l & r edges
\r
980 JMP @FB_ONE_BAND_ONLY ; if so, then special processing
\r
983 SUB CX, DX ; CX = # bands -1
\r
984 MOV SI, AX ; SI = PLANE#(X1)
\r
985 AND SI, PLANE_BITS ; if Left edge is aligned then
\r
986 JZ @FB_L_PLANE_FLUSH ; no special processing..
\r
988 ; Draw "Left Edge" vertical strip of 1-3 pixels...
\r
990 OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask
\r
992 MOV SI, DI ; SI = Copy of Start Addr (UL)
\r
994 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
995 MOV AL, [BP].FB_Color ; Get Fill Color
\r
996 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
999 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
1000 ADD SI, BX ; Point to Next Line (Below)
\r
1001 LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn
\r
1003 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
1004 ADD SI, BX ; Point to Next Line (Below)
\r
1005 LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn
\r
1009 INC DI ; Point to Middle (or Right) Block
\r
1010 DEC CX ; Reset CX instead of JMP @FB_RIGHT
\r
1012 @FB_L_PLANE_FLUSH:
\r
1013 INC CX ; Add in Left band to middle block
\r
1015 ; DI = Addr of 1st middle Pixel (band) to fill
\r
1016 ; CX = # of Bands to fill -1
\r
1019 MOV SI, [BP].FB_Xpos2 ; Get Xpos2
\r
1020 AND SI, PLANE_BITS ; Get Plane values
\r
1021 CMP SI, 0003 ; Plane = 3?
\r
1022 JE @FB_R_EDGE_FLUSH ; Hey, add to middle
\r
1024 ; Draw "Right Edge" vertical strip of 1-3 pixels...
\r
1026 OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask
\r
1028 MOV SI, DI ; Get Addr of Left Edge
\r
1029 ADD SI, CX ; Add Width-1 (Bands)
\r
1030 DEC SI ; To point to top of Right Edge
\r
1032 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1033 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1034 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1037 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
1038 ADD SI, BX ; Point to Next Line (Below)
\r
1039 LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn
\r
1041 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
1042 ADD SI, BX ; Point to Next Line (Below)
\r
1043 LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn
\r
1047 DEC CX ; Minus 1 for Middle bands
\r
1048 JZ @FB_EXIT ; Uh.. no Middle bands...
\r
1052 ; DI = Addr of Upper Left block to fill
\r
1053 ; CX = # of Bands to fill in (width)
\r
1055 OUT_8 SC_Data, ALL_PLANES ; Write to All Planes
\r
1057 MOV DX, SCREEN_WIDTH ; DX = DI Increment
\r
1058 SUB DX, CX ; = Screen_Width-# Planes Filled
\r
1060 MOV BX, CX ; BX = Quick Refill for CX
\r
1061 MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill
\r
1062 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1065 REP STOSB ; Fill in entire line
\r
1067 MOV CX, BX ; Recharge CX (Line Width)
\r
1068 ADD DI, DX ; Point to start of Next Line
\r
1069 LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn
\r
1071 JMP s @FB_EXIT ; Outa here
\r
1073 @FB_ONE_BAND_ONLY:
\r
1074 MOV SI, AX ; Get Left Clip Mask, Save X1
\r
1075 AND SI, PLANE_BITS ; Mask out Row #
\r
1076 MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1077 MOV SI, BX ; Get Right Clip Mask, Save X2
\r
1078 AND SI, PLANE_BITS ; Mask out Row #
\r
1079 AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte
\r
1081 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
1083 MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1084 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1085 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1088 MOV ES:[DI], AL ; Fill in Pixels
\r
1089 ADD DI, BX ; Point to Next Line (Below)
\r
1090 LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn
\r
1092 MOV ES:[DI], AL ; Fill in Pixels
\r
1093 ADD DI, BX ; Point to Next Line (Below)
\r
1094 LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn
\r
1097 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
1102 RET 10 ; Exit and Clean up Stack
\r
1107 ;=====================================================
\r
1108 ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
1109 ;=====================================================
\r
1111 ; Draws a Line on the active display page
\r
1113 ; ENTRY: Xpos1 = X position of first point on line
\r
1114 ; Ypos1 = Y position of first point on line
\r
1115 ; Xpos2 = X position of last point on line
\r
1116 ; Ypos2 = Y position of last point on line
\r
1117 ; ColorNum = Color to draw line with
\r
1119 ; EXIT: No meaningful values returned
\r
1123 DW ?x1 ; DI, SI, BP
\r
1124 DW ?x1 ; DI, SI, BP
\r
1125 DW ?x1 ; DI, SI, BP
\r
1127 DL_ColorF DB ?,? ; Line Draw Color
\r
1128 DL_Ypos2 DW ? ; Y pos of last point
\r
1129 DL_Xpos2 DW ? ; X pos of last point
\r
1130 DL_Ypos1 DW ? ; Y pos of first point
\r
1131 DL_Xpos1 DW ? ; X pos of first point
\r
1136 DRAW_LINE PROC FAR
\r
1138 ;PUSHx BP, SI, DI ; Preserve Important Registers
\r
1142 MOV BP, SP ; Set up Stack Frame
\r
1143 CLD ; Direction Flag = Forward
\r
1145 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
1146 MOV CH, [BP].DL_ColorF ; Save Line Color in CH
\r
1150 MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2?
\r
1151 MOV DI, [BP].DL_Xpos2 ; DX = X2
\r
1152 CMP SI, DI ; Is X1 < X2
\r
1153 JE @DL_VLINE ; If X1=X2, Draw Vertical Line
\r
1154 JL @DL_NOSWAP1 ; If X1 < X2, don't swap
\r
1156 XCHG SI, DI ; X2 IS > X1, SO SWAP THEM
\r
1160 ; SI = X1, DI = X2
\r
1162 MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2?
\r
1163 CMP AX, [BP].DL_Ypos2 ; Y1 = Y2?
\r
1164 JE @DL_HORZ ; If so, Draw a Horizontal Line
\r
1166 JMP @DL_BREZHAM ; Diagonal line... go do it...
\r
1168 ; This Code draws a Horizontal Line in Mode X where:
\r
1169 ; SI = X1, DI = X2, and AX = Y1/Y2
\r
1173 MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width
\r
1174 MOV DX, AX ; CX = Line offset into Page
\r
1176 MOV AX, SI ; Get Left edge, Save X1
\r
1177 AND SI, PLANE_BITS ; Mask out Row #
\r
1178 MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1179 MOV CX, DI ; Get Right edge, Save X2
\r
1180 AND DI, PLANE_BITS ; Mask out Row #
\r
1181 MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte
\r
1183 SHR AX, 1 ; Get X1 Byte # (=X1/4)
\r
1184 SHR CX, 1 ; Get X2 Byte # (=X2/4)
\r
1185 SHR AX, 1 ; Get X1 Byte # (=X1/4)
\r
1186 SHR CX, 1 ; Get X2 Byte # (=X2/4)
\r
1188 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1189 ADD DI, DX ; Point to Start of Line
\r
1190 ADD DI, AX ; Point to Pixel X1
\r
1192 SUB CX, AX ; CX = # Of Bands (-1) to set
\r
1193 JNZ @DL_LONGLN ; jump if longer than one segment
\r
1195 AND BL, BH ; otherwise, merge clip masks
\r
1199 OUT_8 SC_Data, BL ; Set the Left Clip Mask
\r
1201 MOV AL, [BP].DL_ColorF ; Get Line Color
\r
1202 MOV BL, AL ; BL = Copy of Line Color
\r
1203 STOSB ; Set Left (1-4) Pixels
\r
1205 JCXZ @DL_EXIT ; Done if only one Line Segment
\r
1207 DEC CX ; CX = # of Middle Segments
\r
1208 JZ @DL_XRSEG ; If no middle segments....
\r
1210 ; Draw Middle Segments
\r
1212 OUT_8 DX, ALL_PLANES ; Write to ALL Planes
\r
1214 MOV AL, BL ; Get Color from BL
\r
1215 REP STOSB ; Draw Middle (4 Pixel) Segments
\r
1218 OUT_8 DX, BH ; Select Planes for Right Clip Mask
\r
1219 MOV AL, BL ; Get Color Value
\r
1220 STOSB ; Draw Right (1-4) Pixels
\r
1222 JMP s @DL_EXIT ; We Are Done...
\r
1225 ; This Code Draws A Vertical Line. On entry:
\r
1226 ; CH = Line Color, SI & DI = X1
\r
1230 MOV AX, [BP].DL_Ypos1 ; AX = Y1
\r
1231 MOV SI, [BP].DL_Ypos2 ; SI = Y2
\r
1232 CMP AX, SI ; Is Y1 < Y2?
\r
1233 JLE @DL_NOSWAP2 ; if so, Don't Swap them
\r
1235 XCHG AX, SI ; Ok, NOW Y1 < Y2
\r
1239 SUB SI, AX ; SI = Line Height (Y2-Y1+1)
\r
1242 ; AX = Y1, DI = X1, Get offset into Page into AX
\r
1244 MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width
\r
1245 MOV DX, DI ; Copy Xpos into DX
\r
1246 SHR DI, 1 ; DI = Xpos/4
\r
1247 SHR DI, 1 ; DI = Xpos/4
\r
1248 ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1
\r
1250 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1251 ADD DI, AX ; Point to Pixel X1, Y1
\r
1255 MOV CL, DL ; CL = Save X1
\r
1256 AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #)
\r
1257 MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1
\r
1258 SHL AH, CL ; Change to Correct Plane #
\r
1259 OUT_16 SC_Index, AX ; Select Plane
\r
1261 MOV AL, CH ; Get Saved Color
\r
1262 MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By
\r
1265 MOV ES:[DI], AL ; Draw Single Pixel
\r
1266 ADD DI, BX ; Point to Next Line
\r
1267 LOOPjz SI, @DL_EXIT ; Lines--, Exit if done
\r
1269 MOV ES:[DI], AL ; Draw Single Pixel
\r
1270 ADD DI, BX ; Point to Next Line
\r
1271 LOOPx SI, @DL_VLoop ; Lines--, Loop until Done
\r
1275 JMP @DL_EXIT2 ; Done!
\r
1277 ; This code Draws a diagonal line in Mode X
\r
1280 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1282 MOV AX, [BP].DL_Ypos1 ; get Y1 value
\r
1283 MOV BX, [BP].DL_Ypos2 ; get Y2 value
\r
1284 MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos
\r
1286 CMP BX, AX ; Y2-Y1 is?
\r
1287 JNC @DL_DeltaYOK ; if Y2>=Y1 then goto...
\r
1289 XCHG BX, AX ; Swap em...
\r
1290 MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos
\r
1293 MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1
\r
1295 ADD DI, AX ; DI -> Start of Line Y1 on Page
\r
1296 MOV AX, CX ; AX = Xpos (X1)
\r
1297 SHR AX, 1 ; /4 = Byte Offset into Line
\r
1298 SHR AX, 1 ; /4 = Byte Offset into Line
\r
1299 ADD DI, AX ; DI = Starting pos (X1,Y1)
\r
1301 MOV AL, 11h ; Staring Mask
\r
1302 AND CL, PLANE_BITS ; Get Plane #
\r
1303 SHL AL, CL ; and shift into place
\r
1304 MOV AH, [BP].DL_ColorF ; Color in Hi Bytes
\r
1306 PUSH AX ; Save Mask,Color...
\r
1308 MOV AH, AL ; Plane # in AH
\r
1309 MOV AL, MAP_MASK ; Select Plane Register
\r
1310 OUT_16 SC_Index, AX ; Select initial plane
\r
1312 MOV AX, [BP].DL_Xpos1 ; get X1 value
\r
1313 MOV BX, [BP].DL_Ypos1 ; get Y1 value
\r
1314 MOV CX, [BP].DL_Xpos2 ; get X2 value
\r
1315 MOV DX, [BP].DL_Ypos2 ; get Y2 value
\r
1317 MOV BP, SCREEN_WIDTH ; Use BP for Line width to
\r
1318 ; to avoid extra memory access
\r
1320 SUB DX, BX ; figure Delta_Y
\r
1321 JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1
\r
1323 ADD BX, DX ; put Y2 into Y1
\r
1324 NEG DX ; abs(Delta_Y)
\r
1325 XCHG AX, CX ; and exchange X1 and X2
\r
1328 MOV BX, 08000H ; seed for fraction accumulator
\r
1330 SUB CX, AX ; figure Delta_X
\r
1331 JC @DL_DrawLeft ; if negative, go left
\r
1333 JMP @DL_DrawRight ; Draw Line that slopes right
\r
1337 NEG CX ; abs(Delta_X)
\r
1339 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1340 JB @DL_SteepLeft ; yes, so go do steep line
\r
1341 ; (Delta_Y iterations)
\r
1343 ; Draw a Shallow line to the left in Mode X
\r
1346 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1347 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1348 SBB DX, 0 ; include carry
\r
1349 DIV CX ; divide by Delta_X
\r
1351 MOV SI, BX ; SI = Accumulator
\r
1352 MOV BX, AX ; BX = Add fraction
\r
1353 POP AX ; Get Color, Bit mask
\r
1354 MOV DX, SC_Data ; Sequence controller data register
\r
1355 INC CX ; Inc Delta_X so we can unroll loop
\r
1357 ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...
\r
1360 MOV ES:[DI], AH ; set first pixel, plane data set up
\r
1361 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1363 ADD SI, BX ; add numerator to accumulator
\r
1364 JNC @DL_SLLL2nc ; move down on carry
\r
1366 ADD DI, BP ; Move Down one line...
\r
1369 DEC DI ; Left one addr
\r
1370 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1371 CMP AL, 87h ; wrap?, if AL <88 then Carry set
\r
1372 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1373 OUT DX, AL ; Set up New Bit Plane mask
\r
1375 MOV ES:[DI], AH ; set pixel
\r
1376 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1378 ADD SI, BX ; add numerator to accumulator,
\r
1379 JNC @DL_SLLL3nc ; move down on carry
\r
1381 ADD DI, BP ; Move Down one line...
\r
1383 @DL_SLLL3nc: ; Now move left a pixel...
\r
1384 DEC DI ; Left one addr
\r
1385 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1386 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1387 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1388 OUT DX, AL ; Set up New Bit Plane mask
\r
1389 JMP s @DL_SLLLoop ; loop until done
\r
1392 JMP @DL_EXIT2 ; and exit
\r
1394 ; Draw a steep line to the left in Mode X
\r
1397 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1398 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1399 DIV CX ; divide by Delta_Y
\r
1401 MOV SI, BX ; SI = Accumulator
\r
1402 MOV BX, AX ; BX = Add Fraction
\r
1403 POP AX ; Get Color, Bit mask
\r
1404 MOV DX, SC_Data ; Sequence controller data register
\r
1405 INC CX ; Inc Delta_Y so we can unroll loop
\r
1407 ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
\r
1411 MOV ES:[DI], AH ; set first pixel
\r
1412 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1414 ADD SI, BX ; add numerator to accumulator
\r
1415 JNC @DL_STLnc2 ; No carry, just move down!
\r
1417 DEC DI ; Move Left one addr
\r
1418 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1419 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1420 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1421 OUT DX, AL ; Set up New Bit Plane mask
\r
1424 ADD DI, BP ; advance to next line.
\r
1426 MOV ES:[DI], AH ; set pixel
\r
1427 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1429 ADD SI, BX ; add numerator to accumulator
\r
1430 JNC @DL_STLnc3 ; No carry, just move down!
\r
1432 DEC DI ; Move Left one addr
\r
1433 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1434 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1435 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1436 OUT DX, AL ; Set up New Bit Plane mask
\r
1439 ADD DI, BP ; advance to next line.
\r
1440 JMP s @DL_STLLoop ; Loop until done
\r
1443 JMP @DL_EXIT2 ; and exit
\r
1445 ; Draw a line that goes to the Right...
\r
1448 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1449 JB @DL_SteepRight ; yes, so go do steep line
\r
1450 ; (Delta_Y iterations)
\r
1452 ; Draw a Shallow line to the Right in Mode X
\r
1455 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1456 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1457 SBB DX, 0 ; include carry
\r
1458 DIV CX ; divide by Delta_X
\r
1460 MOV SI, BX ; SI = Accumulator
\r
1461 MOV BX, AX ; BX = Add Fraction
\r
1462 POP AX ; Get Color, Bit mask
\r
1463 MOV DX, SC_Data ; Sequence controller data register
\r
1464 INC CX ; Inc Delta_X so we can unroll loop
\r
1466 ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...
\r
1469 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1470 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1472 ADD SI, BX ; add numerator to accumulator
\r
1473 JNC @DL_SLR2nc ; don't move down if carry not set
\r
1475 ADD DI, BP ; Move Down one line...
\r
1477 @DL_SLR2nc: ; Now move right a pixel...
\r
1478 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1479 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1480 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1481 OUT DX, AL ; Set up New Bit Plane mask
\r
1483 MOV ES:[DI], AH ; set pixel
\r
1484 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1486 ADD SI, BX ; add numerator to accumulator
\r
1487 JNC @DL_SLR3nc ; don't move down if carry not set
\r
1489 ADD DI, BP ; Move Down one line...
\r
1492 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1493 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1494 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1495 OUT DX, AL ; Set up New Bit Plane mask
\r
1496 JMP s @DL_SLRLoop ; loop till done
\r
1499 JMP @DL_EXIT2 ; and exit
\r
1501 ; Draw a Steep line to the Right in Mode X
\r
1504 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1505 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1506 DIV CX ; divide by Delta_Y
\r
1508 MOV SI, BX ; SI = Accumulator
\r
1509 MOV BX, AX ; BX = Add Fraction
\r
1510 POP AX ; Get Color, Bit mask
\r
1511 MOV DX, SC_Data ; Sequence controller data register
\r
1512 INC CX ; Inc Delta_Y so we can unroll loop
\r
1514 ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
\r
1517 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1518 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1520 ADD SI, BX ; add numerator to accumulator
\r
1521 JNC @STRnc2 ; if no carry then just go down...
\r
1523 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1524 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1525 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1526 OUT DX, AL ; Set up New Bit Plane mask
\r
1529 ADD DI, BP ; advance to next line.
\r
1531 MOV ES:[DI], AH ; set pixel
\r
1532 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1534 ADD SI, BX ; add numerator to accumulator
\r
1535 JNC @STRnc3 ; if no carry then just go down...
\r
1537 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1538 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1539 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1540 OUT DX, AL ; Set up New Bit Plane mask
\r
1543 ADD DI, BP ; advance to next line.
\r
1544 JMP s @STRLoop ; loop till done
\r
1547 ;POPx DI, SI, BP ; Restore Saved Registers
\r
1551 RET 10 ; Exit and Clean up Stack
\r
1556 ; ===== DAC COLOR REGISTER ROUTINES =====
\r
1558 ;=================================================
\r
1559 ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)
\r
1560 ;=================================================
\r
1562 ; Sets a single (RGB) Vga Palette Register
\r
1564 ; ENTRY: Register = The DAC # to modify (0-255)
\r
1565 ; Red = The new Red Intensity (0-63)
\r
1566 ; Green = The new Green Intensity (0-63)
\r
1567 ; Blue = The new Blue Intensity (0-63)
\r
1569 ; EXIT: No meaningful values returned
\r
1575 SDR_Blue DB ?,? ; Blue Data Value
\r
1576 SDR_Green DB ?,? ; Green Data Value
\r
1577 SDR_Red DB ?,? ; Red Data Value
\r
1578 SDR_Register DB ?,? ; Palette Register #
\r
1581 PUBLIC SET_DAC_REGISTER
\r
1583 SET_DAC_REGISTER PROC FAR
\r
1586 MOV BP, SP ; Set up Stack Frame
\r
1588 ; Select which DAC Register to modify
\r
1590 OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register
\r
1592 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1593 OUT_8 DX, [BP].SDR_Red ; Set Red Intensity
\r
1594 OUT_8 DX, [BP].SDR_Green ; Set Green Intensity
\r
1595 OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity
\r
1597 POP BP ; Restore Registers
\r
1598 RET 8 ; Exit & Clean Up Stack
\r
1600 SET_DAC_REGISTER ENDP
\r
1602 ;====================================================
\r
1603 ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)
\r
1604 ;====================================================
\r
1606 ; Reads the RGB Values of a single Vga Palette Register
\r
1608 ; ENTRY: Register = The DAC # to read (0-255)
\r
1609 ; Red = Offset to Red Variable in DS
\r
1610 ; Green = Offset to Green Variable in DS
\r
1611 ; Blue = Offset to Blue Variable in DS
\r
1613 ; EXIT: The values of the integer variables Red,
\r
1614 ; Green, and Blue are set to the values
\r
1615 ; taken from the specified DAC register.
\r
1621 GDR_Blue DW ? ; Addr of Blue Data Value in DS
\r
1622 GDR_Green DW ? ; Addr of Green Data Value in DS
\r
1623 GDR_Red DW ? ; Addr of Red Data Value in DS
\r
1624 GDR_Register DB ?,? ; Palette Register #
\r
1627 PUBLIC GET_DAC_REGISTER
\r
1629 GET_DAC_REGISTER PROC FAR
\r
1632 MOV BP, SP ; Set up Stack Frame
\r
1634 ; Select which DAC Register to read in
\r
1636 OUT_8 DAC_READ_ADDR, [BP].GDR_Register
\r
1638 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1639 mov ax,0 ; Clear AX
\r
1641 IN AL, DX ; Read Red Value
\r
1642 MOV BX, [BP].GDR_Red ; Get Address of Red%
\r
1643 MOV [BX], AX ; *Red% = AX
\r
1645 IN AL, DX ; Read Green Value
\r
1646 MOV BX, [BP].GDR_Green ; Get Address of Green%
\r
1647 MOV [BX], AX ; *Green% = AX
\r
1649 IN AL, DX ; Read Blue Value
\r
1650 MOV BX, [BP].GDR_Blue ; Get Address of Blue%
\r
1651 MOV [BX], AX ; *Blue% = AX
\r
1653 POP BP ; Restore Registers
\r
1654 RET 8 ; Exit & Clean Up Stack
\r
1656 GET_DAC_REGISTER ENDP
\r
1659 ;===========================================================
\r
1660 ;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%)
\r
1661 ;===========================================================
\r
1663 ; Sets a Block of Vga Palette Registers
\r
1665 ; ENTRY: PalData = Far Pointer to Block of palette data
\r
1666 ; StartReg = First Register # in range to set (0-255)
\r
1667 ; EndReg = Last Register # in Range to set (0-255)
\r
1668 ; Sync = Wait for Vertical Retrace Flag (Boolean)
\r
1670 ; EXIT: No meaningful values returned
\r
1672 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1673 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1677 DW ?x1 ; BP, DS, SI
\r
1678 DW ?x1 ; BP, DS, SI
\r
1679 DW ?x1 ; BP, DS, SI
\r
1681 LDR_Sync DW ? ; Vertical Sync Flag
\r
1682 LDR_EndReg DB ?,? ; Last Register #
\r
1683 LDR_StartReg DB ?,? ; First Register #
\r
1684 LDR_PalData DD ? ; Far Ptr to Palette Data
\r
1687 PUBLIC LOAD_DAC_REGISTERS
\r
1689 LOAD_DAC_REGISTERS PROC FAR
\r
1691 ;PUSHx BP, DS, SI ; Save Registers
\r
1695 mov BP, SP ; Set up Stack Frame
\r
1697 mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag
\r
1698 or AX, AX ; is Sync Flag = 0?
\r
1699 jz @LDR_Load ; if so, skip call
\r
1701 call f SYNC_DISPLAY ; wait for vsync
\r
1703 ; Determine register #'s, size to copy, etc
\r
1707 lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data
\r
1708 mov DX, DAC_WRITE_ADDR ; DAC register # selector
\r
1710 mov ax,0, BX ; Clear for byte loads
\r
1711 mov AL, [BP].LDR_StartReg ; Get Start Register
\r
1712 mov BL, [BP].LDR_EndReg ; Get End Register
\r
1714 sub BX, AX ; BX = # of DAC registers -1
\r
1715 inc BX ; BX = # of DAC registers
\r
1716 mov CX, BX ; CX = # of DAC registers
\r
1717 add CX, BX ; CX = " " * 2
\r
1718 add CX, BX ; CX = " " * 3
\r
1719 cld ; Block OUTs forward
\r
1720 out DX, AL ; set up correct register #
\r
1722 ; Load a block of DAC Registers
\r
1724 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1726 ;rep outsb ; block set DAC registers
\r
1728 ;POPx SI, DS, BP ; Restore Registers
\r
1732 ret 10 ; Exit & Clean Up Stack
\r
1734 LOAD_DAC_REGISTERS ENDP
\r
1737 ;====================================================
\r
1738 ;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%)
\r
1739 ;====================================================
\r
1741 ; Reads a Block of Vga Palette Registers
\r
1743 ; ENTRY: PalData = Far Pointer to block to store palette data
\r
1744 ; StartReg = First Register # in range to read (0-255)
\r
1745 ; EndReg = Last Register # in Range to read (0-255)
\r
1747 ; EXIT: No meaningful values returned
\r
1749 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1750 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1754 DW ?x1 ; BP, ES, DI
\r
1755 DW ?x1 ; BP, ES, DI
\r
1756 DW ?x1 ; BP, ES, DI
\r
1758 RDR_EndReg DB ?,? ; Last Register #
\r
1759 RDR_StartReg DB ?,? ; First Register #
\r
1760 RDR_PalData DD ? ; Far Ptr to Palette Data
\r
1763 PUBLIC READ_DAC_REGISTERS
\r
1765 READ_DAC_REGISTERS PROC FAR
\r
1767 ;PUSHx BP, ES, DI ; Save Registers
\r
1771 mov BP, SP ; Set up Stack Frame
\r
1773 ; Determine register #'s, size to copy, etc
\r
1775 les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer
\r
1776 mov DX, DAC_READ_ADDR ; DAC register # selector
\r
1778 mov ax,0, BX ; Clear for byte loads
\r
1779 mov AL, [BP].RDR_StartReg ; Get Start Register
\r
1780 mov BL, [BP].RDR_EndReg ; Get End Register
\r
1782 sub BX, AX ; BX = # of DAC registers -1
\r
1783 inc BX ; BX = # of DAC registers
\r
1784 mov CX, BX ; CX = # of DAC registers
\r
1785 add CX, BX ; CX = " " * 2
\r
1786 add CX, BX ; CX = " " * 3
\r
1787 cld ; Block INs forward
\r
1789 ; Read a block of DAC Registers
\r
1791 out DX, AL ; set up correct register #
\r
1792 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1794 ;rep insb ; block read DAC registers
\r
1796 ;POPx DI, ES, BP ; Restore Registers
\r
1800 ret 8 ; Exit & Clean Up Stack
\r
1802 READ_DAC_REGISTERS ENDP
\r
1805 ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====
\r
1807 ;=========================
\r
1808 ;SET_ACTIVE_PAGE (PageNo%)
\r
1809 ;=========================
\r
1811 ; Sets the active display Page to be used for future drawing
\r
1813 ; ENTRY: PageNo = Display Page to make active
\r
1814 ; (values: 0 to Number of Pages - 1)
\r
1816 ; EXIT: No meaningful values returned
\r
1822 SAP_Page DW ? ; Page # for Drawing
\r
1825 PUBLIC SET_ACTIVE_PAGE
\r
1827 SET_ACTIVE_PAGE PROC FAR
\r
1829 PUSH BP ; Preserve Registers
\r
1830 MOV BP, SP ; Set up Stack Frame
\r
1832 MOV BX, [BP].SAP_Page ; Get Desired Page #
\r
1833 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1834 JAE @SAP_Exit ; IF Not, Do Nothing
\r
1836 MOV ACTIVE_PAGE, BX ; Set Active Page #
\r
1838 SHL BX, 1 ; Scale Page # to Word
\r
1839 MOV AX, PAGE_ADDR[BX] ; Get offset to Page
\r
1841 MOV CURRENT_PAGE, AX ; And set for future LES's
\r
1844 POP BP ; Restore Registers
\r
1845 RET 2 ; Exit and Clean up Stack
\r
1847 SET_ACTIVE_PAGE ENDP
\r
1854 ; Returns the Video Page # currently used for Drawing
\r
1856 ; ENTRY: No Parameters are passed
\r
1858 ; EXIT: AX = Current Video Page used for Drawing
\r
1861 PUBLIC GET_ACTIVE_PAGE
\r
1863 GET_ACTIVE_PAGE PROC FAR
\r
1865 MOV AX, ACTIVE_PAGE ; Get Active Page #
\r
1866 RET ; Exit and Clean up Stack
\r
1868 GET_ACTIVE_PAGE ENDP
\r
1871 ;===============================
\r
1872 ;SET_DISPLAY_PAGE (DisplayPage%)
\r
1873 ;===============================
\r
1875 ; Sets the currently visible display page.
\r
1876 ; When called this routine syncronizes the display
\r
1877 ; to the vertical blank.
\r
1879 ; ENTRY: PageNo = Display Page to show on the screen
\r
1880 ; (values: 0 to Number of Pages - 1)
\r
1882 ; EXIT: No meaningful values returned
\r
1888 SDP_Page DW ? ; Page # to Display...
\r
1891 PUBLIC SET_DISPLAY_PAGE
\r
1893 SET_DISPLAY_PAGE PROC FAR
\r
1895 PUSH BP ; Preserve Registers
\r
1896 MOV BP, SP ; Set up Stack Frame
\r
1898 MOV BX, [BP].SDP_Page ; Get Desired Page #
\r
1899 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1900 JAE @SDP_Exit ; IF Not, Do Nothing
\r
1902 MOV DISPLAY_PAGE, BX ; Set Display Page #
\r
1904 SHL BX, 1 ; Scale Page # to Word
\r
1905 MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page
\r
1906 ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling
\r
1908 ; Wait if we are currently in a Vertical Retrace
\r
1910 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1913 IN AL, DX ; Get VGA status
\r
1914 AND AL, VERT_RETRACE ; In Display mode yet?
\r
1915 JNZ @DP_WAIT0 ; If Not, wait for it
\r
1917 ; Set the Start Display Address to the new page
\r
1919 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
1921 MOV AL, START_DISP_LO ; Display Start Low Register
\r
1922 MOV AH, CL ; Low 8 Bits of Start Addr
\r
1923 OUT DX, AX ; Set Display Addr Low
\r
1925 MOV AL, START_DISP_HI ; Display Start High Register
\r
1926 MOV AH, CH ; High 8 Bits of Start Addr
\r
1927 OUT DX, AX ; Set Display Addr High
\r
1929 ; Wait for a Vertical Retrace to smooth out things
\r
1931 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1934 IN AL, DX ; Get VGA status
\r
1935 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
1936 JZ @DP_WAIT1 ; If Not, wait for it
\r
1938 ; Now Set Display Starting Address
\r
1942 POP BP ; Restore Registers
\r
1943 RET 2 ; Exit and Clean up Stack
\r
1945 SET_DISPLAY_PAGE ENDP
\r
1948 ;=================
\r
1949 ;GET_DISPLAY_PAGE%
\r
1950 ;=================
\r
1952 ; Returns the Video Page # currently displayed
\r
1954 ; ENTRY: No Parameters are passed
\r
1956 ; EXIT: AX = Current Video Page being displayed
\r
1959 PUBLIC GET_DISPLAY_PAGE
\r
1961 GET_DISPLAY_PAGE PROC FAR
\r
1963 MOV AX, DISPLAY_PAGE ; Get Display Page #
\r
1964 RET ; Exit & Clean Up Stack
\r
1966 GET_DISPLAY_PAGE ENDP
\r
1969 ;=======================================
\r
1970 ;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)
\r
1971 ;=======================================
\r
1973 ; Since a Logical Screen can be larger than the Physical
\r
1974 ; Screen, Scrolling is possible. This routine sets the
\r
1975 ; Upper Left Corner of the Screen to the specified Pixel.
\r
1976 ; Also Sets the Display page to simplify combined page
\r
1977 ; flipping and scrolling. When called this routine
\r
1978 ; syncronizes the display to the vertical blank.
\r
1980 ; ENTRY: DisplayPage = Display Page to show on the screen
\r
1981 ; Xpos = # of pixels to shift screen right
\r
1982 ; Ypos = # of lines to shift screen down
\r
1984 ; EXIT: No meaningful values returned
\r
1990 SW_Ypos DW ? ; Y pos of UL Screen Corner
\r
1991 SW_Xpos DW ? ; X pos of UL Screen Corner
\r
1992 SW_Page DW ? ; (new) Display Page
\r
1997 SET_WINDOW PROC FAR
\r
1999 PUSH BP ; Preserve Registers
\r
2000 MOV BP, SP ; Set up Stack Frame
\r
2002 ; Check if our Scroll Offsets are Valid
\r
2004 MOV BX, [BP].SW_Page ; Get Desired Page #
\r
2005 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
2006 JAE @SW_Exit ; IF Not, Do Nothing
\r
2008 MOV AX, [BP].SW_Ypos ; Get Desired Y Offset
\r
2009 CMP AX, MAX_YOFFSET ; Is it Within Limits?
\r
2010 JA @SW_Exit ; if not, exit
\r
2012 MOV CX, [BP].SW_Xpos ; Get Desired X Offset
\r
2013 CMP CX, MAX_XOFFSET ; Is it Within Limits?
\r
2014 JA @SW_Exit ; if not, exit
\r
2016 ; Compute proper Display start address to use
\r
2018 MUL SCREEN_WIDTH ; AX = YOffset * Line Width
\r
2019 SHR CX, 1 ; CX / 4 = Bytes into Line
\r
2020 SHR CX, 1 ; CX / 4 = Bytes into Line
\r
2021 ADD AX, CX ; AX = Offset of Upper Left Pixel
\r
2023 MOV CURRENT_MOFFSET, AX ; Save Offset Info
\r
2025 MOV DISPLAY_PAGE, BX ; Set Current Page #
\r
2026 SHL BX, 1 ; Scale Page # to Word
\r
2027 ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page
\r
2028 MOV BX, AX ; BX = Desired Display Start
\r
2030 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2032 ; Wait if we are currently in a Vertical Retrace
\r
2035 IN AL, DX ; Get VGA status
\r
2036 AND AL, VERT_RETRACE ; In Display mode yet?
\r
2037 JNZ @SW_WAIT0 ; If Not, wait for it
\r
2039 ; Set the Start Display Address to the new window
\r
2041 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
2042 MOV AL, START_DISP_LO ; Display Start Low Register
\r
2043 MOV AH, BL ; Low 8 Bits of Start Addr
\r
2044 OUT DX, AX ; Set Display Addr Low
\r
2046 MOV AL, START_DISP_HI ; Display Start High Register
\r
2047 MOV AH, BH ; High 8 Bits of Start Addr
\r
2048 OUT DX, AX ; Set Display Addr High
\r
2050 ; Wait for a Vertical Retrace to smooth out things
\r
2052 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2055 IN AL, DX ; Get VGA status
\r
2056 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
2057 JZ @SW_WAIT1 ; If Not, wait for it
\r
2059 ; Now Set the Horizontal Pixel Pan values
\r
2061 OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register
\r
2063 MOV AX, [BP].SW_Xpos ; Get Desired X Offset
\r
2064 AND AL, 03 ; Get # of Pixels to Pan (0-3)
\r
2065 SHL AL, 1 ; Shift for 256 Color Mode
\r
2066 OUT DX, AL ; Fine tune the display!
\r
2069 POP BP ; Restore Saved Registers
\r
2070 RET 6 ; Exit and Clean up Stack
\r
2079 ; Returns the X coordinate of the Pixel currently display
\r
2080 ; in the upper left corner of the display
\r
2082 ; ENTRY: No Parameters are passed
\r
2084 ; EXIT: AX = Current Horizontal Scroll Offset
\r
2087 PUBLIC GET_X_OFFSET
\r
2089 GET_X_OFFSET PROC FAR
\r
2091 MOV AX, CURRENT_XOFFSET ; Get current horz offset
\r
2092 RET ; Exit & Clean Up Stack
\r
2101 ; Returns the Y coordinate of the Pixel currently display
\r
2102 ; in the upper left corner of the display
\r
2104 ; ENTRY: No Parameters are passed
\r
2106 ; EXIT: AX = Current Vertical Scroll Offset
\r
2109 PUBLIC GET_Y_OFFSET
\r
2111 GET_Y_OFFSET PROC FAR
\r
2113 MOV AX, CURRENT_YOFFSET ; Get current vertical offset
\r
2114 RET ; Exit & Clean Up Stack
\r
2123 ; Pauses the computer until the next Vertical Retrace starts
\r
2125 ; ENTRY: No Parameters are passed
\r
2127 ; EXIT: No meaningful values returned
\r
2130 PUBLIC SYNC_DISPLAY
\r
2132 SYNC_DISPLAY PROC FAR
\r
2134 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2136 ; Wait for any current retrace to end
\r
2139 IN AL, DX ; Get VGA status
\r
2140 AND AL, VERT_RETRACE ; In Display mode yet?
\r
2141 JNZ @SD_WAIT0 ; If Not, wait for it
\r
2143 ; Wait for the start of the next vertical retrace
\r
2146 IN AL, DX ; Get VGA status
\r
2147 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
2148 JZ @SD_WAIT1 ; If Not, wait for it
\r
2150 RET ; Exit & Clean Up Stack
\r
2155 ; ===== TEXT DISPLAY ROUTINES =====
\r
2157 ;==================================================
\r
2158 ;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2159 ;==================================================
\r
2161 ; Draws an ASCII Text Character using the currently selected
\r
2162 ; 8x8 font on the active display page. It would be a simple
\r
2163 ; exercise to make this routine process variable height fonts.
\r
2165 ; ENTRY: CharNum = ASCII character # to draw
\r
2166 ; Xpos = X position to draw Character at
\r
2167 ; Ypos = Y position of to draw Character at
\r
2168 ; ColorF = Color to draw text character in
\r
2169 ; ColorB = Color to set background to
\r
2171 ; EXIT: No meaningful values returned
\r
2175 GPC_Width DW ? ; Screen Width-1
\r
2176 GPC_Lines DB ?,? ; Scan lines to Decode
\r
2177 GPC_T_SETS DW ? ; Saved Charset Segment
\r
2178 GPC_T_SETO DW ? ; Saved Charset Offset
\r
2179 DW ?x1 ; DI, SI, DS, BP
\r
2180 DW ?x1 ; DS, DI, SI, BP
\r
2181 DW ?x1 ; DS, DI, SI, BP
\r
2182 DW ?x1 ; DS, DI, SI, BP
\r
2184 GPC_ColorB DB ?,? ; Background Color
\r
2185 GPC_ColorF DB ?,? ; Text Color
\r
2186 GPC_Ypos DW ? ; Y Position to Print at
\r
2187 GPC_Xpos DW ? ; X position to Print at
\r
2188 GPC_Char DB ?,? ; Character to Print
\r
2195 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2200 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2201 MOV BP, SP ; Set up Stack Frame
\r
2203 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2205 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2206 MOV BX, AX ; BX = Screen Width
\r
2207 DEC BX ; = Screen Width-1
\r
2208 MOV [BP].GPC_Width, BX ; Save for later use
\r
2210 MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width
\r
2211 ADD DI, AX ; DI -> Start of Line Ypos
\r
2213 MOV AX, [BP].GPC_Xpos ; Get Xpos of Character
\r
2214 MOV CX, AX ; Save Copy of Xpos
\r
2215 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2216 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2217 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2219 ;Get Source ADDR of Character Bit Map & Save
\r
2221 MOV AL, [BP].GPC_Char ; Get Character #
\r
2222 TEST AL, 080h ; Is Hi Bit Set?
\r
2223 JZ @GPC_LowChar ; Nope, use low char set ptr
\r
2225 AND AL, 07Fh ; Mask Out Hi Bit
\r
2226 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2227 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2228 JMP s @GPC_Set_Char ; Go Setup Character Ptr
\r
2232 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2233 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2236 MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack
\r
2238 MOV AH, 0 ; Valid #'s are 0..127
\r
2239 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2240 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2241 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2242 ADD BX, AX ; BX = Offset of Selected char
\r
2243 MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack
\r
2245 AND CX, PLANE_BITS ; Get Plane #
\r
2246 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2247 SHL CH, CL ; And shift into position
\r
2248 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2250 MOV AL, 04 ; 4-Plane # = # of initial
\r
2251 SUB AL, CL ; shifts to align bit mask
\r
2252 MOV CL, AL ; Shift Count for SHL
\r
2254 ;Get segment of character map
\r
2256 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2257 INC DX ; DX -> SC_Data
\r
2259 MOV AL, 08 ; 8 Lines to Process
\r
2260 MOV [BP].GPC_Lines, AL ; Save on Stack
\r
2262 MOV DS, [BP].GPC_T_SETS ; Point to character set
\r
2264 @GPC_DECODE_CHAR_BYTE:
\r
2266 MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String
\r
2268 MOV BH, [SI] ; Get Bit Map
\r
2269 INC SI ; Point to Next Line
\r
2270 MOV [BP].GPC_T_SETO, SI ; And save new Pointer...
\r
2272 mov ax,0 ; Clear AX
\r
2274 ;mov bl,0 ; Clear BL
\r
2276 ROL BX, CL ; BL holds left edge bits
\r
2277 MOV SI, BX ; Use as Table Index
\r
2278 AND SI, CHAR_BITS ; Get Low Bits
\r
2279 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2280 JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2282 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2283 OUT DX, AL ; Set up Screen Mask
\r
2284 MOV ES:[DI], AH ; Write Foreground color
\r
2286 @GPC_NO_LEFT1BITS:
\r
2287 XOR AL, CH ; Invert mask for Background
\r
2288 JZ @GPC_NO_LEFT0BITS ; Hey, no need for this
\r
2290 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2291 OUT DX, AL ; Set up Screen Mask
\r
2292 MOV ES:[DI], AH ; Write Foreground color
\r
2294 ;Now Do Middle/Last Band
\r
2296 @GPC_NO_LEFT0BITS:
\r
2297 INC DI ; Point to next Byte
\r
2298 ROL BX, 1 ; Shift 4 bits
\r
2299 ROL BX, 1 ; Shift 4 bits
\r
2300 ROL BX, 1 ; Shift 4 bits
\r
2301 ROL BX, 1 ; Shift 4 bits
\r
2303 MOV SI, BX ; Make Lookup Pointer
\r
2304 AND SI, CHAR_BITS ; Get Low Bits
\r
2305 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2306 JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2308 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2309 OUT DX, AL ; Set up Screen Mask
\r
2310 MOV ES:[DI], AH ; Write Foreground color
\r
2312 @GPC_NO_MIDDLE1BITS:
\r
2313 XOR AL, ALL_PLANES ; Invert mask for Background
\r
2314 JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this
\r
2316 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2317 OUT DX, AL ; Set up Screen Mask
\r
2318 MOV ES:[DI], AH ; Write Foreground color
\r
2320 @GPC_NO_MIDDLE0BITS:
\r
2321 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2322 CMP CL, 4 ; Aligned by 4?
\r
2323 JZ @GPC_NEXT_LINE ; If so, Exit now..
\r
2325 INC DI ; Point to next Byte
\r
2326 ROL BX, 1 ; Shift 4 bits
\r
2327 ROL BX, 1 ; Shift 4 bits
\r
2328 ROL BX, 1 ; Shift 4 bits
\r
2329 ROL BX, 1 ; Shift 4 bits
\r
2331 MOV SI, BX ; Make Lookup Pointer
\r
2332 AND SI, CHAR_BITS ; Get Low Bits
\r
2333 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2334 JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2336 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2337 OUT DX, AL ; Set up Screen Mask
\r
2338 MOV ES:[DI], AH ; Write Foreground color
\r
2340 @GPC_NO_RIGHT1BITS:
\r
2342 XOR AL, CH ; Invert mask for Background
\r
2343 JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this
\r
2345 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2346 OUT DX, AL ; Set up Screen Mask
\r
2347 MOV ES:[DI], AH ; Write Foreground color
\r
2349 @GPC_NO_RIGHT0BITS:
\r
2350 DEC DI ; Adjust for Next Line Advance
\r
2353 ADD DI, [BP].GPC_Width ; Point to Next Line
\r
2354 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2356 DEC [BP].GPC_Lines ; Count Down Lines
\r
2357 JZ @GPC_EXIT ; Ok... Done!
\r
2359 JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey!
\r
2362 ADD SP, 08 ; Deallocate stack workspace
\r
2363 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2368 RET 10 ; Exit and Clean up Stack
\r
2373 ;==========================================
\r
2374 ;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)
\r
2375 ;==========================================
\r
2377 ; Transparently draws an ASCII Text Character using the
\r
2378 ; currently selected 8x8 font on the active display page.
\r
2380 ; ENTRY: CharNum = ASCII character # to draw
\r
2381 ; Xpos = X position to draw Character at
\r
2382 ; Ypos = Y position of to draw Character at
\r
2383 ; ColorF = Color to draw text character in
\r
2385 ; EXIT: No meaningful values returned
\r
2389 TGP_Width DW ? ; Screen Width-1
\r
2390 TGP_Lines DB ?,? ; Scan lines to Decode
\r
2391 TGP_T_SETS DW ? ; Saved Charset Segment
\r
2392 TGP_T_SETO DW ? ; Saved Charset Offset
\r
2393 DW ?x1 ; DI, SI, DS, BP
\r
2394 DW ?x1 ; DS, DI, SI, BP
\r
2395 DW ?x1 ; DS, DI, SI, BP
\r
2396 DW ?x1 ; DS, DI, SI, BP
\r
2398 TGP_ColorF DB ?,? ; Text Color
\r
2399 TGP_Ypos DW ? ; Y Position to Print at
\r
2400 TGP_Xpos DW ? ; X position to Print at
\r
2401 TGP_Char DB ?,? ; Character to Print
\r
2408 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2413 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2414 MOV BP, SP ; Set up Stack Frame
\r
2416 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2418 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2419 MOV BX, AX ; BX = Screen Width
\r
2420 DEC BX ; = Screen Width-1
\r
2421 MOV [BP].TGP_Width, BX ; Save for later use
\r
2423 MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width
\r
2424 ADD DI, AX ; DI -> Start of Line Ypos
\r
2426 MOV AX, [BP].TGP_Xpos ; Get Xpos of Character
\r
2427 MOV CX, AX ; Save Copy of Xpos
\r
2428 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2429 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2430 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2432 ;Get Source ADDR of Character Bit Map & Save
\r
2434 MOV AL, [BP].TGP_Char ; Get Character #
\r
2435 TEST AL, 080h ; Is Hi Bit Set?
\r
2436 JZ @TGP_LowChar ; Nope, use low char set ptr
\r
2438 AND AL, 07Fh ; Mask Out Hi Bit
\r
2439 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2440 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2441 JMP s @TGP_Set_Char ; Go Setup Character Ptr
\r
2445 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2446 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2449 MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack
\r
2451 MOV AH, 0 ; Valid #'s are 0..127
\r
2452 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2453 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2454 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2455 ADD BX, AX ; BX = Offset of Selected char
\r
2456 MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack
\r
2458 AND CX, PLANE_BITS ; Get Plane #
\r
2459 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2460 SHL CH, CL ; And shift into position
\r
2461 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2463 MOV AL, 04 ; 4-Plane # = # of initial
\r
2464 SUB AL, CL ; shifts to align bit mask
\r
2465 MOV CL, AL ; Shift Count for SHL
\r
2467 ;Get segment of character map
\r
2469 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2470 INC DX ; DX -> SC_Data
\r
2472 MOV AL, 08 ; 8 Lines to Process
\r
2473 MOV [BP].TGP_Lines, AL ; Save on Stack
\r
2475 MOV DS, [BP].TGP_T_SETS ; Point to character set
\r
2477 @TGP_DECODE_CHAR_BYTE:
\r
2479 MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String
\r
2481 MOV BH, [SI] ; Get Bit Map
\r
2482 INC SI ; Point to Next Line
\r
2483 MOV [BP].TGP_T_SETO, SI ; And save new Pointer...
\r
2485 MOV AH, [BP].TGP_ColorF ; Get Foreground Color
\r
2487 mov bl,0 ; Clear BL
\r
2488 ROL BX, CL ; BL holds left edge bits
\r
2489 MOV SI, BX ; Use as Table Index
\r
2490 AND SI, CHAR_BITS ; Get Low Bits
\r
2491 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2492 JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2494 OUT DX, AL ; Set up Screen Mask
\r
2495 MOV ES:[DI], AH ; Write Foreground color
\r
2497 ;Now Do Middle/Last Band
\r
2499 @TGP_NO_LEFT1BITS:
\r
2501 INC DI ; Point to next Byte
\r
2502 ROL BX, 1 ; Shift 4 bits
\r
2503 ROL BX, 1 ; Shift 4 bits
\r
2504 ROL BX, 1 ; Shift 4 bits
\r
2505 ROL BX, 1 ; Shift 4 bits
\r
2507 MOV SI, BX ; Make Lookup Pointer
\r
2508 AND SI, CHAR_BITS ; Get Low Bits
\r
2509 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2510 JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2512 OUT DX, AL ; Set up Screen Mask
\r
2513 MOV ES:[DI], AH ; Write Foreground color
\r
2515 @TGP_NO_MIDDLE1BITS:
\r
2516 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2517 CMP CL, 4 ; Aligned by 4?
\r
2518 JZ @TGP_NEXT_LINE ; If so, Exit now..
\r
2520 INC DI ; Point to next Byte
\r
2521 ROL BX, 1 ; Shift 4 bits
\r
2522 ROL BX, 1 ; Shift 4 bits
\r
2523 ROL BX, 1 ; Shift 4 bits
\r
2524 ROL BX, 1 ; Shift 4 bits
\r
2526 MOV SI, BX ; Make Lookup Pointer
\r
2527 AND SI, CHAR_BITS ; Get Low Bits
\r
2528 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2529 JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2531 OUT DX, AL ; Set up Screen Mask
\r
2532 MOV ES:[DI], AH ; Write Foreground color
\r
2534 @TGP_NO_RIGHT1BITS:
\r
2536 DEC DI ; Adjust for Next Line Advance
\r
2539 ADD DI, [BP].TGP_Width ; Point to Next Line
\r
2540 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2542 DEC [BP].TGP_Lines ; Count Down Lines
\r
2543 JZ @TGP_EXIT ; Ok... Done!
\r
2545 JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey!
\r
2548 ADD SP, 08 ; Deallocate stack workspace
\r
2549 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2554 RET 8 ; Exit and Clean up Stack
\r
2559 ;===============================================================
\r
2560 ;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2561 ;===============================================================
\r
2563 ; Routine to quickly Print a null terminated ASCII string on the
\r
2564 ; active display page up to a maximum length.
\r
2566 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2567 ; MaxLen = # of characters to print if no null found
\r
2568 ; Xpos = X position to draw Text at
\r
2569 ; Ypos = Y position of to draw Text at
\r
2570 ; ColorF = Color to draw text in
\r
2571 ; ColorB = Color to set background to
\r
2573 ; EXIT: No meaningful values returned
\r
2577 DW ?x1 ; DI, SI, DS, BP
\r
2578 DW ?x1 ; DI, SI, DS, BP
\r
2579 DW ?x1 ; DS, DI, SI, BP
\r
2580 DW ?x1 ; DS, DI, SI, BP
\r
2582 PS_ColorB DW ? ; Background Color
\r
2583 PS_ColorF DW ? ; Text Color
\r
2584 PS_Ypos DW ? ; Y Position to Print at
\r
2585 PS_Xpos DW ? ; X position to Print at
\r
2586 PS_Len DW ? ; Maximum Length of string to print
\r
2587 PS_Text DW ?,? ; Far Ptr to Text String
\r
2592 PRINT_STR PROC FAR
\r
2594 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2599 MOV BP, SP ; Set up Stack Frame
\r
2603 MOV CX, [BP].PS_Len ; Get Remaining text Length
\r
2604 JCXZ @PS_Exit ; Exit when out of text
\r
2606 LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text
\r
2607 MOV AL, ES:[DI] ; AL = Text Character
\r
2608 AND AX, 00FFh ; Clear High Word
\r
2609 JZ @PS_Exit ; Exit if null character
\r
2611 DEC [BP].PS_Len ; Remaining Text length--
\r
2612 INC [BP].PS_Text ; Point to Next text char
\r
2614 ; Set up Call to GPRINTC
\r
2616 PUSH AX ; Set Character Parameter
\r
2617 MOV BX, [BP].PS_Xpos ; Get Xpos
\r
2618 PUSH BX ; Set Xpos Parameter
\r
2619 ADD BX, 8 ; Advance 1 Char to Right
\r
2620 MOV [BP].PS_Xpos, BX ; Save for next time through
\r
2622 MOV BX, [BP].PS_Ypos ; Get Ypos
\r
2623 PUSH BX ; Set Ypos Parameter
\r
2625 MOV BX, [BP].PS_ColorF ; Get Text Color
\r
2626 PUSH BX ; Set ColorF Parameter
\r
2628 MOV BX, [BP].PS_ColorB ; Get Background Color
\r
2629 PUSH BX ; Set ColorB Parameter
\r
2631 CALL f GPRINTC ; Print Character!
\r
2632 JMP s @PS_Print_It ; Process next character
\r
2635 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2640 RET 14 ; Exit and Clean up Stack
\r
2645 ;================================================================
\r
2646 ;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2647 ;================================================================
\r
2649 ; Routine to quickly transparently Print a null terminated ASCII
\r
2650 ; string on the active display page up to a maximum length.
\r
2652 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2653 ; MaxLen = # of characters to print if no null found
\r
2654 ; Xpos = X position to draw Text at
\r
2655 ; Ypos = Y position of to draw Text at
\r
2656 ; ColorF = Color to draw text in
\r
2658 ; EXIT: No meaningful values returned
\r
2662 DW ?x1 ; DI, SI, DS, BP
\r
2663 DW ?x1 ; DI, SI, DS, BP
\r
2664 DW ?x1 ; DS, DI, SI, BP
\r
2665 DW ?x1 ; DS, DI, SI, BP
\r
2667 TPS_ColorF DW ? ; Text Color
\r
2668 TPS_Ypos DW ? ; Y Position to Print at
\r
2669 TPS_Xpos DW ? ; X position to Print at
\r
2670 TPS_Len DW ? ; Maximum Length of string to print
\r
2671 TPS_Text DW ?,? ; Far Ptr to Text String
\r
2676 TPRINT_STR PROC FAR
\r
2678 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2683 MOV BP, SP ; Set up Stack Frame
\r
2687 MOV CX, [BP].TPS_Len ; Get Remaining text Length
\r
2688 JCXZ @TPS_Exit ; Exit when out of text
\r
2690 LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text
\r
2691 MOV AL, ES:[DI] ; AL = Text Character
\r
2692 AND AX, 00FFh ; Clear High Word
\r
2693 JZ @TPS_Exit ; Exit if null character
\r
2695 DEC [BP].TPS_Len ; Remaining Text length--
\r
2696 INC [BP].TPS_Text ; Point to Next text char
\r
2698 ; Set up Call to TGPRINTC
\r
2700 PUSH AX ; Set Character Parameter
\r
2701 MOV BX, [BP].TPS_Xpos ; Get Xpos
\r
2702 PUSH BX ; Set Xpos Parameter
\r
2703 ADD BX, 8 ; Advance 1 Char to Right
\r
2704 MOV [BP].TPS_Xpos, BX ; Save for next time through
\r
2706 MOV BX, [BP].TPS_Ypos ; Get Ypos
\r
2707 PUSH BX ; Set Ypos Parameter
\r
2709 MOV BX, [BP].TPS_ColorF ; Get Text Color
\r
2710 PUSH BX ; Set ColorF Parameter
\r
2712 CALL f TGPRINTC ; Print Character!
\r
2713 JMP s @TPS_Print_It ; Process next character
\r
2716 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2721 RET 12 ; Exit and Clean up Stack
\r
2726 ;===========================================
\r
2727 ;SET_DISPLAY_FONT(SEG FontData, FontNumber%)
\r
2728 ;===========================================
\r
2730 ; Allows the user to specify their own font data for
\r
2731 ; wither the lower or upper 128 characters.
\r
2733 ; ENTRY: FontData = Far Pointer to Font Bitmaps
\r
2734 ; FontNumber = Which half of set this is
\r
2735 ; = 0, Lower 128 characters
\r
2736 ; = 1, Upper 128 characters
\r
2738 ; EXIT: No meaningful values returned
\r
2744 SDF_Which DW ? ; Hi Table/Low Table Flag
\r
2745 SDF_Font DD ? ; Far Ptr to Font Table
\r
2748 PUBLIC SET_DISPLAY_FONT
\r
2750 SET_DISPLAY_FONT PROC FAR
\r
2752 PUSH BP ; Preserve Registers
\r
2753 MOV BP, SP ; Set up Stack Frame
\r
2755 LES DI, [BP].SDF_Font ; Get Far Ptr to Font
\r
2757 MOV SI, o CHARSET_LOW ; Assume Lower 128 chars
\r
2758 TEST [BP].SDF_Which, 1 ; Font #1 selected?
\r
2759 JZ @SDF_Set_Font ; If not, skip ahead
\r
2761 MOV SI, o CHARSET_HI ; Ah, really it's 128-255
\r
2764 MOV [SI], DI ; Set Font Pointer Offset
\r
2765 MOV [SI+2], ES ; Set Font Pointer Segment
\r
2767 POP BP ; Restore Registers
\r
2768 RET 6 ; We are Done.. Outa here
\r
2770 SET_DISPLAY_FONT ENDP
\r
2773 ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====
\r
2775 ;======================================================
\r
2776 ;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2777 ;======================================================
\r
2779 ; Draws a variable sized Graphics Bitmap such as a
\r
2780 ; picture or an Icon on the current Display Page in
\r
2781 ; Mode X. The Bitmap is stored in a linear byte array
\r
2782 ; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)
\r
2783 ; This is the same linear manner as mode 13h graphics.
\r
2785 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2786 ; Xpos = X position to Place Upper Left pixel at
\r
2787 ; Ypos = Y position to Place Upper Left pixel at
\r
2788 ; Width = Width of the Bitmap in Pixels
\r
2789 ; Height = Height of the Bitmap in Pixels
\r
2791 ; EXIT: No meaningful values returned
\r
2795 DB_LineO DW ? ; Offset to Next Line
\r
2796 DB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2797 DB_Start DW ? ; Addr of Upper Left Pixel
\r
2798 DB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2799 DB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2800 DW ?x1 ; DI, SI, DS, BP
\r
2801 DW ?x1 ; DI, SI, DS, BP
\r
2802 DW ?x1 ; DS, DI, SI, BP
\r
2803 DW ?x1 ; DS, DI, SI, BP
\r
2805 DB_Height DW ? ; Height of Bitmap in Pixels
\r
2806 DB_Width DW ? ; Width of Bitmap in Pixels
\r
2807 DB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2808 DB_Xpos DW ? ; X position to Draw Bitmap at
\r
2809 DB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2812 PUBLIC DRAW_BITMAP
\r
2814 DRAW_BITMAP PROC FAR
\r
2816 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2821 SUB SP, 10 ; Allocate workspace
\r
2822 MOV BP, SP ; Set up Stack Frame
\r
2824 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2825 CLD ; Direction Flag = Forward
\r
2827 MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos
\r
2828 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
2830 MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos
\r
2831 MOV CL, BL ; Save Plane # in CL
\r
2832 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2833 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2835 ADD DI, AX ; ES:DI -> Start of Line
\r
2836 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
2837 MOV [BP].DB_Start, DI ; Save Starting Addr
\r
2839 ; Compute line to line offset
\r
2841 MOV BX, [BP].DB_Width ; Get Width of Image
\r
2842 MOV DX, BX ; Save Copy in DX
\r
2843 SHR BX, 1 ; /4 = width in bands
\r
2844 SHR BX, 1 ; /4 = width in bands
\r
2845 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
2846 SUB AX, BX ; - (Bitmap Width/4)
\r
2848 MOV [BP].DB_LineO, AX ; Save Line Width offset
\r
2849 MOV [BP].DB_PixCount, BX ; Minimum # pix to copy
\r
2851 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
2852 MOV [BP].DB_PixSkew, DX ; Also End of Line Skew
\r
2853 MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count
\r
2855 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
2856 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
2857 SHL AH, CL ; Select correct Plane
\r
2858 OUT_16 SC_Index, AX ; Select Plane...
\r
2859 MOV BH, AH ; BH = Saved Plane Mask
\r
2860 MOV BL, 4 ; BL = Planes to Copy
\r
2864 LDS SI, [BP].DB_Image ; DS:SI-> Source Image
\r
2865 MOV DX, [BP].DB_Height ; # of Lines to Copy
\r
2866 MOV DI, [BP].DB_Start ; ES:DI-> Dest pos
\r
2869 MOV CX, [BP].DB_PixCount ; Min # to copy
\r
2871 TEST CL, 0FCh ; 16+PixWide?
\r
2872 JZ @DB_COPY_REMAINDER ; Nope...
\r
2874 ; Pixel Copy loop has been unrolled to x4
\r
2877 MOVSB ; Copy Bitmap Pixel
\r
2878 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2879 MOVSB ; Copy Bitmap Pixel
\r
2880 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2881 MOVSB ; Copy Bitmap Pixel
\r
2882 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2883 MOVSB ; Copy Bitmap Pixel
\r
2884 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2886 SUB CL, 4 ; Pixels to Copy=-4
\r
2887 TEST CL, 0FCh ; 4+ Pixels Left?
\r
2888 JNZ @DB_COPY_LOOP ; if so, do another block
\r
2890 @DB_COPY_REMAINDER:
\r
2891 JCXZ @DB_NEXT_LINE ; Any Pixels left on line
\r
2894 MOVSB ; Copy Bitmap Pixel
\r
2895 ADD SI,3 ; Skip to Next Byte in same plane
\r
2896 LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done
\r
2900 ; any Partial Pixels? (some planes only)
\r
2902 OR CX, [BP].DB_SkewFlag ; Get Skew Count
\r
2903 JZ @DB_NEXT2 ; if no partial pixels
\r
2905 MOVSB ; Copy Bitmap Pixel
\r
2906 DEC DI ; Back up to align
\r
2907 DEC SI ; Back up to align
\r
2910 ADD SI, [BP].DB_PixSkew ; Adjust Skew
\r
2911 ADD DI, [BP].DB_LineO ; Set to Next Display Line
\r
2912 LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more
\r
2914 ; Copy Next Plane....
\r
2916 DEC BL ; Planes to Go--
\r
2917 JZ @DB_Exit ; Hey! We are done
\r
2919 ROL BH, 1 ; Next Plane in line...
\r
2920 OUT_8 SC_Data, BH ; Select Plane
\r
2922 CMP AL, 12h ; Carry Set if AL=11h
\r
2923 ADC [BP].DB_Start, 0 ; Screen Addr =+Carry
\r
2924 INC w [BP].DB_Image ; Start @ Next Byte
\r
2926 SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew
\r
2927 ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1
\r
2929 JMP s @DB_COPY_PLANE ; Go Copy the Next Plane
\r
2932 ADD SP, 10 ; Deallocate workspace
\r
2933 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2938 RET 12 ; Exit and Clean up Stack
\r
2943 ;=======================================================
\r
2944 ;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2945 ;=======================================================
\r
2947 ; Transparently Draws a variable sized Graphics Bitmap
\r
2948 ; such as a picture or an Icon on the current Display Page
\r
2949 ; in Mode X. Pixels with a value of 0 are not drawn,
\r
2950 ; leaving the previous "background" contents intact.
\r
2952 ; The Bitmap format is the same as for the DRAW_BITMAP function.
\r
2954 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2955 ; Xpos = X position to Place Upper Left pixel at
\r
2956 ; Ypos = Y position to Place Upper Left pixel at
\r
2957 ; Width = Width of the Bitmap in Pixels
\r
2958 ; Height = Height of the Bitmap in Pixels
\r
2960 ; EXIT: No meaningful values returned
\r
2964 TB_LineO DW ? ; Offset to Next Line
\r
2965 TB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2966 TB_Start DW ? ; Addr of Upper Left Pixel
\r
2967 TB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2968 TB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2969 DW ?x1 ; DI, SI, DS, BP
\r
2970 DW ?x1 ; DI, SI, DS, BP
\r
2971 DW ?x1 ; DS, DI, SI, BP
\r
2972 DW ?x1 ; DS, DI, SI, BP
\r
2974 TB_Height DW ? ; Height of Bitmap in Pixels
\r
2975 TB_Width DW ? ; Width of Bitmap in Pixels
\r
2976 TB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2977 TB_Xpos DW ? ; X position to Draw Bitmap at
\r
2978 TB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2981 PUBLIC TDRAW_BITMAP
\r
2983 TDRAW_BITMAP PROC FAR
\r
2985 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2990 SUB SP, 10 ; Allocate workspace
\r
2991 MOV BP, SP ; Set up Stack Frame
\r
2993 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2994 CLD ; Direction Flag = Forward
\r
2996 MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos
\r
2997 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
2999 MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos
\r
3000 MOV CL, BL ; Save Plane # in CL
\r
3001 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
3002 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
3004 ADD DI, AX ; ES:DI -> Start of Line
\r
3005 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
3006 MOV [BP].TB_Start, DI ; Save Starting Addr
\r
3008 ; Compute line to line offset
\r
3010 MOV BX, [BP].TB_Width ; Get Width of Image
\r
3011 MOV DX, BX ; Save Copy in DX
\r
3012 SHR BX, 1 ; /4 = width in bands
\r
3013 SHR BX, 1 ; /4 = width in bands
\r
3014 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
3015 SUB AX, BX ; - (Bitmap Width/4)
\r
3017 MOV [BP].TB_LineO, AX ; Save Line Width offset
\r
3018 MOV [BP].TB_PixCount, BX ; Minimum # pix to copy
\r
3020 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
3021 MOV [BP].TB_PixSkew, DX ; Also End of Line Skew
\r
3022 MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count
\r
3024 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
3025 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
3026 SHL AH, CL ; Select correct Plane
\r
3027 OUT_16 SC_Index, AX ; Select Plane...
\r
3028 MOV BH, AH ; BH = Saved Plane Mask
\r
3029 MOV BL, 4 ; BL = Planes to Copy
\r
3033 LDS SI, [BP].TB_Image ; DS:SI-> Source Image
\r
3034 MOV DX, [BP].TB_Height ; # of Lines to Copy
\r
3035 MOV DI, [BP].TB_Start ; ES:DI-> Dest pos
\r
3037 ; Here AH is set with the value to be considered
\r
3038 ; "Transparent". It can be changed!
\r
3040 MOV AH, 0 ; Value to Detect 0
\r
3043 MOV CX, [BP].TB_PixCount ; Min # to copy
\r
3045 TEST CL, 0FCh ; 16+PixWide?
\r
3046 JZ @TB_COPY_REMAINDER ; Nope...
\r
3048 ; Pixel Copy loop has been unrolled to x4
\r
3051 LODSB ; Get Pixel Value in AL
\r
3052 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3053 CMP AL, AH ; It is "Transparent"?
\r
3054 JE @TB_SKIP_01 ; Skip ahead if so
\r
3055 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3058 LODSB ; Get Pixel Value in AL
\r
3059 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3060 CMP AL, AH ; It is "Transparent"?
\r
3061 JE @TB_SKIP_02 ; Skip ahead if so
\r
3062 MOV ES:[DI+1], AL ; Copy Pixel to VGA screen
\r
3065 LODSB ; Get Pixel Value in AL
\r
3066 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3067 CMP AL, AH ; It is "Transparent"?
\r
3068 JE @TB_SKIP_03 ; Skip ahead if so
\r
3069 MOV ES:[DI+2], AL ; Copy Pixel to VGA screen
\r
3072 LODSB ; Get Pixel Value in AL
\r
3073 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3074 CMP AL, AH ; It is "Transparent"?
\r
3075 JE @TB_SKIP_04 ; Skip ahead if so
\r
3076 MOV ES:[DI+3], AL ; Copy Pixel to VGA screen
\r
3079 ADD DI, 4 ; Adjust Pixel Write Location
\r
3080 SUB CL, 4 ; Pixels to Copy=-4
\r
3081 TEST CL, 0FCh ; 4+ Pixels Left?
\r
3082 JNZ @TB_COPY_LOOP ; if so, do another block
\r
3084 @TB_COPY_REMAINDER:
\r
3085 JCXZ @TB_NEXT_LINE ; Any Pixels left on line
\r
3088 LODSB ; Get Pixel Value in AL
\r
3089 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3090 CMP AL, AH ; It is "Transparent"?
\r
3091 JE @TB_SKIP_05 ; Skip ahead if so
\r
3092 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3095 INC DI ; Advance Dest Addr
\r
3096 LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done
\r
3100 ; any Partial Pixels? (some planes only)
\r
3102 OR CX, [BP].TB_SkewFlag ; Get Skew Count
\r
3103 JZ @TB_NEXT2 ; if no partial pixels
\r
3105 LODSB ; Get Pixel Value in AL
\r
3106 DEC SI ; Backup to Align
\r
3107 CMP AL, AH ; It is "Transparent"?
\r
3108 JE @TB_NEXT2 ; Skip ahead if so
\r
3109 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3112 ADD SI, [BP].TB_PixSkew ; Adjust Skew
\r
3113 ADD DI, [BP].TB_LineO ; Set to Next Display Line
\r
3114 LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More
\r
3116 ;Copy Next Plane....
\r
3118 DEC BL ; Planes to Go--
\r
3119 JZ @TB_Exit ; Hey! We are done
\r
3121 ROL BH, 1 ; Next Plane in line...
\r
3122 OUT_8 SC_Data, BH ; Select Plane
\r
3124 CMP AL, 12h ; Carry Set if AL=11h
\r
3125 ADC [BP].TB_Start, 0 ; Screen Addr =+Carry
\r
3126 INC w [BP].TB_Image ; Start @ Next Byte
\r
3128 SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew
\r
3129 ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1
\r
3131 JMP @TB_COPY_PLANE ; Go Copy the next Plane
\r
3134 ADD SP, 10 ; Deallocate workspace
\r
3135 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3140 RET 12 ; Exit and Clean up Stack
\r
3145 ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====
\r
3147 ;==================================
\r
3148 ;COPY_PAGE (SourcePage%, DestPage%)
\r
3149 ;==================================
\r
3151 ; Duplicate on display page onto another
\r
3153 ; ENTRY: SourcePage = Display Page # to Duplicate
\r
3154 ; DestPage = Display Page # to hold copy
\r
3156 ; EXIT: No meaningful values returned
\r
3160 DW ?x1 ; DI, SI, DS, BP
\r
3161 DW ?x1 ; DI, SI, DS, BP
\r
3162 DW ?x1 ; DS, DI, SI, BP
\r
3163 DW ?x1 ; DS, DI, SI, BP
\r
3165 CP_DestP DW ? ; Page to hold copied image
\r
3166 CP_SourceP DW ? ; Page to Make copy from
\r
3171 COPY_PAGE PROC FAR
\r
3173 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
3178 MOV BP, SP ; Set up Stack Frame
\r
3179 CLD ; Block Xfer Forwards
\r
3181 ; Make sure Page #'s are valid
\r
3183 MOV AX, [BP].CP_SourceP ; Get Source Page #
\r
3184 CMP AX, LAST_PAGE ; is it > Max Page #?
\r
3185 JAE @CP_Exit ; if so, abort
\r
3187 MOV BX, [BP].CP_DestP ; Get Destination Page #
\r
3188 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3189 JAE @CP_Exit ; if so, abort
\r
3191 CMP AX, BX ; Pages #'s the same?
\r
3192 JE @CP_Exit ; if so, abort
\r
3194 ; Setup DS:SI and ES:DI to Video Pages
\r
3196 SHL BX, 1 ; Scale index to Word
\r
3197 MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page
\r
3199 MOV BX, AX ; Index to Source page
\r
3200 SHL BX, 1 ; Scale index to Word
\r
3201 MOV SI, PAGE_ADDR[BX] ; Offset to Source Page
\r
3203 MOV CX, PAGE_SIZE ; Get size of Page
\r
3204 MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment
\r
3205 MOV ES, AX ; ES:DI -> Dest Page
\r
3206 MOV DS, AX ; DS:SI -> Source Page
\r
3208 ; Setup VGA registers for Mem to Mem copy
\r
3210 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3211 OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes
\r
3213 ; Note.. Do *NOT* use MOVSW or MOVSD - they will
\r
3214 ; Screw with the latches which are 8 bits x 4
\r
3216 REP MOVSB ; Copy entire Page!
\r
3218 ; Reset VGA for normal memory access
\r
3220 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off
\r
3223 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3228 RET 4 ; Exit and Clean up Stack
\r
3233 ;==========================================================================
\r
3234 ;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)
\r
3235 ;==========================================================================
\r
3237 ; Copies a Bitmap Image from one Display Page to Another
\r
3238 ; This Routine is Limited to copying Images with the same
\r
3239 ; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4)
\r
3240 ; Copying an Image to the Same Page is supported, but results
\r
3241 ; may be defined when the when the rectangular areas
\r
3242 ; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) -
\r
3243 ; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...
\r
3244 ; No Paramter checking to done to insure that
\r
3245 ; X2 >= X1 and Y2 >= Y1. Be Careful...
\r
3247 ; ENTRY: SourcePage = Display Page # with Source Image
\r
3248 ; X1 = Upper Left Xpos of Source Image
\r
3249 ; Y1 = Upper Left Ypos of Source Image
\r
3250 ; X2 = Lower Right Xpos of Source Image
\r
3251 ; Y2 = Lower Right Ypos of Source Image
\r
3252 ; DestPage = Display Page # to copy Image to
\r
3253 ; DestX1 = Xpos to Copy UL Corner of Image to
\r
3254 ; DestY1 = Ypos to Copy UL Corner of Image to
\r
3256 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
3260 CB_Height DW ? ; Height of Image in Lines
\r
3261 CB_Width DW ? ; Width of Image in "bands"
\r
3262 DW ?x1 ; DI, SI, DS, BP
\r
3263 DW ?x1 ; DI, SI, DS, BP
\r
3264 DW ?x1 ; DS, DI, SI, BP
\r
3265 DW ?x1 ; DS, DI, SI, BP
\r
3267 CB_DestY1 DW ? ; Destination Ypos
\r
3268 CB_DestX1 DW ? ; Destination Xpos
\r
3269 CB_DestP DW ? ; Page to Copy Bitmap To
\r
3270 CB_Y2 DW ? ; LR Ypos of Image
\r
3271 CB_X2 DW ? ; LR Xpos of Image
\r
3272 CB_Y1 DW ? ; UL Ypos of Image
\r
3273 CB_X1 DW ? ; UL Xpos of Image
\r
3274 CB_SourceP DW ? ; Page containing Source Bitmap
\r
3277 PUBLIC COPY_BITMAP
\r
3279 COPY_BITMAP PROC FAR
\r
3281 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
3286 SUB SP, 4 ; Allocate WorkSpace on Stack
\r
3287 MOV BP, SP ; Set up Stack Frame
\r
3289 ; Prep Registers (and keep jumps short!)
\r
3291 MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram
\r
3292 CLD ; Block Xfer Forwards
\r
3294 ; Make sure Parameters are valid
\r
3296 MOV BX, [BP].CB_SourceP ; Get Source Page #
\r
3297 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3298 JAE @CB_Abort ; if so, abort
\r
3300 MOV CX, [BP].CB_DestP ; Get Destination Page #
\r
3301 CMP CX, LAST_PAGE ; is it > Max Page #?
\r
3302 JAE @CB_Abort ; if so, abort
\r
3304 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3305 XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1
\r
3306 AND AX, PLANE_BITS ; Check Plane Bits
\r
3307 JNZ @CB_Abort ; They should cancel out
\r
3309 ; Setup for Copy processing
\r
3311 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
3312 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3314 ; Compute Info About Images, Setup ES:SI & ES:DI
\r
3316 MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines
\r
3317 SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1
\r
3318 INC AX ; (add 1 since were not 0 based)
\r
3319 MOV [BP].CB_Height, AX ; Save on Stack for later use
\r
3321 MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels
\r
3322 MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1
\r
3323 SHR AX, 1 ; Get X2 Band (X2 / 4)
\r
3324 SHR DX, 1 ; Get X1 Band (X1 / 4)
\r
3325 SHR AX, 1 ; Get X2 Band (X2 / 4)
\r
3326 SHR DX, 1 ; Get X1 Band (X1 / 4)
\r
3327 SUB AX, DX ; AX = # of Bands - 1
\r
3328 INC AX ; AX = # of Bands
\r
3329 MOV [BP].CB_Width, AX ; Save on Stack for later use
\r
3331 SHL BX, 1 ; Scale Source Page to Word
\r
3332 MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page
\r
3333 MOV AX, [BP].CB_Y1 ; Get Source Y1 Line
\r
3334 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3335 ADD SI, AX ; SI = Offset to Line Y1
\r
3336 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3337 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3338 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3339 ADD SI, AX ; SI = Byte Offset to (X1,Y1)
\r
3341 MOV BX, CX ; Dest Page Index to BX
\r
3342 SHL BX, 1 ; Scale Source Page to Word
\r
3343 MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page
\r
3344 MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line
\r
3345 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3346 ADD DI, AX ; DI = Offset to Line Y1
\r
3347 MOV AX, [BP].CB_DestX1 ; Get Dest X1
\r
3348 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3349 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3350 ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1)
\r
3352 MOV CX, [BP].CB_Width ; CX = Width of Image (Bands)
\r
3354 JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band
\r
3356 MOV BX, [BP].CB_X1 ; Get Source X1
\r
3357 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?)
\r
3358 JZ @CB_Check_Right ; if so, check right alignment
\r
3359 JNZ @CB_Left_Band ; not aligned? well..
\r
3362 mov ax,0 ; Return False (Failure)
\r
3363 JMP @CB_Exit ; and Finish Up
\r
3365 ; Copy when Left & Right Clip Masks overlap...
\r
3367 @CB_Only_One_Band:
\r
3368 MOV BX, [BP].CB_X1 ; Get Left Clip Mask
\r
3369 AND BX, PLANE_BITS ; Mask out Row #
\r
3370 MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask
\r
3371 MOV BX, [BP].CB_X2 ; Get Right Clip Mask
\r
3372 AND BX, PLANE_BITS ; Mask out Row #
\r
3373 AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte
\r
3375 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
3377 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3378 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3379 mov bx,0 ; BX = Offset into Image
\r
3382 MOV AL, ES:[SI+BX] ; Load Latches
\r
3383 MOV ES:[DI+BX], AL ; Unload Latches
\r
3384 ADD BX, DX ; Advance Offset to Next Line
\r
3385 LOOPjz CX, @CB_One_Done ; Exit Loop if Finished
\r
3387 MOV AL, ES:[SI+BX] ; Load Latches
\r
3388 MOV ES:[DI+BX], AL ; Unload Latches
\r
3389 ADD BX, DX ; Advance Offset to Next Line
\r
3390 LOOPx CX, @CB_One_Loop ; Loop until Finished
\r
3393 JMP @CB_Finish ; Outa Here!
\r
3395 ; Copy Left Edge of Bitmap
\r
3399 OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask
\r
3401 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3402 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3403 mov bx,0 ; BX = Offset into Image
\r
3406 MOV AL, ES:[SI+BX] ; Load Latches
\r
3407 MOV ES:[DI+BX], AL ; Unload Latches
\r
3408 ADD BX, DX ; Advance Offset to Next Line
\r
3409 LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished
\r
3411 MOV AL, ES:[SI+BX] ; Load Latches
\r
3412 MOV ES:[DI+BX], AL ; Unload Latches
\r
3413 ADD BX, DX ; Advance Offset to Next Line
\r
3414 LOOPx CX, @CB_Left_Loop ; Loop until Finished
\r
3417 INC DI ; Move Dest Over 1 band
\r
3418 INC SI ; Move Source Over 1 band
\r
3419 DEC [BP].CB_Width ; Band Width--
\r
3421 ; Determine if Right Edge of Bitmap needs special copy
\r
3424 MOV BX, [BP].CB_X2 ; Get Source X2
\r
3425 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?)
\r
3426 CMP BL, 03h ; Plane = 3?
\r
3427 JE @CB_Copy_Middle ; Copy the Middle then!
\r
3429 ; Copy Right Edge of Bitmap
\r
3433 OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask
\r
3435 DEC [BP].CB_Width ; Band Width--
\r
3436 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3437 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3438 MOV BX, [BP].CB_Width ; BX = Offset to Right Edge
\r
3441 MOV AL, ES:[SI+BX] ; Load Latches
\r
3442 MOV ES:[DI+BX], AL ; Unload Latches
\r
3443 ADD BX, DX ; Advance Offset to Next Line
\r
3444 LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished
\r
3446 MOV AL, ES:[SI+BX] ; Load Latches
\r
3447 MOV ES:[DI+BX], AL ; Unload Latches
\r
3448 ADD BX, DX ; Advance Offset to Next Line
\r
3449 LOOPx CX, @CB_Right_Loop ; Loop until Finished
\r
3453 ; Copy the Main Block of the Bitmap
\r
3457 MOV CX, [BP].CB_Width ; Get Width Remaining
\r
3458 JCXZ @CB_Finish ; Exit if Done
\r
3460 OUT_8 SC_Data, ALL_PLANES ; Copy all Planes
\r
3462 MOV DX, SCREEN_WIDTH ; Get Width of Screen minus
\r
3463 SUB DX, CX ; Image width (for Adjustment)
\r
3464 MOV AX, [BP].CB_Height ; AX = # of Lines to Copy
\r
3465 MOV BX, CX ; BX = Quick REP reload count
\r
3466 MOV CX, ES ; Move VGA Segment
\r
3467 MOV DS, CX ; Into DS
\r
3469 ; Actual Copy Loop. REP MOVSB does the work
\r
3472 MOV CX, BX ; Recharge Rep Count
\r
3473 REP MOVSB ; Move Bands
\r
3474 LOOPjz AX, @CB_Finish ; Exit Loop if Finished
\r
3476 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3477 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3479 MOV CX, BX ; Recharge Rep Count
\r
3480 REP MOVSB ; Move Bands
\r
3482 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3483 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3484 LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done
\r
3487 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on
\r
3490 ADD SP, 04 ; Deallocate stack workspace
\r
3491 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3496 RET 16 ; Exit and Clean up Stack
\r
3500 END ; End of Code Segment
\r