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 jmp @SVM_Continue;0000
\r
527 mov ax,8 ; Return Value = False
\r
528 JMP @SVM_Exit ; Normal Exit
\r
529 @SVM_BadModeSetup1:
\r
530 mov ax,1 ; Return Value = False
\r
531 JMP @SVM_Exit ; Normal Exit
\r
532 @SVM_BadModeSetup2:
\r
533 mov ax,2 ; Return Value = False
\r
534 JMP @SVM_Exit ; Normal Exit
\r
535 @SVM_BadModeSetup3:
\r
536 mov ax,3 ; Return Value = False
\r
537 JMP @SVM_Exit ; Normal Exit
\r
538 @SVM_BadModeSetup4:
\r
539 mov ax,4 ; Return Value = False
\r
540 JMP @SVM_Exit ; Normal Exit
\r
541 @SVM_BadModeSetup5:
\r
542 mov ax,5 ; Return Value = False
\r
543 JMP @SVM_Exit ; Normal Exit
\r
544 @SVM_BadModeSetup6:
\r
545 mov ax,6 ; Return Value = False
\r
546 JMP @SVM_Exit ; Normal Exit
\r
547 @SVM_BadModeSetup7:
\r
548 mov ax,7 ; Return Value = False
\r
549 JMP @SVM_Exit ; Normal Exit
\r
553 MOV AX, 13H ; Start with Mode 13H
\r
554 INT 10H ; Let BIOS Set Mode
\r
556 OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode
\r
557 OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset
\r
558 OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size
\r
559 OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ...
\r
561 OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register
\r
562 INC DX ; Point to Data
\r
563 IN AL, DX ; Get Value, Bit 7 = Protect
\r
564 AND AL, 7FH ; Mask out Write Protect
\r
565 OUT DX, AL ; And send it back
\r
567 MOV DX, CRTC_INDEX ; Vga Crtc Registers
\r
568 ADD SI, M_CRTC ; SI -> CRTC Parameter Data
\r
570 ; Load Tables of CRTC Parameters from List of Tables
\r
574 MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl
\r
575 ADD SI, 2 ; Point to next Ptr Entry
\r
576 OR DI, DI ; A nil Ptr means that we have
\r
577 JZ @SVM_Set_Data ; finished CRTC programming
\r
580 MOV AX, CS:[DI] ; Get CRTC Data from Table
\r
581 ADD DI, 2 ; Advance Pointer
\r
582 OR AX, AX ; At End of Data Table?
\r
583 JZ @SVM_Setup_Table ; If so, Exit & get next Table
\r
585 OUT DX, AX ; Reprogram VGA CRTC reg
\r
586 JMP s @SVM_Setup_CRTC ; Process Next Table Entry
\r
588 ; Initialize Page & Scroll info, DI = 0
\r
591 MOV DISPLAY_PAGE, DI ; Display Page = 0
\r
592 MOV ACTIVE_PAGE, DI ; Active Page = 0
\r
593 MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0
\r
594 MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0
\r
595 MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0
\r
596 MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0
\r
598 MOV AX, VGA_SEGMENT ; Segment for VGA memory
\r
599 MOV CURRENT_SEGMENT, AX ; Save for Future LES's
\r
601 ; Set Logical Screen Width, X Scroll and Our Data
\r
603 MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info
\r
604 MOV AX, [BP].SVM_Xsize ; Get Display Width
\r
606 MOV CX, AX ; CX = Logical Width
\r
607 SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value
\r
608 MOV MAX_XOFFSET, CX ; Set Maximum X Scroll
\r
610 SHR AX, 1 ; Bytes = Pixels / 4
\r
611 SHR AX, 1 ; Bytes = Pixels / 4
\r
612 MOV SCREEN_WIDTH, AX ; Save Width in Pixels
\r
614 SHR AX, 1 ; Offset Value = Bytes / 2
\r
615 MOV AH, 13h ; CRTC Offset Register Index
\r
616 XCHG AL, AH ; Switch format for OUT
\r
617 OUT DX, AX ; Set VGA CRTC Offset Reg
\r
619 ; Setup Data table, Y Scroll, Misc for Other Routines
\r
621 MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height
\r
623 MOV CX, AX ; CX = Logical Height
\r
624 SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value
\r
625 MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll
\r
627 MOV SCREEN_HEIGHT, AX ; Save Height in Pixels
\r
628 MUL SCREEN_WIDTH ; AX = Page Size in Bytes,
\r
629 MOV PAGE_SIZE, AX ; Save Page Size
\r
631 MOV CX, [BP].SVM_Pages ; Get # of Pages
\r
632 MOV LAST_PAGE, CX ; Save # of Pages
\r
634 mov bx,0 ; Page # = 0
\r
635 MOV DX, BX ; Page 0 Offset = 0
\r
639 MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset
\r
640 ADD BX, 2 ; Page#++
\r
641 ADD DX, AX ; Compute Addr of Next Page
\r
642 LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set
\r
646 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
647 LES DI, d CURRENT_PAGE ; -> Start of VGA memory
\r
650 CLD ; Block Xfer Forwards
\r
651 MOV CX, 8000H ; 32K * 4 * 2 = 256K
\r
652 REP STOSW ; Clear dat memory!
\r
654 ; Setup Font Pointers
\r
656 MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127
\r
657 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
658 INT 10h ; Call VGA BIOS
\r
660 MOV CHARSET_LOW, BP ; Save Char Set Offset
\r
661 MOV CHARSET_LOW+2, ES ; Save Char Set Segment
\r
663 MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255
\r
664 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
665 INT 10h ; Call VGA BIOS
\r
667 MOV CHARSET_HI, BP ; Save Char Set Offset
\r
668 MOV CHARSET_HI+2, ES ; Save Char Set Segment
\r
670 MOV AX, True ; Return Success Code
\r
673 ADD SP, 2 ; Deallocate workspace
\r
674 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
679 RET 8 ; Exit & Clean Up Stack
\r
684 ;==================
\r
685 ;SET_MODEX% (Mode%)
\r
686 ;==================
\r
688 ; Quickie Mode Set - Sets Up Mode X to Default Configuration
\r
690 ; ENTRY: ModeType = Desired Screen Resolution (0-7)
\r
691 ; (See SET_VGA_MODEX for list)
\r
693 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
699 SM_Mode DW ? ; Desired Screen Resolution
\r
706 ;PUSHx BP, SI ; Preserve Important registers
\r
709 MOV BP, SP ; Set up Stack Frame
\r
711 mov ax,0 ; Assume Failure
\r
712 MOV BX, [BP].SM_Mode ; Get Desired Mode #
\r
713 CMP BX, NUM_MODES ; Is it a Valid Mode #?
\r
714 JAE @SMX_Exit ; If Not, don't Bother
\r
716 PUSH BX ; Push Mode Parameter
\r
718 SHL BX, 1 ; Scale BX to word Index
\r
719 MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info
\r
721 PUSH CS:[SI].M_XSize ; Push Default X Size
\r
722 PUSH CS:[SI].M_Ysize ; Push Default Y size
\r
723 MOV AL, CS:[SI].M_Pages ; Get Default # of Pages
\r
724 mov ah,0 ; Hi Byte = 0
\r
725 PUSH AX ; Push # Pages
\r
727 CALL f SET_VGA_MODEX ; Set up Mode X!
\r
730 ;POPx SI, BP ; Restore Registers
\r
733 RET 2 ; Exit & Clean Up Stack
\r
738 ; ===== BASIC GRAPHICS PRIMITIVES =====
\r
740 ;============================
\r
741 ;CLEAR_VGA_SCREEN (ColorNum%)
\r
742 ;============================
\r
744 ; Clears the active display page
\r
746 ; ENTRY: ColorNum = Color Value to fill the page with
\r
748 ; EXIT: No meaningful values returned
\r
754 CVS_COLOR DB ?,? ; Color to Set Screen to
\r
757 PUBLIC CLEAR_VGA_SCREEN
\r
759 CLEAR_VGA_SCREEN PROC FAR
\r
761 ;PUSHx BP, DI ; Preserve Important Registers
\r
764 MOV BP, SP ; Set up Stack Frame
\r
766 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
767 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
769 MOV AL, [BP].CVS_COLOR ; Get Color
\r
770 MOV AH, AL ; Copy for Word Write
\r
771 CLD ; Block fill Forwards
\r
773 MOV CX, PAGE_SIZE ; Get Size of Page
\r
774 SHR CX, 1 ; Divide by 2 for Words
\r
775 REP STOSW ; Block Fill VGA memory
\r
777 ;POPx DI, BP ; Restore Saved Registers
\r
780 RET 2 ; Exit & Clean Up Stack
\r
782 CLEAR_VGA_SCREEN ENDP
\r
785 ;===================================
\r
786 ;SET_POINT (Xpos%, Ypos%, ColorNum%)
\r
787 ;===================================
\r
789 ; Plots a single Pixel on the active display page
\r
791 ; ENTRY: Xpos = X position to plot pixel at
\r
792 ; Ypos = Y position to plot pixel at
\r
793 ; ColorNum = Color to plot pixel with
\r
795 ; EXIT: No meaningful values returned
\r
801 SETP_Color DB ?,? ; Color of Point to Plot
\r
802 SETP_Ypos DW ? ; Y pos of Point to Plot
\r
803 SETP_Xpos DW ? ; X pos of Point to Plot
\r
810 ;PUSHx BP, DI ; Preserve Registers
\r
813 MOV BP, SP ; Set up Stack Frame
\r
815 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
817 MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel
\r
818 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
820 MOV BX, [BP].SETP_Xpos ; Get Xpos
\r
821 MOV CX, BX ; Copy to extract Plane # from
\r
822 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
823 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
824 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
826 MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register
\r
827 AND CL, PLANE_BITS ; Get Plane Bits
\r
828 SHL AH, CL ; Get Plane Select Value
\r
829 OUT_16 SC_Index, AX ; Select Plane
\r
831 MOV AL,[BP].SETP_Color ; Get Pixel Color
\r
832 MOV ES:[DI+BX], AL ; Draw Pixel
\r
834 ;POPx DI, BP ; Restore Saved Registers
\r
837 RET 6 ; Exit and Clean up Stack
\r
842 ;==========================
\r
843 ;READ_POINT% (Xpos%, Ypos%)
\r
844 ;==========================
\r
846 ; Read the color of a pixel from the Active Display Page
\r
848 ; ENTRY: Xpos = X position of pixel to read
\r
849 ; Ypos = Y position of pixel to read
\r
851 ; EXIT: AX = Color of Pixel at (Xpos, Ypos)
\r
857 RP_Ypos DW ? ; Y pos of Point to Read
\r
858 RP_Xpos DW ? ; X pos of Point to Read
\r
863 READ_POINT PROC FAR
\r
865 ;PUSHx BP, DI ; Preserve Registers
\r
868 MOV BP, SP ; Set up Stack Frame
\r
870 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
872 MOV AX, [BP].RP_Ypos ; Get Line # of Pixel
\r
873 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
875 MOV BX, [BP].RP_Xpos ; Get Xpos
\r
877 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
878 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
879 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
881 MOV AL, READ_MAP ; GC Read Mask Register
\r
882 MOV AH, CL ; Get Xpos
\r
883 AND AH, PLANE_BITS ; & mask out Plane #
\r
884 OUT_16 GC_INDEX, AX ; Select Plane to read in
\r
886 mov ah,0 ; Clear Return Value Hi byte
\r
887 MOV AL, ES:[DI+BX] ; Get Color of Pixel
\r
889 ;POPx DI, BP ; Restore Saved Registers
\r
892 RET 4 ; Exit and Clean up Stack
\r
897 ;======================================================
\r
898 ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
899 ;======================================================
\r
901 ; Fills a rectangular block on the active display Page
\r
903 ; ENTRY: Xpos1 = Left X position of area to fill
\r
904 ; Ypos1 = Top Y position of area to fill
\r
905 ; Xpos2 = Right X position of area to fill
\r
906 ; Ypos2 = Bottom Y position of area to fill
\r
907 ; ColorNum = Color to fill area with
\r
909 ; EXIT: No meaningful values returned
\r
913 DW ?x1 ; DS, DI, SI, BP
\r
914 DW ?x1 ; DS, DI, SI, BP
\r
915 DW ?x1 ; DS, DI, SI, BP
\r
916 DW ?x1 ; DS, DI, SI, BP
\r
918 FB_Color DB ?,? ; Fill Color
\r
919 FB_Ypos2 DW ? ; Y pos of Lower Right Pixel
\r
920 FB_Xpos2 DW ? ; X pos of Lower Right Pixel
\r
921 FB_Ypos1 DW ? ; Y pos of Upper Left Pixel
\r
922 FB_Xpos1 DW ? ; X pos of Upper Left Pixel
\r
927 FILL_BLOCK PROC FAR
\r
929 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
934 MOV BP, SP ; Set up Stack Frame
\r
936 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
937 CLD ; Direction Flag = Forward
\r
939 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
941 ; Validate Pixel Coordinates
\r
942 ; If necessary, Swap so X1 <= X2, Y1 <= Y2
\r
944 MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2?
\r
945 MOV BX, [BP].FB_Ypos2 ; BX = Y2
\r
949 MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1
\r
950 XCHG AX, BX ; on stack for future use
\r
953 SUB BX, AX ; Get Y width
\r
954 INC BX ; Add 1 to avoid 0 value
\r
955 MOV [BP].FB_Ypos2, BX ; Save in Ypos2
\r
957 MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line
\r
958 ADD DI, AX ; DI = Start of Line Y1
\r
960 MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2
\r
961 MOV BX, [BP].FB_Xpos2 ;
\r
963 JLE @FB_NOSWAP2 ; Skip Ahead if Ok
\r
965 MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2
\r
966 XCHG AX, BX ; on stack for future use
\r
968 ; All our Input Values are in order, Now determine
\r
969 ; How many full "bands" 4 pixels wide (aligned) there
\r
970 ; are, and if there are partial bands (<4 pixels) on
\r
971 ; the left and right edges.
\r
974 MOV DX, AX ; DX = X1 (Pixel Position)
\r
975 SHR DX, 1 ; DX/4 = Bytes into Line
\r
976 SHR DX, 1 ; DX/4 = Bytes into Line
\r
977 ADD DI, DX ; DI = Addr of Upper-Left Corner
\r
979 MOV CX, BX ; CX = X2 (Pixel Position)
\r
980 SHR CX, 1 ; CX/4 = Bytes into Line
\r
981 SHR CX, 1 ; CX/4 = Bytes into Line
\r
983 CMP DX, CX ; Start and end in same band?
\r
984 JNE @FB_NORMAL ; if not, check for l & r edges
\r
985 JMP @FB_ONE_BAND_ONLY ; if so, then special processing
\r
988 SUB CX, DX ; CX = # bands -1
\r
989 MOV SI, AX ; SI = PLANE#(X1)
\r
990 AND SI, PLANE_BITS ; if Left edge is aligned then
\r
991 JZ @FB_L_PLANE_FLUSH ; no special processing..
\r
993 ; Draw "Left Edge" vertical strip of 1-3 pixels...
\r
995 OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask
\r
997 MOV SI, DI ; SI = Copy of Start Addr (UL)
\r
999 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1000 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1001 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1004 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
1005 ADD SI, BX ; Point to Next Line (Below)
\r
1006 LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn
\r
1008 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
1009 ADD SI, BX ; Point to Next Line (Below)
\r
1010 LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn
\r
1014 INC DI ; Point to Middle (or Right) Block
\r
1015 DEC CX ; Reset CX instead of JMP @FB_RIGHT
\r
1017 @FB_L_PLANE_FLUSH:
\r
1018 INC CX ; Add in Left band to middle block
\r
1020 ; DI = Addr of 1st middle Pixel (band) to fill
\r
1021 ; CX = # of Bands to fill -1
\r
1024 MOV SI, [BP].FB_Xpos2 ; Get Xpos2
\r
1025 AND SI, PLANE_BITS ; Get Plane values
\r
1026 CMP SI, 0003 ; Plane = 3?
\r
1027 JE @FB_R_EDGE_FLUSH ; Hey, add to middle
\r
1029 ; Draw "Right Edge" vertical strip of 1-3 pixels...
\r
1031 OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask
\r
1033 MOV SI, DI ; Get Addr of Left Edge
\r
1034 ADD SI, CX ; Add Width-1 (Bands)
\r
1035 DEC SI ; To point to top of Right Edge
\r
1037 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1038 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1039 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1042 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
1043 ADD SI, BX ; Point to Next Line (Below)
\r
1044 LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn
\r
1046 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
1047 ADD SI, BX ; Point to Next Line (Below)
\r
1048 LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn
\r
1052 DEC CX ; Minus 1 for Middle bands
\r
1053 JZ @FB_EXIT ; Uh.. no Middle bands...
\r
1057 ; DI = Addr of Upper Left block to fill
\r
1058 ; CX = # of Bands to fill in (width)
\r
1060 OUT_8 SC_Data, ALL_PLANES ; Write to All Planes
\r
1062 MOV DX, SCREEN_WIDTH ; DX = DI Increment
\r
1063 SUB DX, CX ; = Screen_Width-# Planes Filled
\r
1065 MOV BX, CX ; BX = Quick Refill for CX
\r
1066 MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill
\r
1067 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1070 REP STOSB ; Fill in entire line
\r
1072 MOV CX, BX ; Recharge CX (Line Width)
\r
1073 ADD DI, DX ; Point to start of Next Line
\r
1074 LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn
\r
1076 JMP s @FB_EXIT ; Outa here
\r
1078 @FB_ONE_BAND_ONLY:
\r
1079 MOV SI, AX ; Get Left Clip Mask, Save X1
\r
1080 AND SI, PLANE_BITS ; Mask out Row #
\r
1081 MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1082 MOV SI, BX ; Get Right Clip Mask, Save X2
\r
1083 AND SI, PLANE_BITS ; Mask out Row #
\r
1084 AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte
\r
1086 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
1088 MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1089 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1090 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1093 MOV ES:[DI], AL ; Fill in Pixels
\r
1094 ADD DI, BX ; Point to Next Line (Below)
\r
1095 LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn
\r
1097 MOV ES:[DI], AL ; Fill in Pixels
\r
1098 ADD DI, BX ; Point to Next Line (Below)
\r
1099 LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn
\r
1102 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
1107 RET 10 ; Exit and Clean up Stack
\r
1112 ;=====================================================
\r
1113 ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
1114 ;=====================================================
\r
1116 ; Draws a Line on the active display page
\r
1118 ; ENTRY: Xpos1 = X position of first point on line
\r
1119 ; Ypos1 = Y position of first point on line
\r
1120 ; Xpos2 = X position of last point on line
\r
1121 ; Ypos2 = Y position of last point on line
\r
1122 ; ColorNum = Color to draw line with
\r
1124 ; EXIT: No meaningful values returned
\r
1128 DW ?x1 ; DI, SI, BP
\r
1129 DW ?x1 ; DI, SI, BP
\r
1130 DW ?x1 ; DI, SI, BP
\r
1132 DL_ColorF DB ?,? ; Line Draw Color
\r
1133 DL_Ypos2 DW ? ; Y pos of last point
\r
1134 DL_Xpos2 DW ? ; X pos of last point
\r
1135 DL_Ypos1 DW ? ; Y pos of first point
\r
1136 DL_Xpos1 DW ? ; X pos of first point
\r
1141 DRAW_LINE PROC FAR
\r
1143 ;PUSHx BP, SI, DI ; Preserve Important Registers
\r
1147 MOV BP, SP ; Set up Stack Frame
\r
1148 CLD ; Direction Flag = Forward
\r
1150 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
1151 MOV CH, [BP].DL_ColorF ; Save Line Color in CH
\r
1155 MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2?
\r
1156 MOV DI, [BP].DL_Xpos2 ; DX = X2
\r
1157 CMP SI, DI ; Is X1 < X2
\r
1158 JE @DL_VLINE ; If X1=X2, Draw Vertical Line
\r
1159 JL @DL_NOSWAP1 ; If X1 < X2, don't swap
\r
1161 XCHG SI, DI ; X2 IS > X1, SO SWAP THEM
\r
1165 ; SI = X1, DI = X2
\r
1167 MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2?
\r
1168 CMP AX, [BP].DL_Ypos2 ; Y1 = Y2?
\r
1169 JE @DL_HORZ ; If so, Draw a Horizontal Line
\r
1171 JMP @DL_BREZHAM ; Diagonal line... go do it...
\r
1173 ; This Code draws a Horizontal Line in Mode X where:
\r
1174 ; SI = X1, DI = X2, and AX = Y1/Y2
\r
1178 MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width
\r
1179 MOV DX, AX ; CX = Line offset into Page
\r
1181 MOV AX, SI ; Get Left edge, Save X1
\r
1182 AND SI, PLANE_BITS ; Mask out Row #
\r
1183 MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1184 MOV CX, DI ; Get Right edge, Save X2
\r
1185 AND DI, PLANE_BITS ; Mask out Row #
\r
1186 MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte
\r
1188 SHR AX, 1 ; Get X1 Byte # (=X1/4)
\r
1189 SHR CX, 1 ; Get X2 Byte # (=X2/4)
\r
1190 SHR AX, 1 ; Get X1 Byte # (=X1/4)
\r
1191 SHR CX, 1 ; Get X2 Byte # (=X2/4)
\r
1193 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1194 ADD DI, DX ; Point to Start of Line
\r
1195 ADD DI, AX ; Point to Pixel X1
\r
1197 SUB CX, AX ; CX = # Of Bands (-1) to set
\r
1198 JNZ @DL_LONGLN ; jump if longer than one segment
\r
1200 AND BL, BH ; otherwise, merge clip masks
\r
1204 OUT_8 SC_Data, BL ; Set the Left Clip Mask
\r
1206 MOV AL, [BP].DL_ColorF ; Get Line Color
\r
1207 MOV BL, AL ; BL = Copy of Line Color
\r
1208 STOSB ; Set Left (1-4) Pixels
\r
1210 JCXZ @DL_EXIT ; Done if only one Line Segment
\r
1212 DEC CX ; CX = # of Middle Segments
\r
1213 JZ @DL_XRSEG ; If no middle segments....
\r
1215 ; Draw Middle Segments
\r
1217 OUT_8 DX, ALL_PLANES ; Write to ALL Planes
\r
1219 MOV AL, BL ; Get Color from BL
\r
1220 REP STOSB ; Draw Middle (4 Pixel) Segments
\r
1223 OUT_8 DX, BH ; Select Planes for Right Clip Mask
\r
1224 MOV AL, BL ; Get Color Value
\r
1225 STOSB ; Draw Right (1-4) Pixels
\r
1227 JMP s @DL_EXIT ; We Are Done...
\r
1230 ; This Code Draws A Vertical Line. On entry:
\r
1231 ; CH = Line Color, SI & DI = X1
\r
1235 MOV AX, [BP].DL_Ypos1 ; AX = Y1
\r
1236 MOV SI, [BP].DL_Ypos2 ; SI = Y2
\r
1237 CMP AX, SI ; Is Y1 < Y2?
\r
1238 JLE @DL_NOSWAP2 ; if so, Don't Swap them
\r
1240 XCHG AX, SI ; Ok, NOW Y1 < Y2
\r
1244 SUB SI, AX ; SI = Line Height (Y2-Y1+1)
\r
1247 ; AX = Y1, DI = X1, Get offset into Page into AX
\r
1249 MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width
\r
1250 MOV DX, DI ; Copy Xpos into DX
\r
1251 SHR DI, 1 ; DI = Xpos/4
\r
1252 SHR DI, 1 ; DI = Xpos/4
\r
1253 ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1
\r
1255 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1256 ADD DI, AX ; Point to Pixel X1, Y1
\r
1260 MOV CL, DL ; CL = Save X1
\r
1261 AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #)
\r
1262 MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1
\r
1263 SHL AH, CL ; Change to Correct Plane #
\r
1264 OUT_16 SC_Index, AX ; Select Plane
\r
1266 MOV AL, CH ; Get Saved Color
\r
1267 MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By
\r
1270 MOV ES:[DI], AL ; Draw Single Pixel
\r
1271 ADD DI, BX ; Point to Next Line
\r
1272 LOOPjz SI, @DL_EXIT ; Lines--, Exit if done
\r
1274 MOV ES:[DI], AL ; Draw Single Pixel
\r
1275 ADD DI, BX ; Point to Next Line
\r
1276 LOOPx SI, @DL_VLoop ; Lines--, Loop until Done
\r
1280 JMP @DL_EXIT2 ; Done!
\r
1282 ; This code Draws a diagonal line in Mode X
\r
1285 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1287 MOV AX, [BP].DL_Ypos1 ; get Y1 value
\r
1288 MOV BX, [BP].DL_Ypos2 ; get Y2 value
\r
1289 MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos
\r
1291 CMP BX, AX ; Y2-Y1 is?
\r
1292 JNC @DL_DeltaYOK ; if Y2>=Y1 then goto...
\r
1294 XCHG BX, AX ; Swap em...
\r
1295 MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos
\r
1298 MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1
\r
1300 ADD DI, AX ; DI -> Start of Line Y1 on Page
\r
1301 MOV AX, CX ; AX = Xpos (X1)
\r
1302 SHR AX, 1 ; /4 = Byte Offset into Line
\r
1303 SHR AX, 1 ; /4 = Byte Offset into Line
\r
1304 ADD DI, AX ; DI = Starting pos (X1,Y1)
\r
1306 MOV AL, 11h ; Staring Mask
\r
1307 AND CL, PLANE_BITS ; Get Plane #
\r
1308 SHL AL, CL ; and shift into place
\r
1309 MOV AH, [BP].DL_ColorF ; Color in Hi Bytes
\r
1311 PUSH AX ; Save Mask,Color...
\r
1313 MOV AH, AL ; Plane # in AH
\r
1314 MOV AL, MAP_MASK ; Select Plane Register
\r
1315 OUT_16 SC_Index, AX ; Select initial plane
\r
1317 MOV AX, [BP].DL_Xpos1 ; get X1 value
\r
1318 MOV BX, [BP].DL_Ypos1 ; get Y1 value
\r
1319 MOV CX, [BP].DL_Xpos2 ; get X2 value
\r
1320 MOV DX, [BP].DL_Ypos2 ; get Y2 value
\r
1322 MOV BP, SCREEN_WIDTH ; Use BP for Line width to
\r
1323 ; to avoid extra memory access
\r
1325 SUB DX, BX ; figure Delta_Y
\r
1326 JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1
\r
1328 ADD BX, DX ; put Y2 into Y1
\r
1329 NEG DX ; abs(Delta_Y)
\r
1330 XCHG AX, CX ; and exchange X1 and X2
\r
1333 MOV BX, 08000H ; seed for fraction accumulator
\r
1335 SUB CX, AX ; figure Delta_X
\r
1336 JC @DL_DrawLeft ; if negative, go left
\r
1338 JMP @DL_DrawRight ; Draw Line that slopes right
\r
1342 NEG CX ; abs(Delta_X)
\r
1344 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1345 JB @DL_SteepLeft ; yes, so go do steep line
\r
1346 ; (Delta_Y iterations)
\r
1348 ; Draw a Shallow line to the left in Mode X
\r
1351 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1352 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1353 SBB DX, 0 ; include carry
\r
1354 DIV CX ; divide by Delta_X
\r
1356 MOV SI, BX ; SI = Accumulator
\r
1357 MOV BX, AX ; BX = Add fraction
\r
1358 POP AX ; Get Color, Bit mask
\r
1359 MOV DX, SC_Data ; Sequence controller data register
\r
1360 INC CX ; Inc Delta_X so we can unroll loop
\r
1362 ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...
\r
1365 MOV ES:[DI], AH ; set first pixel, plane data set up
\r
1366 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1368 ADD SI, BX ; add numerator to accumulator
\r
1369 JNC @DL_SLLL2nc ; move down on carry
\r
1371 ADD DI, BP ; Move Down one line...
\r
1374 DEC DI ; Left one addr
\r
1375 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1376 CMP AL, 87h ; wrap?, if AL <88 then Carry set
\r
1377 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1378 OUT DX, AL ; Set up New Bit Plane mask
\r
1380 MOV ES:[DI], AH ; set pixel
\r
1381 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1383 ADD SI, BX ; add numerator to accumulator,
\r
1384 JNC @DL_SLLL3nc ; move down on carry
\r
1386 ADD DI, BP ; Move Down one line...
\r
1388 @DL_SLLL3nc: ; Now move left a pixel...
\r
1389 DEC DI ; Left one addr
\r
1390 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1391 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1392 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1393 OUT DX, AL ; Set up New Bit Plane mask
\r
1394 JMP s @DL_SLLLoop ; loop until done
\r
1397 JMP @DL_EXIT2 ; and exit
\r
1399 ; Draw a steep line to the left in Mode X
\r
1402 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1403 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1404 DIV CX ; divide by Delta_Y
\r
1406 MOV SI, BX ; SI = Accumulator
\r
1407 MOV BX, AX ; BX = Add Fraction
\r
1408 POP AX ; Get Color, Bit mask
\r
1409 MOV DX, SC_Data ; Sequence controller data register
\r
1410 INC CX ; Inc Delta_Y so we can unroll loop
\r
1412 ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
\r
1416 MOV ES:[DI], AH ; set first pixel
\r
1417 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1419 ADD SI, BX ; add numerator to accumulator
\r
1420 JNC @DL_STLnc2 ; No carry, just move down!
\r
1422 DEC DI ; Move Left one addr
\r
1423 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1424 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1425 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1426 OUT DX, AL ; Set up New Bit Plane mask
\r
1429 ADD DI, BP ; advance to next line.
\r
1431 MOV ES:[DI], AH ; set pixel
\r
1432 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1434 ADD SI, BX ; add numerator to accumulator
\r
1435 JNC @DL_STLnc3 ; No carry, just move down!
\r
1437 DEC DI ; Move Left one addr
\r
1438 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1439 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1440 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1441 OUT DX, AL ; Set up New Bit Plane mask
\r
1444 ADD DI, BP ; advance to next line.
\r
1445 JMP s @DL_STLLoop ; Loop until done
\r
1448 JMP @DL_EXIT2 ; and exit
\r
1450 ; Draw a line that goes to the Right...
\r
1453 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1454 JB @DL_SteepRight ; yes, so go do steep line
\r
1455 ; (Delta_Y iterations)
\r
1457 ; Draw a Shallow line to the Right in Mode X
\r
1460 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1461 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1462 SBB DX, 0 ; include carry
\r
1463 DIV CX ; divide by Delta_X
\r
1465 MOV SI, BX ; SI = Accumulator
\r
1466 MOV BX, AX ; BX = Add Fraction
\r
1467 POP AX ; Get Color, Bit mask
\r
1468 MOV DX, SC_Data ; Sequence controller data register
\r
1469 INC CX ; Inc Delta_X so we can unroll loop
\r
1471 ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...
\r
1474 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1475 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1477 ADD SI, BX ; add numerator to accumulator
\r
1478 JNC @DL_SLR2nc ; don't move down if carry not set
\r
1480 ADD DI, BP ; Move Down one line...
\r
1482 @DL_SLR2nc: ; Now move right a pixel...
\r
1483 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1484 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1485 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1486 OUT DX, AL ; Set up New Bit Plane mask
\r
1488 MOV ES:[DI], AH ; set pixel
\r
1489 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1491 ADD SI, BX ; add numerator to accumulator
\r
1492 JNC @DL_SLR3nc ; don't move down if carry not set
\r
1494 ADD DI, BP ; Move Down one line...
\r
1497 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1498 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1499 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1500 OUT DX, AL ; Set up New Bit Plane mask
\r
1501 JMP s @DL_SLRLoop ; loop till done
\r
1504 JMP @DL_EXIT2 ; and exit
\r
1506 ; Draw a Steep line to the Right in Mode X
\r
1509 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1510 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1511 DIV CX ; divide by Delta_Y
\r
1513 MOV SI, BX ; SI = Accumulator
\r
1514 MOV BX, AX ; BX = Add Fraction
\r
1515 POP AX ; Get Color, Bit mask
\r
1516 MOV DX, SC_Data ; Sequence controller data register
\r
1517 INC CX ; Inc Delta_Y so we can unroll loop
\r
1519 ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
\r
1522 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1523 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1525 ADD SI, BX ; add numerator to accumulator
\r
1526 JNC @STRnc2 ; if no carry then just go down...
\r
1528 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1529 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1530 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1531 OUT DX, AL ; Set up New Bit Plane mask
\r
1534 ADD DI, BP ; advance to next line.
\r
1536 MOV ES:[DI], AH ; set pixel
\r
1537 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1539 ADD SI, BX ; add numerator to accumulator
\r
1540 JNC @STRnc3 ; if no carry then just go down...
\r
1542 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1543 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1544 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1545 OUT DX, AL ; Set up New Bit Plane mask
\r
1548 ADD DI, BP ; advance to next line.
\r
1549 JMP s @STRLoop ; loop till done
\r
1552 ;POPx DI, SI, BP ; Restore Saved Registers
\r
1556 RET 10 ; Exit and Clean up Stack
\r
1561 ; ===== DAC COLOR REGISTER ROUTINES =====
\r
1563 ;=================================================
\r
1564 ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)
\r
1565 ;=================================================
\r
1567 ; Sets a single (RGB) Vga Palette Register
\r
1569 ; ENTRY: Register = The DAC # to modify (0-255)
\r
1570 ; Red = The new Red Intensity (0-63)
\r
1571 ; Green = The new Green Intensity (0-63)
\r
1572 ; Blue = The new Blue Intensity (0-63)
\r
1574 ; EXIT: No meaningful values returned
\r
1580 SDR_Blue DB ?,? ; Blue Data Value
\r
1581 SDR_Green DB ?,? ; Green Data Value
\r
1582 SDR_Red DB ?,? ; Red Data Value
\r
1583 SDR_Register DB ?,? ; Palette Register #
\r
1586 PUBLIC SET_DAC_REGISTER
\r
1588 SET_DAC_REGISTER PROC FAR
\r
1591 MOV BP, SP ; Set up Stack Frame
\r
1593 ; Select which DAC Register to modify
\r
1595 OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register
\r
1597 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1598 OUT_8 DX, [BP].SDR_Red ; Set Red Intensity
\r
1599 OUT_8 DX, [BP].SDR_Green ; Set Green Intensity
\r
1600 OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity
\r
1602 POP BP ; Restore Registers
\r
1603 RET 8 ; Exit & Clean Up Stack
\r
1605 SET_DAC_REGISTER ENDP
\r
1607 ;====================================================
\r
1608 ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)
\r
1609 ;====================================================
\r
1611 ; Reads the RGB Values of a single Vga Palette Register
\r
1613 ; ENTRY: Register = The DAC # to read (0-255)
\r
1614 ; Red = Offset to Red Variable in DS
\r
1615 ; Green = Offset to Green Variable in DS
\r
1616 ; Blue = Offset to Blue Variable in DS
\r
1618 ; EXIT: The values of the integer variables Red,
\r
1619 ; Green, and Blue are set to the values
\r
1620 ; taken from the specified DAC register.
\r
1626 GDR_Blue DW ? ; Addr of Blue Data Value in DS
\r
1627 GDR_Green DW ? ; Addr of Green Data Value in DS
\r
1628 GDR_Red DW ? ; Addr of Red Data Value in DS
\r
1629 GDR_Register DB ?,? ; Palette Register #
\r
1632 PUBLIC GET_DAC_REGISTER
\r
1634 GET_DAC_REGISTER PROC FAR
\r
1637 MOV BP, SP ; Set up Stack Frame
\r
1639 ; Select which DAC Register to read in
\r
1641 OUT_8 DAC_READ_ADDR, [BP].GDR_Register
\r
1643 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1644 mov ax,0 ; Clear AX
\r
1646 IN AL, DX ; Read Red Value
\r
1647 MOV BX, [BP].GDR_Red ; Get Address of Red%
\r
1648 MOV [BX], AX ; *Red% = AX
\r
1650 IN AL, DX ; Read Green Value
\r
1651 MOV BX, [BP].GDR_Green ; Get Address of Green%
\r
1652 MOV [BX], AX ; *Green% = AX
\r
1654 IN AL, DX ; Read Blue Value
\r
1655 MOV BX, [BP].GDR_Blue ; Get Address of Blue%
\r
1656 MOV [BX], AX ; *Blue% = AX
\r
1658 POP BP ; Restore Registers
\r
1659 RET 8 ; Exit & Clean Up Stack
\r
1661 GET_DAC_REGISTER ENDP
\r
1664 ;===========================================================
\r
1665 ;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%)
\r
1666 ;===========================================================
\r
1668 ; Sets a Block of Vga Palette Registers
\r
1670 ; ENTRY: PalData = Far Pointer to Block of palette data
\r
1671 ; StartReg = First Register # in range to set (0-255)
\r
1672 ; EndReg = Last Register # in Range to set (0-255)
\r
1673 ; Sync = Wait for Vertical Retrace Flag (Boolean)
\r
1675 ; EXIT: No meaningful values returned
\r
1677 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1678 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1682 DW ?x1 ; BP, DS, SI
\r
1683 DW ?x1 ; BP, DS, SI
\r
1684 DW ?x1 ; BP, DS, SI
\r
1686 LDR_Sync DW ? ; Vertical Sync Flag
\r
1687 LDR_EndReg DB ?,? ; Last Register #
\r
1688 LDR_StartReg DB ?,? ; First Register #
\r
1689 LDR_PalData DD ? ; Far Ptr to Palette Data
\r
1692 PUBLIC LOAD_DAC_REGISTERS
\r
1694 LOAD_DAC_REGISTERS PROC FAR
\r
1696 ;PUSHx BP, DS, SI ; Save Registers
\r
1700 mov BP, SP ; Set up Stack Frame
\r
1702 mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag
\r
1703 or AX, AX ; is Sync Flag = 0?
\r
1704 jz @LDR_Load ; if so, skip call
\r
1706 call f SYNC_DISPLAY ; wait for vsync
\r
1708 ; Determine register #'s, size to copy, etc
\r
1712 lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data
\r
1713 mov DX, DAC_WRITE_ADDR ; DAC register # selector
\r
1715 mov ax,0, BX ; Clear for byte loads
\r
1716 mov AL, [BP].LDR_StartReg ; Get Start Register
\r
1717 mov BL, [BP].LDR_EndReg ; Get End Register
\r
1719 sub BX, AX ; BX = # of DAC registers -1
\r
1720 inc BX ; BX = # of DAC registers
\r
1721 mov CX, BX ; CX = # of DAC registers
\r
1722 add CX, BX ; CX = " " * 2
\r
1723 add CX, BX ; CX = " " * 3
\r
1724 cld ; Block OUTs forward
\r
1725 out DX, AL ; set up correct register #
\r
1727 ; Load a block of DAC Registers
\r
1729 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1731 ;rep outsb ; block set DAC registers
\r
1733 ;POPx SI, DS, BP ; Restore Registers
\r
1737 ret 10 ; Exit & Clean Up Stack
\r
1739 LOAD_DAC_REGISTERS ENDP
\r
1742 ;====================================================
\r
1743 ;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%)
\r
1744 ;====================================================
\r
1746 ; Reads a Block of Vga Palette Registers
\r
1748 ; ENTRY: PalData = Far Pointer to block to store palette data
\r
1749 ; StartReg = First Register # in range to read (0-255)
\r
1750 ; EndReg = Last Register # in Range to read (0-255)
\r
1752 ; EXIT: No meaningful values returned
\r
1754 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1755 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1759 DW ?x1 ; BP, ES, DI
\r
1760 DW ?x1 ; BP, ES, DI
\r
1761 DW ?x1 ; BP, ES, DI
\r
1763 RDR_EndReg DB ?,? ; Last Register #
\r
1764 RDR_StartReg DB ?,? ; First Register #
\r
1765 RDR_PalData DD ? ; Far Ptr to Palette Data
\r
1768 PUBLIC READ_DAC_REGISTERS
\r
1770 READ_DAC_REGISTERS PROC FAR
\r
1772 ;PUSHx BP, ES, DI ; Save Registers
\r
1776 mov BP, SP ; Set up Stack Frame
\r
1778 ; Determine register #'s, size to copy, etc
\r
1780 les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer
\r
1781 mov DX, DAC_READ_ADDR ; DAC register # selector
\r
1783 mov ax,0, BX ; Clear for byte loads
\r
1784 mov AL, [BP].RDR_StartReg ; Get Start Register
\r
1785 mov BL, [BP].RDR_EndReg ; Get End Register
\r
1787 sub BX, AX ; BX = # of DAC registers -1
\r
1788 inc BX ; BX = # of DAC registers
\r
1789 mov CX, BX ; CX = # of DAC registers
\r
1790 add CX, BX ; CX = " " * 2
\r
1791 add CX, BX ; CX = " " * 3
\r
1792 cld ; Block INs forward
\r
1794 ; Read a block of DAC Registers
\r
1796 out DX, AL ; set up correct register #
\r
1797 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1799 ;rep insb ; block read DAC registers
\r
1801 ;POPx DI, ES, BP ; Restore Registers
\r
1805 ret 8 ; Exit & Clean Up Stack
\r
1807 READ_DAC_REGISTERS ENDP
\r
1810 ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====
\r
1812 ;=========================
\r
1813 ;SET_ACTIVE_PAGE (PageNo%)
\r
1814 ;=========================
\r
1816 ; Sets the active display Page to be used for future drawing
\r
1818 ; ENTRY: PageNo = Display Page to make active
\r
1819 ; (values: 0 to Number of Pages - 1)
\r
1821 ; EXIT: No meaningful values returned
\r
1827 SAP_Page DW ? ; Page # for Drawing
\r
1830 PUBLIC SET_ACTIVE_PAGE
\r
1832 SET_ACTIVE_PAGE PROC FAR
\r
1834 PUSH BP ; Preserve Registers
\r
1835 MOV BP, SP ; Set up Stack Frame
\r
1837 MOV BX, [BP].SAP_Page ; Get Desired Page #
\r
1838 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1839 JAE @SAP_Exit ; IF Not, Do Nothing
\r
1841 MOV ACTIVE_PAGE, BX ; Set Active Page #
\r
1843 SHL BX, 1 ; Scale Page # to Word
\r
1844 MOV AX, PAGE_ADDR[BX] ; Get offset to Page
\r
1846 MOV CURRENT_PAGE, AX ; And set for future LES's
\r
1849 POP BP ; Restore Registers
\r
1850 RET 2 ; Exit and Clean up Stack
\r
1852 SET_ACTIVE_PAGE ENDP
\r
1859 ; Returns the Video Page # currently used for Drawing
\r
1861 ; ENTRY: No Parameters are passed
\r
1863 ; EXIT: AX = Current Video Page used for Drawing
\r
1866 PUBLIC GET_ACTIVE_PAGE
\r
1868 GET_ACTIVE_PAGE PROC FAR
\r
1870 MOV AX, ACTIVE_PAGE ; Get Active Page #
\r
1871 RET ; Exit and Clean up Stack
\r
1873 GET_ACTIVE_PAGE ENDP
\r
1876 ;===============================
\r
1877 ;SET_DISPLAY_PAGE (DisplayPage%)
\r
1878 ;===============================
\r
1880 ; Sets the currently visible display page.
\r
1881 ; When called this routine syncronizes the display
\r
1882 ; to the vertical blank.
\r
1884 ; ENTRY: PageNo = Display Page to show on the screen
\r
1885 ; (values: 0 to Number of Pages - 1)
\r
1887 ; EXIT: No meaningful values returned
\r
1893 SDP_Page DW ? ; Page # to Display...
\r
1896 PUBLIC SET_DISPLAY_PAGE
\r
1898 SET_DISPLAY_PAGE PROC FAR
\r
1900 PUSH BP ; Preserve Registers
\r
1901 MOV BP, SP ; Set up Stack Frame
\r
1903 MOV BX, [BP].SDP_Page ; Get Desired Page #
\r
1904 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1905 JAE @SDP_Exit ; IF Not, Do Nothing
\r
1907 MOV DISPLAY_PAGE, BX ; Set Display Page #
\r
1909 SHL BX, 1 ; Scale Page # to Word
\r
1910 MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page
\r
1911 ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling
\r
1913 ; Wait if we are currently in a Vertical Retrace
\r
1915 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1918 IN AL, DX ; Get VGA status
\r
1919 AND AL, VERT_RETRACE ; In Display mode yet?
\r
1920 JNZ @DP_WAIT0 ; If Not, wait for it
\r
1922 ; Set the Start Display Address to the new page
\r
1924 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
1926 MOV AL, START_DISP_LO ; Display Start Low Register
\r
1927 MOV AH, CL ; Low 8 Bits of Start Addr
\r
1928 OUT DX, AX ; Set Display Addr Low
\r
1930 MOV AL, START_DISP_HI ; Display Start High Register
\r
1931 MOV AH, CH ; High 8 Bits of Start Addr
\r
1932 OUT DX, AX ; Set Display Addr High
\r
1934 ; Wait for a Vertical Retrace to smooth out things
\r
1936 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1939 IN AL, DX ; Get VGA status
\r
1940 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
1941 JZ @DP_WAIT1 ; If Not, wait for it
\r
1943 ; Now Set Display Starting Address
\r
1947 POP BP ; Restore Registers
\r
1948 RET 2 ; Exit and Clean up Stack
\r
1950 SET_DISPLAY_PAGE ENDP
\r
1953 ;=================
\r
1954 ;GET_DISPLAY_PAGE%
\r
1955 ;=================
\r
1957 ; Returns the Video Page # currently displayed
\r
1959 ; ENTRY: No Parameters are passed
\r
1961 ; EXIT: AX = Current Video Page being displayed
\r
1964 PUBLIC GET_DISPLAY_PAGE
\r
1966 GET_DISPLAY_PAGE PROC FAR
\r
1968 MOV AX, DISPLAY_PAGE ; Get Display Page #
\r
1969 RET ; Exit & Clean Up Stack
\r
1971 GET_DISPLAY_PAGE ENDP
\r
1974 ;=======================================
\r
1975 ;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)
\r
1976 ;=======================================
\r
1978 ; Since a Logical Screen can be larger than the Physical
\r
1979 ; Screen, Scrolling is possible. This routine sets the
\r
1980 ; Upper Left Corner of the Screen to the specified Pixel.
\r
1981 ; Also Sets the Display page to simplify combined page
\r
1982 ; flipping and scrolling. When called this routine
\r
1983 ; syncronizes the display to the vertical blank.
\r
1985 ; ENTRY: DisplayPage = Display Page to show on the screen
\r
1986 ; Xpos = # of pixels to shift screen right
\r
1987 ; Ypos = # of lines to shift screen down
\r
1989 ; EXIT: No meaningful values returned
\r
1995 SW_Ypos DW ? ; Y pos of UL Screen Corner
\r
1996 SW_Xpos DW ? ; X pos of UL Screen Corner
\r
1997 SW_Page DW ? ; (new) Display Page
\r
2002 SET_WINDOW PROC FAR
\r
2004 PUSH BP ; Preserve Registers
\r
2005 MOV BP, SP ; Set up Stack Frame
\r
2007 ; Check if our Scroll Offsets are Valid
\r
2009 MOV BX, [BP].SW_Page ; Get Desired Page #
\r
2010 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
2011 JAE @SW_Exit ; IF Not, Do Nothing
\r
2013 MOV AX, [BP].SW_Ypos ; Get Desired Y Offset
\r
2014 CMP AX, MAX_YOFFSET ; Is it Within Limits?
\r
2015 JA @SW_Exit ; if not, exit
\r
2017 MOV CX, [BP].SW_Xpos ; Get Desired X Offset
\r
2018 CMP CX, MAX_XOFFSET ; Is it Within Limits?
\r
2019 JA @SW_Exit ; if not, exit
\r
2021 ; Compute proper Display start address to use
\r
2023 MUL SCREEN_WIDTH ; AX = YOffset * Line Width
\r
2024 SHR CX, 1 ; CX / 4 = Bytes into Line
\r
2025 SHR CX, 1 ; CX / 4 = Bytes into Line
\r
2026 ADD AX, CX ; AX = Offset of Upper Left Pixel
\r
2028 MOV CURRENT_MOFFSET, AX ; Save Offset Info
\r
2030 MOV DISPLAY_PAGE, BX ; Set Current Page #
\r
2031 SHL BX, 1 ; Scale Page # to Word
\r
2032 ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page
\r
2033 MOV BX, AX ; BX = Desired Display Start
\r
2035 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2037 ; Wait if we are currently in a Vertical Retrace
\r
2040 IN AL, DX ; Get VGA status
\r
2041 AND AL, VERT_RETRACE ; In Display mode yet?
\r
2042 JNZ @SW_WAIT0 ; If Not, wait for it
\r
2044 ; Set the Start Display Address to the new window
\r
2046 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
2047 MOV AL, START_DISP_LO ; Display Start Low Register
\r
2048 MOV AH, BL ; Low 8 Bits of Start Addr
\r
2049 OUT DX, AX ; Set Display Addr Low
\r
2051 MOV AL, START_DISP_HI ; Display Start High Register
\r
2052 MOV AH, BH ; High 8 Bits of Start Addr
\r
2053 OUT DX, AX ; Set Display Addr High
\r
2055 ; Wait for a Vertical Retrace to smooth out things
\r
2057 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2060 IN AL, DX ; Get VGA status
\r
2061 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
2062 JZ @SW_WAIT1 ; If Not, wait for it
\r
2064 ; Now Set the Horizontal Pixel Pan values
\r
2066 OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register
\r
2068 MOV AX, [BP].SW_Xpos ; Get Desired X Offset
\r
2069 AND AL, 03 ; Get # of Pixels to Pan (0-3)
\r
2070 SHL AL, 1 ; Shift for 256 Color Mode
\r
2071 OUT DX, AL ; Fine tune the display!
\r
2074 POP BP ; Restore Saved Registers
\r
2075 RET 6 ; Exit and Clean up Stack
\r
2084 ; Returns the X coordinate of the Pixel currently display
\r
2085 ; in the upper left corner of the display
\r
2087 ; ENTRY: No Parameters are passed
\r
2089 ; EXIT: AX = Current Horizontal Scroll Offset
\r
2092 PUBLIC GET_X_OFFSET
\r
2094 GET_X_OFFSET PROC FAR
\r
2096 MOV AX, CURRENT_XOFFSET ; Get current horz offset
\r
2097 RET ; Exit & Clean Up Stack
\r
2106 ; Returns the Y coordinate of the Pixel currently display
\r
2107 ; in the upper left corner of the display
\r
2109 ; ENTRY: No Parameters are passed
\r
2111 ; EXIT: AX = Current Vertical Scroll Offset
\r
2114 PUBLIC GET_Y_OFFSET
\r
2116 GET_Y_OFFSET PROC FAR
\r
2118 MOV AX, CURRENT_YOFFSET ; Get current vertical offset
\r
2119 RET ; Exit & Clean Up Stack
\r
2128 ; Pauses the computer until the next Vertical Retrace starts
\r
2130 ; ENTRY: No Parameters are passed
\r
2132 ; EXIT: No meaningful values returned
\r
2135 PUBLIC SYNC_DISPLAY
\r
2137 SYNC_DISPLAY PROC FAR
\r
2139 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2141 ; Wait for any current retrace to end
\r
2144 IN AL, DX ; Get VGA status
\r
2145 AND AL, VERT_RETRACE ; In Display mode yet?
\r
2146 JNZ @SD_WAIT0 ; If Not, wait for it
\r
2148 ; Wait for the start of the next vertical retrace
\r
2151 IN AL, DX ; Get VGA status
\r
2152 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
2153 JZ @SD_WAIT1 ; If Not, wait for it
\r
2155 RET ; Exit & Clean Up Stack
\r
2160 ; ===== TEXT DISPLAY ROUTINES =====
\r
2162 ;==================================================
\r
2163 ;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2164 ;==================================================
\r
2166 ; Draws an ASCII Text Character using the currently selected
\r
2167 ; 8x8 font on the active display page. It would be a simple
\r
2168 ; exercise to make this routine process variable height fonts.
\r
2170 ; ENTRY: CharNum = ASCII character # to draw
\r
2171 ; Xpos = X position to draw Character at
\r
2172 ; Ypos = Y position of to draw Character at
\r
2173 ; ColorF = Color to draw text character in
\r
2174 ; ColorB = Color to set background to
\r
2176 ; EXIT: No meaningful values returned
\r
2180 GPC_Width DW ? ; Screen Width-1
\r
2181 GPC_Lines DB ?,? ; Scan lines to Decode
\r
2182 GPC_T_SETS DW ? ; Saved Charset Segment
\r
2183 GPC_T_SETO DW ? ; Saved Charset Offset
\r
2184 DW ?x1 ; DI, SI, DS, BP
\r
2185 DW ?x1 ; DS, DI, SI, BP
\r
2186 DW ?x1 ; DS, DI, SI, BP
\r
2187 DW ?x1 ; DS, DI, SI, BP
\r
2189 GPC_ColorB DB ?,? ; Background Color
\r
2190 GPC_ColorF DB ?,? ; Text Color
\r
2191 GPC_Ypos DW ? ; Y Position to Print at
\r
2192 GPC_Xpos DW ? ; X position to Print at
\r
2193 GPC_Char DB ?,? ; Character to Print
\r
2200 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2205 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2206 MOV BP, SP ; Set up Stack Frame
\r
2208 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2210 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2211 MOV BX, AX ; BX = Screen Width
\r
2212 DEC BX ; = Screen Width-1
\r
2213 MOV [BP].GPC_Width, BX ; Save for later use
\r
2215 MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width
\r
2216 ADD DI, AX ; DI -> Start of Line Ypos
\r
2218 MOV AX, [BP].GPC_Xpos ; Get Xpos of Character
\r
2219 MOV CX, AX ; Save Copy of Xpos
\r
2220 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2221 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2222 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2224 ;Get Source ADDR of Character Bit Map & Save
\r
2226 MOV AL, [BP].GPC_Char ; Get Character #
\r
2227 TEST AL, 080h ; Is Hi Bit Set?
\r
2228 JZ @GPC_LowChar ; Nope, use low char set ptr
\r
2230 AND AL, 07Fh ; Mask Out Hi Bit
\r
2231 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2232 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2233 JMP s @GPC_Set_Char ; Go Setup Character Ptr
\r
2237 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2238 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2241 MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack
\r
2243 MOV AH, 0 ; Valid #'s are 0..127
\r
2244 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2245 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2246 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2247 ADD BX, AX ; BX = Offset of Selected char
\r
2248 MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack
\r
2250 AND CX, PLANE_BITS ; Get Plane #
\r
2251 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2252 SHL CH, CL ; And shift into position
\r
2253 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2255 MOV AL, 04 ; 4-Plane # = # of initial
\r
2256 SUB AL, CL ; shifts to align bit mask
\r
2257 MOV CL, AL ; Shift Count for SHL
\r
2259 ;Get segment of character map
\r
2261 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2262 INC DX ; DX -> SC_Data
\r
2264 MOV AL, 08 ; 8 Lines to Process
\r
2265 MOV [BP].GPC_Lines, AL ; Save on Stack
\r
2267 MOV DS, [BP].GPC_T_SETS ; Point to character set
\r
2269 @GPC_DECODE_CHAR_BYTE:
\r
2271 MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String
\r
2273 MOV BH, [SI] ; Get Bit Map
\r
2274 INC SI ; Point to Next Line
\r
2275 MOV [BP].GPC_T_SETO, SI ; And save new Pointer...
\r
2277 mov ax,0 ; Clear AX
\r
2279 ;mov bl,0 ; Clear BL
\r
2281 ROL BX, CL ; BL holds left edge bits
\r
2282 MOV SI, BX ; Use as Table Index
\r
2283 AND SI, CHAR_BITS ; Get Low Bits
\r
2284 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2285 JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2287 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2288 OUT DX, AL ; Set up Screen Mask
\r
2289 MOV ES:[DI], AH ; Write Foreground color
\r
2291 @GPC_NO_LEFT1BITS:
\r
2292 XOR AL, CH ; Invert mask for Background
\r
2293 JZ @GPC_NO_LEFT0BITS ; Hey, no need for this
\r
2295 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2296 OUT DX, AL ; Set up Screen Mask
\r
2297 MOV ES:[DI], AH ; Write Foreground color
\r
2299 ;Now Do Middle/Last Band
\r
2301 @GPC_NO_LEFT0BITS:
\r
2302 INC DI ; Point to next Byte
\r
2303 ROL BX, 1 ; Shift 4 bits
\r
2304 ROL BX, 1 ; Shift 4 bits
\r
2305 ROL BX, 1 ; Shift 4 bits
\r
2306 ROL BX, 1 ; Shift 4 bits
\r
2308 MOV SI, BX ; Make Lookup Pointer
\r
2309 AND SI, CHAR_BITS ; Get Low Bits
\r
2310 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2311 JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2313 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2314 OUT DX, AL ; Set up Screen Mask
\r
2315 MOV ES:[DI], AH ; Write Foreground color
\r
2317 @GPC_NO_MIDDLE1BITS:
\r
2318 XOR AL, ALL_PLANES ; Invert mask for Background
\r
2319 JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this
\r
2321 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2322 OUT DX, AL ; Set up Screen Mask
\r
2323 MOV ES:[DI], AH ; Write Foreground color
\r
2325 @GPC_NO_MIDDLE0BITS:
\r
2326 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2327 CMP CL, 4 ; Aligned by 4?
\r
2328 JZ @GPC_NEXT_LINE ; If so, Exit now..
\r
2330 INC DI ; Point to next Byte
\r
2331 ROL BX, 1 ; Shift 4 bits
\r
2332 ROL BX, 1 ; Shift 4 bits
\r
2333 ROL BX, 1 ; Shift 4 bits
\r
2334 ROL BX, 1 ; Shift 4 bits
\r
2336 MOV SI, BX ; Make Lookup Pointer
\r
2337 AND SI, CHAR_BITS ; Get Low Bits
\r
2338 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2339 JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2341 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2342 OUT DX, AL ; Set up Screen Mask
\r
2343 MOV ES:[DI], AH ; Write Foreground color
\r
2345 @GPC_NO_RIGHT1BITS:
\r
2347 XOR AL, CH ; Invert mask for Background
\r
2348 JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this
\r
2350 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2351 OUT DX, AL ; Set up Screen Mask
\r
2352 MOV ES:[DI], AH ; Write Foreground color
\r
2354 @GPC_NO_RIGHT0BITS:
\r
2355 DEC DI ; Adjust for Next Line Advance
\r
2358 ADD DI, [BP].GPC_Width ; Point to Next Line
\r
2359 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2361 DEC [BP].GPC_Lines ; Count Down Lines
\r
2362 JZ @GPC_EXIT ; Ok... Done!
\r
2364 JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey!
\r
2367 ADD SP, 08 ; Deallocate stack workspace
\r
2368 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2373 RET 10 ; Exit and Clean up Stack
\r
2378 ;==========================================
\r
2379 ;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)
\r
2380 ;==========================================
\r
2382 ; Transparently draws an ASCII Text Character using the
\r
2383 ; currently selected 8x8 font on the active display page.
\r
2385 ; ENTRY: CharNum = ASCII character # to draw
\r
2386 ; Xpos = X position to draw Character at
\r
2387 ; Ypos = Y position of to draw Character at
\r
2388 ; ColorF = Color to draw text character in
\r
2390 ; EXIT: No meaningful values returned
\r
2394 TGP_Width DW ? ; Screen Width-1
\r
2395 TGP_Lines DB ?,? ; Scan lines to Decode
\r
2396 TGP_T_SETS DW ? ; Saved Charset Segment
\r
2397 TGP_T_SETO DW ? ; Saved Charset Offset
\r
2398 DW ?x1 ; DI, SI, DS, BP
\r
2399 DW ?x1 ; DS, DI, SI, BP
\r
2400 DW ?x1 ; DS, DI, SI, BP
\r
2401 DW ?x1 ; DS, DI, SI, BP
\r
2403 TGP_ColorF DB ?,? ; Text Color
\r
2404 TGP_Ypos DW ? ; Y Position to Print at
\r
2405 TGP_Xpos DW ? ; X position to Print at
\r
2406 TGP_Char DB ?,? ; Character to Print
\r
2413 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2418 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2419 MOV BP, SP ; Set up Stack Frame
\r
2421 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2423 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2424 MOV BX, AX ; BX = Screen Width
\r
2425 DEC BX ; = Screen Width-1
\r
2426 MOV [BP].TGP_Width, BX ; Save for later use
\r
2428 MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width
\r
2429 ADD DI, AX ; DI -> Start of Line Ypos
\r
2431 MOV AX, [BP].TGP_Xpos ; Get Xpos of Character
\r
2432 MOV CX, AX ; Save Copy of Xpos
\r
2433 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2434 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2435 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2437 ;Get Source ADDR of Character Bit Map & Save
\r
2439 MOV AL, [BP].TGP_Char ; Get Character #
\r
2440 TEST AL, 080h ; Is Hi Bit Set?
\r
2441 JZ @TGP_LowChar ; Nope, use low char set ptr
\r
2443 AND AL, 07Fh ; Mask Out Hi Bit
\r
2444 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2445 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2446 JMP s @TGP_Set_Char ; Go Setup Character Ptr
\r
2450 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2451 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2454 MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack
\r
2456 MOV AH, 0 ; Valid #'s are 0..127
\r
2457 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2458 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2459 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2460 ADD BX, AX ; BX = Offset of Selected char
\r
2461 MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack
\r
2463 AND CX, PLANE_BITS ; Get Plane #
\r
2464 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2465 SHL CH, CL ; And shift into position
\r
2466 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2468 MOV AL, 04 ; 4-Plane # = # of initial
\r
2469 SUB AL, CL ; shifts to align bit mask
\r
2470 MOV CL, AL ; Shift Count for SHL
\r
2472 ;Get segment of character map
\r
2474 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2475 INC DX ; DX -> SC_Data
\r
2477 MOV AL, 08 ; 8 Lines to Process
\r
2478 MOV [BP].TGP_Lines, AL ; Save on Stack
\r
2480 MOV DS, [BP].TGP_T_SETS ; Point to character set
\r
2482 @TGP_DECODE_CHAR_BYTE:
\r
2484 MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String
\r
2486 MOV BH, [SI] ; Get Bit Map
\r
2487 INC SI ; Point to Next Line
\r
2488 MOV [BP].TGP_T_SETO, SI ; And save new Pointer...
\r
2490 MOV AH, [BP].TGP_ColorF ; Get Foreground Color
\r
2492 mov bl,0 ; Clear BL
\r
2493 ROL BX, CL ; BL holds left edge bits
\r
2494 MOV SI, BX ; Use as Table Index
\r
2495 AND SI, CHAR_BITS ; Get Low Bits
\r
2496 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2497 JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2499 OUT DX, AL ; Set up Screen Mask
\r
2500 MOV ES:[DI], AH ; Write Foreground color
\r
2502 ;Now Do Middle/Last Band
\r
2504 @TGP_NO_LEFT1BITS:
\r
2506 INC DI ; Point to next Byte
\r
2507 ROL BX, 1 ; Shift 4 bits
\r
2508 ROL BX, 1 ; Shift 4 bits
\r
2509 ROL BX, 1 ; Shift 4 bits
\r
2510 ROL BX, 1 ; Shift 4 bits
\r
2512 MOV SI, BX ; Make Lookup Pointer
\r
2513 AND SI, CHAR_BITS ; Get Low Bits
\r
2514 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2515 JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2517 OUT DX, AL ; Set up Screen Mask
\r
2518 MOV ES:[DI], AH ; Write Foreground color
\r
2520 @TGP_NO_MIDDLE1BITS:
\r
2521 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2522 CMP CL, 4 ; Aligned by 4?
\r
2523 JZ @TGP_NEXT_LINE ; If so, Exit now..
\r
2525 INC DI ; Point to next Byte
\r
2526 ROL BX, 1 ; Shift 4 bits
\r
2527 ROL BX, 1 ; Shift 4 bits
\r
2528 ROL BX, 1 ; Shift 4 bits
\r
2529 ROL BX, 1 ; Shift 4 bits
\r
2531 MOV SI, BX ; Make Lookup Pointer
\r
2532 AND SI, CHAR_BITS ; Get Low Bits
\r
2533 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2534 JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2536 OUT DX, AL ; Set up Screen Mask
\r
2537 MOV ES:[DI], AH ; Write Foreground color
\r
2539 @TGP_NO_RIGHT1BITS:
\r
2541 DEC DI ; Adjust for Next Line Advance
\r
2544 ADD DI, [BP].TGP_Width ; Point to Next Line
\r
2545 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2547 DEC [BP].TGP_Lines ; Count Down Lines
\r
2548 JZ @TGP_EXIT ; Ok... Done!
\r
2550 JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey!
\r
2553 ADD SP, 08 ; Deallocate stack workspace
\r
2554 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2559 RET 8 ; Exit and Clean up Stack
\r
2564 ;===============================================================
\r
2565 ;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2566 ;===============================================================
\r
2568 ; Routine to quickly Print a null terminated ASCII string on the
\r
2569 ; active display page up to a maximum length.
\r
2571 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2572 ; MaxLen = # of characters to print if no null found
\r
2573 ; Xpos = X position to draw Text at
\r
2574 ; Ypos = Y position of to draw Text at
\r
2575 ; ColorF = Color to draw text in
\r
2576 ; ColorB = Color to set background to
\r
2578 ; EXIT: No meaningful values returned
\r
2582 DW ?x1 ; DI, SI, DS, BP
\r
2583 DW ?x1 ; DI, SI, DS, BP
\r
2584 DW ?x1 ; DS, DI, SI, BP
\r
2585 DW ?x1 ; DS, DI, SI, BP
\r
2587 PS_ColorB DW ? ; Background Color
\r
2588 PS_ColorF DW ? ; Text Color
\r
2589 PS_Ypos DW ? ; Y Position to Print at
\r
2590 PS_Xpos DW ? ; X position to Print at
\r
2591 PS_Len DW ? ; Maximum Length of string to print
\r
2592 PS_Text DW ?,? ; Far Ptr to Text String
\r
2597 PRINT_STR PROC FAR
\r
2599 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2604 MOV BP, SP ; Set up Stack Frame
\r
2608 MOV CX, [BP].PS_Len ; Get Remaining text Length
\r
2609 JCXZ @PS_Exit ; Exit when out of text
\r
2611 LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text
\r
2612 MOV AL, ES:[DI] ; AL = Text Character
\r
2613 AND AX, 00FFh ; Clear High Word
\r
2614 JZ @PS_Exit ; Exit if null character
\r
2616 DEC [BP].PS_Len ; Remaining Text length--
\r
2617 INC [BP].PS_Text ; Point to Next text char
\r
2619 ; Set up Call to GPRINTC
\r
2621 PUSH AX ; Set Character Parameter
\r
2622 MOV BX, [BP].PS_Xpos ; Get Xpos
\r
2623 PUSH BX ; Set Xpos Parameter
\r
2624 ADD BX, 8 ; Advance 1 Char to Right
\r
2625 MOV [BP].PS_Xpos, BX ; Save for next time through
\r
2627 MOV BX, [BP].PS_Ypos ; Get Ypos
\r
2628 PUSH BX ; Set Ypos Parameter
\r
2630 MOV BX, [BP].PS_ColorF ; Get Text Color
\r
2631 PUSH BX ; Set ColorF Parameter
\r
2633 MOV BX, [BP].PS_ColorB ; Get Background Color
\r
2634 PUSH BX ; Set ColorB Parameter
\r
2636 CALL f GPRINTC ; Print Character!
\r
2637 JMP s @PS_Print_It ; Process next character
\r
2640 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2645 RET 14 ; Exit and Clean up Stack
\r
2650 ;================================================================
\r
2651 ;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2652 ;================================================================
\r
2654 ; Routine to quickly transparently Print a null terminated ASCII
\r
2655 ; string on the active display page up to a maximum length.
\r
2657 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2658 ; MaxLen = # of characters to print if no null found
\r
2659 ; Xpos = X position to draw Text at
\r
2660 ; Ypos = Y position of to draw Text at
\r
2661 ; ColorF = Color to draw text in
\r
2663 ; EXIT: No meaningful values returned
\r
2667 DW ?x1 ; DI, SI, DS, BP
\r
2668 DW ?x1 ; DI, SI, DS, BP
\r
2669 DW ?x1 ; DS, DI, SI, BP
\r
2670 DW ?x1 ; DS, DI, SI, BP
\r
2672 TPS_ColorF DW ? ; Text Color
\r
2673 TPS_Ypos DW ? ; Y Position to Print at
\r
2674 TPS_Xpos DW ? ; X position to Print at
\r
2675 TPS_Len DW ? ; Maximum Length of string to print
\r
2676 TPS_Text DW ?,? ; Far Ptr to Text String
\r
2681 TPRINT_STR PROC FAR
\r
2683 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2688 MOV BP, SP ; Set up Stack Frame
\r
2692 MOV CX, [BP].TPS_Len ; Get Remaining text Length
\r
2693 JCXZ @TPS_Exit ; Exit when out of text
\r
2695 LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text
\r
2696 MOV AL, ES:[DI] ; AL = Text Character
\r
2697 AND AX, 00FFh ; Clear High Word
\r
2698 JZ @TPS_Exit ; Exit if null character
\r
2700 DEC [BP].TPS_Len ; Remaining Text length--
\r
2701 INC [BP].TPS_Text ; Point to Next text char
\r
2703 ; Set up Call to TGPRINTC
\r
2705 PUSH AX ; Set Character Parameter
\r
2706 MOV BX, [BP].TPS_Xpos ; Get Xpos
\r
2707 PUSH BX ; Set Xpos Parameter
\r
2708 ADD BX, 8 ; Advance 1 Char to Right
\r
2709 MOV [BP].TPS_Xpos, BX ; Save for next time through
\r
2711 MOV BX, [BP].TPS_Ypos ; Get Ypos
\r
2712 PUSH BX ; Set Ypos Parameter
\r
2714 MOV BX, [BP].TPS_ColorF ; Get Text Color
\r
2715 PUSH BX ; Set ColorF Parameter
\r
2717 CALL f TGPRINTC ; Print Character!
\r
2718 JMP s @TPS_Print_It ; Process next character
\r
2721 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2726 RET 12 ; Exit and Clean up Stack
\r
2731 ;===========================================
\r
2732 ;SET_DISPLAY_FONT(SEG FontData, FontNumber%)
\r
2733 ;===========================================
\r
2735 ; Allows the user to specify their own font data for
\r
2736 ; wither the lower or upper 128 characters.
\r
2738 ; ENTRY: FontData = Far Pointer to Font Bitmaps
\r
2739 ; FontNumber = Which half of set this is
\r
2740 ; = 0, Lower 128 characters
\r
2741 ; = 1, Upper 128 characters
\r
2743 ; EXIT: No meaningful values returned
\r
2749 SDF_Which DW ? ; Hi Table/Low Table Flag
\r
2750 SDF_Font DD ? ; Far Ptr to Font Table
\r
2753 PUBLIC SET_DISPLAY_FONT
\r
2755 SET_DISPLAY_FONT PROC FAR
\r
2757 PUSH BP ; Preserve Registers
\r
2758 MOV BP, SP ; Set up Stack Frame
\r
2760 LES DI, [BP].SDF_Font ; Get Far Ptr to Font
\r
2762 MOV SI, o CHARSET_LOW ; Assume Lower 128 chars
\r
2763 TEST [BP].SDF_Which, 1 ; Font #1 selected?
\r
2764 JZ @SDF_Set_Font ; If not, skip ahead
\r
2766 MOV SI, o CHARSET_HI ; Ah, really it's 128-255
\r
2769 MOV [SI], DI ; Set Font Pointer Offset
\r
2770 MOV [SI+2], ES ; Set Font Pointer Segment
\r
2772 POP BP ; Restore Registers
\r
2773 RET 6 ; We are Done.. Outa here
\r
2775 SET_DISPLAY_FONT ENDP
\r
2778 ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====
\r
2780 ;======================================================
\r
2781 ;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2782 ;======================================================
\r
2784 ; Draws a variable sized Graphics Bitmap such as a
\r
2785 ; picture or an Icon on the current Display Page in
\r
2786 ; Mode X. The Bitmap is stored in a linear byte array
\r
2787 ; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)
\r
2788 ; This is the same linear manner as mode 13h graphics.
\r
2790 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2791 ; Xpos = X position to Place Upper Left pixel at
\r
2792 ; Ypos = Y position to Place Upper Left pixel at
\r
2793 ; Width = Width of the Bitmap in Pixels
\r
2794 ; Height = Height of the Bitmap in Pixels
\r
2796 ; EXIT: No meaningful values returned
\r
2800 DB_LineO DW ? ; Offset to Next Line
\r
2801 DB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2802 DB_Start DW ? ; Addr of Upper Left Pixel
\r
2803 DB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2804 DB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2805 DW ?x1 ; DI, SI, DS, BP
\r
2806 DW ?x1 ; DI, SI, DS, BP
\r
2807 DW ?x1 ; DS, DI, SI, BP
\r
2808 DW ?x1 ; DS, DI, SI, BP
\r
2810 DB_Height DW ? ; Height of Bitmap in Pixels
\r
2811 DB_Width DW ? ; Width of Bitmap in Pixels
\r
2812 DB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2813 DB_Xpos DW ? ; X position to Draw Bitmap at
\r
2814 DB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2817 PUBLIC DRAW_BITMAP
\r
2819 DRAW_BITMAP PROC FAR
\r
2821 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2826 SUB SP, 10 ; Allocate workspace
\r
2827 MOV BP, SP ; Set up Stack Frame
\r
2829 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2830 CLD ; Direction Flag = Forward
\r
2832 MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos
\r
2833 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
2835 MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos
\r
2836 MOV CL, BL ; Save Plane # in CL
\r
2837 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2838 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2840 ADD DI, AX ; ES:DI -> Start of Line
\r
2841 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
2842 MOV [BP].DB_Start, DI ; Save Starting Addr
\r
2844 ; Compute line to line offset
\r
2846 MOV BX, [BP].DB_Width ; Get Width of Image
\r
2847 MOV DX, BX ; Save Copy in DX
\r
2848 SHR BX, 1 ; /4 = width in bands
\r
2849 SHR BX, 1 ; /4 = width in bands
\r
2850 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
2851 SUB AX, BX ; - (Bitmap Width/4)
\r
2853 MOV [BP].DB_LineO, AX ; Save Line Width offset
\r
2854 MOV [BP].DB_PixCount, BX ; Minimum # pix to copy
\r
2856 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
2857 MOV [BP].DB_PixSkew, DX ; Also End of Line Skew
\r
2858 MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count
\r
2860 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
2861 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
2862 SHL AH, CL ; Select correct Plane
\r
2863 OUT_16 SC_Index, AX ; Select Plane...
\r
2864 MOV BH, AH ; BH = Saved Plane Mask
\r
2865 MOV BL, 4 ; BL = Planes to Copy
\r
2869 LDS SI, [BP].DB_Image ; DS:SI-> Source Image
\r
2870 MOV DX, [BP].DB_Height ; # of Lines to Copy
\r
2871 MOV DI, [BP].DB_Start ; ES:DI-> Dest pos
\r
2874 MOV CX, [BP].DB_PixCount ; Min # to copy
\r
2876 TEST CL, 0FCh ; 16+PixWide?
\r
2877 JZ @DB_COPY_REMAINDER ; Nope...
\r
2879 ; Pixel Copy loop has been unrolled to x4
\r
2882 MOVSB ; Copy Bitmap Pixel
\r
2883 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2884 MOVSB ; Copy Bitmap Pixel
\r
2885 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2886 MOVSB ; Copy Bitmap Pixel
\r
2887 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2888 MOVSB ; Copy Bitmap Pixel
\r
2889 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2891 SUB CL, 4 ; Pixels to Copy=-4
\r
2892 TEST CL, 0FCh ; 4+ Pixels Left?
\r
2893 JNZ @DB_COPY_LOOP ; if so, do another block
\r
2895 @DB_COPY_REMAINDER:
\r
2896 JCXZ @DB_NEXT_LINE ; Any Pixels left on line
\r
2899 MOVSB ; Copy Bitmap Pixel
\r
2900 ADD SI,3 ; Skip to Next Byte in same plane
\r
2901 LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done
\r
2905 ; any Partial Pixels? (some planes only)
\r
2907 OR CX, [BP].DB_SkewFlag ; Get Skew Count
\r
2908 JZ @DB_NEXT2 ; if no partial pixels
\r
2910 MOVSB ; Copy Bitmap Pixel
\r
2911 DEC DI ; Back up to align
\r
2912 DEC SI ; Back up to align
\r
2915 ADD SI, [BP].DB_PixSkew ; Adjust Skew
\r
2916 ADD DI, [BP].DB_LineO ; Set to Next Display Line
\r
2917 LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more
\r
2919 ; Copy Next Plane....
\r
2921 DEC BL ; Planes to Go--
\r
2922 JZ @DB_Exit ; Hey! We are done
\r
2924 ROL BH, 1 ; Next Plane in line...
\r
2925 OUT_8 SC_Data, BH ; Select Plane
\r
2927 CMP AL, 12h ; Carry Set if AL=11h
\r
2928 ADC [BP].DB_Start, 0 ; Screen Addr =+Carry
\r
2929 INC w [BP].DB_Image ; Start @ Next Byte
\r
2931 SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew
\r
2932 ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1
\r
2934 JMP s @DB_COPY_PLANE ; Go Copy the Next Plane
\r
2937 ADD SP, 10 ; Deallocate workspace
\r
2938 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2943 RET 12 ; Exit and Clean up Stack
\r
2948 ;=======================================================
\r
2949 ;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2950 ;=======================================================
\r
2952 ; Transparently Draws a variable sized Graphics Bitmap
\r
2953 ; such as a picture or an Icon on the current Display Page
\r
2954 ; in Mode X. Pixels with a value of 0 are not drawn,
\r
2955 ; leaving the previous "background" contents intact.
\r
2957 ; The Bitmap format is the same as for the DRAW_BITMAP function.
\r
2959 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2960 ; Xpos = X position to Place Upper Left pixel at
\r
2961 ; Ypos = Y position to Place Upper Left pixel at
\r
2962 ; Width = Width of the Bitmap in Pixels
\r
2963 ; Height = Height of the Bitmap in Pixels
\r
2965 ; EXIT: No meaningful values returned
\r
2969 TB_LineO DW ? ; Offset to Next Line
\r
2970 TB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2971 TB_Start DW ? ; Addr of Upper Left Pixel
\r
2972 TB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2973 TB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2974 DW ?x1 ; DI, SI, DS, BP
\r
2975 DW ?x1 ; DI, SI, DS, BP
\r
2976 DW ?x1 ; DS, DI, SI, BP
\r
2977 DW ?x1 ; DS, DI, SI, BP
\r
2979 TB_Height DW ? ; Height of Bitmap in Pixels
\r
2980 TB_Width DW ? ; Width of Bitmap in Pixels
\r
2981 TB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2982 TB_Xpos DW ? ; X position to Draw Bitmap at
\r
2983 TB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2986 PUBLIC TDRAW_BITMAP
\r
2988 TDRAW_BITMAP PROC FAR
\r
2990 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2995 SUB SP, 10 ; Allocate workspace
\r
2996 MOV BP, SP ; Set up Stack Frame
\r
2998 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2999 CLD ; Direction Flag = Forward
\r
3001 MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos
\r
3002 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
3004 MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos
\r
3005 MOV CL, BL ; Save Plane # in CL
\r
3006 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
3007 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
3009 ADD DI, AX ; ES:DI -> Start of Line
\r
3010 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
3011 MOV [BP].TB_Start, DI ; Save Starting Addr
\r
3013 ; Compute line to line offset
\r
3015 MOV BX, [BP].TB_Width ; Get Width of Image
\r
3016 MOV DX, BX ; Save Copy in DX
\r
3017 SHR BX, 1 ; /4 = width in bands
\r
3018 SHR BX, 1 ; /4 = width in bands
\r
3019 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
3020 SUB AX, BX ; - (Bitmap Width/4)
\r
3022 MOV [BP].TB_LineO, AX ; Save Line Width offset
\r
3023 MOV [BP].TB_PixCount, BX ; Minimum # pix to copy
\r
3025 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
3026 MOV [BP].TB_PixSkew, DX ; Also End of Line Skew
\r
3027 MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count
\r
3029 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
3030 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
3031 SHL AH, CL ; Select correct Plane
\r
3032 OUT_16 SC_Index, AX ; Select Plane...
\r
3033 MOV BH, AH ; BH = Saved Plane Mask
\r
3034 MOV BL, 4 ; BL = Planes to Copy
\r
3038 LDS SI, [BP].TB_Image ; DS:SI-> Source Image
\r
3039 MOV DX, [BP].TB_Height ; # of Lines to Copy
\r
3040 MOV DI, [BP].TB_Start ; ES:DI-> Dest pos
\r
3042 ; Here AH is set with the value to be considered
\r
3043 ; "Transparent". It can be changed!
\r
3045 MOV AH, 0 ; Value to Detect 0
\r
3048 MOV CX, [BP].TB_PixCount ; Min # to copy
\r
3050 TEST CL, 0FCh ; 16+PixWide?
\r
3051 JZ @TB_COPY_REMAINDER ; Nope...
\r
3053 ; Pixel Copy loop has been unrolled to x4
\r
3056 LODSB ; Get Pixel Value in AL
\r
3057 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3058 CMP AL, AH ; It is "Transparent"?
\r
3059 JE @TB_SKIP_01 ; Skip ahead if so
\r
3060 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3063 LODSB ; Get Pixel Value in AL
\r
3064 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3065 CMP AL, AH ; It is "Transparent"?
\r
3066 JE @TB_SKIP_02 ; Skip ahead if so
\r
3067 MOV ES:[DI+1], AL ; Copy Pixel to VGA screen
\r
3070 LODSB ; Get Pixel Value in AL
\r
3071 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3072 CMP AL, AH ; It is "Transparent"?
\r
3073 JE @TB_SKIP_03 ; Skip ahead if so
\r
3074 MOV ES:[DI+2], AL ; Copy Pixel to VGA screen
\r
3077 LODSB ; Get Pixel Value in AL
\r
3078 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3079 CMP AL, AH ; It is "Transparent"?
\r
3080 JE @TB_SKIP_04 ; Skip ahead if so
\r
3081 MOV ES:[DI+3], AL ; Copy Pixel to VGA screen
\r
3084 ADD DI, 4 ; Adjust Pixel Write Location
\r
3085 SUB CL, 4 ; Pixels to Copy=-4
\r
3086 TEST CL, 0FCh ; 4+ Pixels Left?
\r
3087 JNZ @TB_COPY_LOOP ; if so, do another block
\r
3089 @TB_COPY_REMAINDER:
\r
3090 JCXZ @TB_NEXT_LINE ; Any Pixels left on line
\r
3093 LODSB ; Get Pixel Value in AL
\r
3094 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3095 CMP AL, AH ; It is "Transparent"?
\r
3096 JE @TB_SKIP_05 ; Skip ahead if so
\r
3097 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3100 INC DI ; Advance Dest Addr
\r
3101 LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done
\r
3105 ; any Partial Pixels? (some planes only)
\r
3107 OR CX, [BP].TB_SkewFlag ; Get Skew Count
\r
3108 JZ @TB_NEXT2 ; if no partial pixels
\r
3110 LODSB ; Get Pixel Value in AL
\r
3111 DEC SI ; Backup to Align
\r
3112 CMP AL, AH ; It is "Transparent"?
\r
3113 JE @TB_NEXT2 ; Skip ahead if so
\r
3114 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3117 ADD SI, [BP].TB_PixSkew ; Adjust Skew
\r
3118 ADD DI, [BP].TB_LineO ; Set to Next Display Line
\r
3119 LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More
\r
3121 ;Copy Next Plane....
\r
3123 DEC BL ; Planes to Go--
\r
3124 JZ @TB_Exit ; Hey! We are done
\r
3126 ROL BH, 1 ; Next Plane in line...
\r
3127 OUT_8 SC_Data, BH ; Select Plane
\r
3129 CMP AL, 12h ; Carry Set if AL=11h
\r
3130 ADC [BP].TB_Start, 0 ; Screen Addr =+Carry
\r
3131 INC w [BP].TB_Image ; Start @ Next Byte
\r
3133 SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew
\r
3134 ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1
\r
3136 JMP @TB_COPY_PLANE ; Go Copy the next Plane
\r
3139 ADD SP, 10 ; Deallocate workspace
\r
3140 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3145 RET 12 ; Exit and Clean up Stack
\r
3150 ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====
\r
3152 ;==================================
\r
3153 ;COPY_PAGE (SourcePage%, DestPage%)
\r
3154 ;==================================
\r
3156 ; Duplicate on display page onto another
\r
3158 ; ENTRY: SourcePage = Display Page # to Duplicate
\r
3159 ; DestPage = Display Page # to hold copy
\r
3161 ; EXIT: No meaningful values returned
\r
3165 DW ?x1 ; DI, SI, DS, BP
\r
3166 DW ?x1 ; DI, SI, DS, BP
\r
3167 DW ?x1 ; DS, DI, SI, BP
\r
3168 DW ?x1 ; DS, DI, SI, BP
\r
3170 CP_DestP DW ? ; Page to hold copied image
\r
3171 CP_SourceP DW ? ; Page to Make copy from
\r
3176 COPY_PAGE PROC FAR
\r
3178 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
3183 MOV BP, SP ; Set up Stack Frame
\r
3184 CLD ; Block Xfer Forwards
\r
3186 ; Make sure Page #'s are valid
\r
3188 MOV AX, [BP].CP_SourceP ; Get Source Page #
\r
3189 CMP AX, LAST_PAGE ; is it > Max Page #?
\r
3190 JAE @CP_Exit ; if so, abort
\r
3192 MOV BX, [BP].CP_DestP ; Get Destination Page #
\r
3193 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3194 JAE @CP_Exit ; if so, abort
\r
3196 CMP AX, BX ; Pages #'s the same?
\r
3197 JE @CP_Exit ; if so, abort
\r
3199 ; Setup DS:SI and ES:DI to Video Pages
\r
3201 SHL BX, 1 ; Scale index to Word
\r
3202 MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page
\r
3204 MOV BX, AX ; Index to Source page
\r
3205 SHL BX, 1 ; Scale index to Word
\r
3206 MOV SI, PAGE_ADDR[BX] ; Offset to Source Page
\r
3208 MOV CX, PAGE_SIZE ; Get size of Page
\r
3209 MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment
\r
3210 MOV ES, AX ; ES:DI -> Dest Page
\r
3211 MOV DS, AX ; DS:SI -> Source Page
\r
3213 ; Setup VGA registers for Mem to Mem copy
\r
3215 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3216 OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes
\r
3218 ; Note.. Do *NOT* use MOVSW or MOVSD - they will
\r
3219 ; Screw with the latches which are 8 bits x 4
\r
3221 REP MOVSB ; Copy entire Page!
\r
3223 ; Reset VGA for normal memory access
\r
3225 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off
\r
3228 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3233 RET 4 ; Exit and Clean up Stack
\r
3238 ;==========================================================================
\r
3239 ;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)
\r
3240 ;==========================================================================
\r
3242 ; Copies a Bitmap Image from one Display Page to Another
\r
3243 ; This Routine is Limited to copying Images with the same
\r
3244 ; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4)
\r
3245 ; Copying an Image to the Same Page is supported, but results
\r
3246 ; may be defined when the when the rectangular areas
\r
3247 ; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) -
\r
3248 ; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...
\r
3249 ; No Paramter checking to done to insure that
\r
3250 ; X2 >= X1 and Y2 >= Y1. Be Careful...
\r
3252 ; ENTRY: SourcePage = Display Page # with Source Image
\r
3253 ; X1 = Upper Left Xpos of Source Image
\r
3254 ; Y1 = Upper Left Ypos of Source Image
\r
3255 ; X2 = Lower Right Xpos of Source Image
\r
3256 ; Y2 = Lower Right Ypos of Source Image
\r
3257 ; DestPage = Display Page # to copy Image to
\r
3258 ; DestX1 = Xpos to Copy UL Corner of Image to
\r
3259 ; DestY1 = Ypos to Copy UL Corner of Image to
\r
3261 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
3265 CB_Height DW ? ; Height of Image in Lines
\r
3266 CB_Width DW ? ; Width of Image in "bands"
\r
3267 DW ?x1 ; DI, SI, DS, BP
\r
3268 DW ?x1 ; DI, SI, DS, BP
\r
3269 DW ?x1 ; DS, DI, SI, BP
\r
3270 DW ?x1 ; DS, DI, SI, BP
\r
3272 CB_DestY1 DW ? ; Destination Ypos
\r
3273 CB_DestX1 DW ? ; Destination Xpos
\r
3274 CB_DestP DW ? ; Page to Copy Bitmap To
\r
3275 CB_Y2 DW ? ; LR Ypos of Image
\r
3276 CB_X2 DW ? ; LR Xpos of Image
\r
3277 CB_Y1 DW ? ; UL Ypos of Image
\r
3278 CB_X1 DW ? ; UL Xpos of Image
\r
3279 CB_SourceP DW ? ; Page containing Source Bitmap
\r
3282 PUBLIC COPY_BITMAP
\r
3284 COPY_BITMAP PROC FAR
\r
3286 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
3291 SUB SP, 4 ; Allocate WorkSpace on Stack
\r
3292 MOV BP, SP ; Set up Stack Frame
\r
3294 ; Prep Registers (and keep jumps short!)
\r
3296 MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram
\r
3297 CLD ; Block Xfer Forwards
\r
3299 ; Make sure Parameters are valid
\r
3301 MOV BX, [BP].CB_SourceP ; Get Source Page #
\r
3302 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3303 JAE @CB_Abort ; if so, abort
\r
3305 MOV CX, [BP].CB_DestP ; Get Destination Page #
\r
3306 CMP CX, LAST_PAGE ; is it > Max Page #?
\r
3307 JAE @CB_Abort ; if so, abort
\r
3309 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3310 XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1
\r
3311 AND AX, PLANE_BITS ; Check Plane Bits
\r
3312 JNZ @CB_Abort ; They should cancel out
\r
3314 ; Setup for Copy processing
\r
3316 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
3317 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3319 ; Compute Info About Images, Setup ES:SI & ES:DI
\r
3321 MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines
\r
3322 SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1
\r
3323 INC AX ; (add 1 since were not 0 based)
\r
3324 MOV [BP].CB_Height, AX ; Save on Stack for later use
\r
3326 MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels
\r
3327 MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1
\r
3328 SHR AX, 1 ; Get X2 Band (X2 / 4)
\r
3329 SHR DX, 1 ; Get X1 Band (X1 / 4)
\r
3330 SHR AX, 1 ; Get X2 Band (X2 / 4)
\r
3331 SHR DX, 1 ; Get X1 Band (X1 / 4)
\r
3332 SUB AX, DX ; AX = # of Bands - 1
\r
3333 INC AX ; AX = # of Bands
\r
3334 MOV [BP].CB_Width, AX ; Save on Stack for later use
\r
3336 SHL BX, 1 ; Scale Source Page to Word
\r
3337 MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page
\r
3338 MOV AX, [BP].CB_Y1 ; Get Source Y1 Line
\r
3339 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3340 ADD SI, AX ; SI = Offset to Line Y1
\r
3341 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3342 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3343 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3344 ADD SI, AX ; SI = Byte Offset to (X1,Y1)
\r
3346 MOV BX, CX ; Dest Page Index to BX
\r
3347 SHL BX, 1 ; Scale Source Page to Word
\r
3348 MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page
\r
3349 MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line
\r
3350 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3351 ADD DI, AX ; DI = Offset to Line Y1
\r
3352 MOV AX, [BP].CB_DestX1 ; Get Dest X1
\r
3353 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3354 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3355 ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1)
\r
3357 MOV CX, [BP].CB_Width ; CX = Width of Image (Bands)
\r
3359 JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band
\r
3361 MOV BX, [BP].CB_X1 ; Get Source X1
\r
3362 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?)
\r
3363 JZ @CB_Check_Right ; if so, check right alignment
\r
3364 JNZ @CB_Left_Band ; not aligned? well..
\r
3367 mov ax,0 ; Return False (Failure)
\r
3368 JMP @CB_Exit ; and Finish Up
\r
3370 ; Copy when Left & Right Clip Masks overlap...
\r
3372 @CB_Only_One_Band:
\r
3373 MOV BX, [BP].CB_X1 ; Get Left Clip Mask
\r
3374 AND BX, PLANE_BITS ; Mask out Row #
\r
3375 MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask
\r
3376 MOV BX, [BP].CB_X2 ; Get Right Clip Mask
\r
3377 AND BX, PLANE_BITS ; Mask out Row #
\r
3378 AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte
\r
3380 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
3382 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3383 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3384 mov bx,0 ; BX = Offset into Image
\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 LOOPjz CX, @CB_One_Done ; Exit Loop if Finished
\r
3392 MOV AL, ES:[SI+BX] ; Load Latches
\r
3393 MOV ES:[DI+BX], AL ; Unload Latches
\r
3394 ADD BX, DX ; Advance Offset to Next Line
\r
3395 LOOPx CX, @CB_One_Loop ; Loop until Finished
\r
3398 JMP @CB_Finish ; Outa Here!
\r
3400 ; Copy Left Edge of Bitmap
\r
3404 OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask
\r
3406 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3407 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3408 mov bx,0 ; BX = Offset into Image
\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 LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished
\r
3416 MOV AL, ES:[SI+BX] ; Load Latches
\r
3417 MOV ES:[DI+BX], AL ; Unload Latches
\r
3418 ADD BX, DX ; Advance Offset to Next Line
\r
3419 LOOPx CX, @CB_Left_Loop ; Loop until Finished
\r
3422 INC DI ; Move Dest Over 1 band
\r
3423 INC SI ; Move Source Over 1 band
\r
3424 DEC [BP].CB_Width ; Band Width--
\r
3426 ; Determine if Right Edge of Bitmap needs special copy
\r
3429 MOV BX, [BP].CB_X2 ; Get Source X2
\r
3430 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?)
\r
3431 CMP BL, 03h ; Plane = 3?
\r
3432 JE @CB_Copy_Middle ; Copy the Middle then!
\r
3434 ; Copy Right Edge of Bitmap
\r
3438 OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask
\r
3440 DEC [BP].CB_Width ; Band Width--
\r
3441 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3442 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3443 MOV BX, [BP].CB_Width ; BX = Offset to Right Edge
\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 LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished
\r
3451 MOV AL, ES:[SI+BX] ; Load Latches
\r
3452 MOV ES:[DI+BX], AL ; Unload Latches
\r
3453 ADD BX, DX ; Advance Offset to Next Line
\r
3454 LOOPx CX, @CB_Right_Loop ; Loop until Finished
\r
3458 ; Copy the Main Block of the Bitmap
\r
3462 MOV CX, [BP].CB_Width ; Get Width Remaining
\r
3463 JCXZ @CB_Finish ; Exit if Done
\r
3465 OUT_8 SC_Data, ALL_PLANES ; Copy all Planes
\r
3467 MOV DX, SCREEN_WIDTH ; Get Width of Screen minus
\r
3468 SUB DX, CX ; Image width (for Adjustment)
\r
3469 MOV AX, [BP].CB_Height ; AX = # of Lines to Copy
\r
3470 MOV BX, CX ; BX = Quick REP reload count
\r
3471 MOV CX, ES ; Move VGA Segment
\r
3472 MOV DS, CX ; Into DS
\r
3474 ; Actual Copy Loop. REP MOVSB does the work
\r
3477 MOV CX, BX ; Recharge Rep Count
\r
3478 REP MOVSB ; Move Bands
\r
3479 LOOPjz AX, @CB_Finish ; Exit Loop if Finished
\r
3481 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3482 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3484 MOV CX, BX ; Recharge Rep Count
\r
3485 REP MOVSB ; Move Bands
\r
3487 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3488 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3489 LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done
\r
3492 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on
\r
3495 ADD SP, 04 ; Deallocate stack workspace
\r
3496 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3501 RET 16 ; Exit and Clean up Stack
\r
3505 END ; End of Code Segment
\r