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 / -1= 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_BadModeSetup ; 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_BadModeSetup ; Report Error if too Many Pages
\r
492 JCXZ @SVM_BadModeSetup ; 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_BadModeSetup ; Report Error if too small
\r
501 CMP AX, CS:[SI].M_XMax ; Check against Max X
\r
502 JA @SVM_BadModeSetup ; 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_BadModeSetup ; Report Error if too small
\r
509 CMP BX, CS:[SI].M_YMax ; Check against Max Y
\r
510 JA @SVM_BadModeSetup ; 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
526 mov ax,0 ; Return Value = False
\r
527 JMP @SVM_Exit ; Normal Exit
\r
531 MOV AX, 13H ; Start with Mode 13H
\r
532 INT 10H ; Let BIOS Set Mode
\r
534 OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode
\r
535 OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset
\r
536 OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size
\r
537 OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ...
\r
539 OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register
\r
540 INC DX ; Point to Data
\r
541 IN AL, DX ; Get Value, Bit 7 = Protect
\r
542 AND AL, 7FH ; Mask out Write Protect
\r
543 OUT DX, AL ; And send it back
\r
545 MOV DX, CRTC_INDEX ; Vga Crtc Registers
\r
546 ADD SI, M_CRTC ; SI -> CRTC Parameter Data
\r
548 ; Load Tables of CRTC Parameters from List of Tables
\r
552 MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl
\r
553 ADD SI, 2 ; Point to next Ptr Entry
\r
554 OR DI, DI ; A nil Ptr means that we have
\r
555 JZ @SVM_Set_Data ; finished CRTC programming
\r
558 MOV AX, CS:[DI] ; Get CRTC Data from Table
\r
559 ADD DI, 2 ; Advance Pointer
\r
560 OR AX, AX ; At End of Data Table?
\r
561 JZ @SVM_Setup_Table ; If so, Exit & get next Table
\r
563 OUT DX, AX ; Reprogram VGA CRTC reg
\r
564 JMP s @SVM_Setup_CRTC ; Process Next Table Entry
\r
566 ; Initialize Page & Scroll info, DI = 0
\r
569 MOV DISPLAY_PAGE, DI ; Display Page = 0
\r
570 MOV ACTIVE_PAGE, DI ; Active Page = 0
\r
571 MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0
\r
572 MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0
\r
573 MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0
\r
574 MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0
\r
576 MOV AX, VGA_SEGMENT ; Segment for VGA memory
\r
577 MOV CURRENT_SEGMENT, AX ; Save for Future LES's
\r
579 ; Set Logical Screen Width, X Scroll and Our Data
\r
581 MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info
\r
582 MOV AX, [BP].SVM_Xsize ; Get Display Width
\r
584 MOV CX, AX ; CX = Logical Width
\r
585 SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value
\r
586 MOV MAX_XOFFSET, CX ; Set Maximum X Scroll
\r
588 SHR AX, 1 ; Bytes = Pixels / 4
\r
589 SHR AX, 1 ; Bytes = Pixels / 4
\r
590 MOV SCREEN_WIDTH, AX ; Save Width in Pixels
\r
592 SHR AX, 1 ; Offset Value = Bytes / 2
\r
593 MOV AH, 13h ; CRTC Offset Register Index
\r
594 XCHG AL, AH ; Switch format for OUT
\r
595 OUT DX, AX ; Set VGA CRTC Offset Reg
\r
597 ; Setup Data table, Y Scroll, Misc for Other Routines
\r
599 MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height
\r
601 MOV CX, AX ; CX = Logical Height
\r
602 SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value
\r
603 MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll
\r
605 MOV SCREEN_HEIGHT, AX ; Save Height in Pixels
\r
606 MUL SCREEN_WIDTH ; AX = Page Size in Bytes,
\r
607 MOV PAGE_SIZE, AX ; Save Page Size
\r
609 MOV CX, [BP].SVM_Pages ; Get # of Pages
\r
610 MOV LAST_PAGE, CX ; Save # of Pages
\r
612 mov bx,0 ; Page # = 0
\r
613 MOV DX, BX ; Page 0 Offset = 0
\r
617 MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset
\r
618 ADD BX, 2 ; Page#++
\r
619 ADD DX, AX ; Compute Addr of Next Page
\r
620 LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set
\r
624 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
625 LES DI, d CURRENT_PAGE ; -> Start of VGA memory
\r
628 CLD ; Block Xfer Forwards
\r
629 MOV CX, 8000H ; 32K * 4 * 2 = 256K
\r
630 REP STOSW ; Clear dat memory!
\r
632 ; Setup Font Pointers
\r
634 MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127
\r
635 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
636 INT 10h ; Call VGA BIOS
\r
638 MOV CHARSET_LOW, BP ; Save Char Set Offset
\r
639 MOV CHARSET_LOW+2, ES ; Save Char Set Segment
\r
641 MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255
\r
642 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
643 INT 10h ; Call VGA BIOS
\r
645 MOV CHARSET_HI, BP ; Save Char Set Offset
\r
646 MOV CHARSET_HI+2, ES ; Save Char Set Segment
\r
648 MOV AX, True ; Return Success Code
\r
651 ADD SP, 2 ; Deallocate workspace
\r
652 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
657 RET 8 ; Exit & Clean Up Stack
\r
662 ;==================
\r
663 ;SET_MODEX% (Mode%)
\r
664 ;==================
\r
666 ; Quickie Mode Set - Sets Up Mode X to Default Configuration
\r
668 ; ENTRY: ModeType = Desired Screen Resolution (0-7)
\r
669 ; (See SET_VGA_MODEX for list)
\r
671 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
677 SM_Mode DW ? ; Desired Screen Resolution
\r
684 ;PUSHx BP, SI ; Preserve Important registers
\r
687 MOV BP, SP ; Set up Stack Frame
\r
689 mov ax,0 ; Assume Failure
\r
690 MOV BX, [BP].SM_Mode ; Get Desired Mode #
\r
691 CMP BX, NUM_MODES ; Is it a Valid Mode #?
\r
692 JAE @SMX_Exit ; If Not, don't Bother
\r
694 PUSH BX ; Push Mode Parameter
\r
696 SHL BX, 1 ; Scale BX to word Index
\r
697 MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info
\r
699 PUSH CS:[SI].M_XSize ; Push Default X Size
\r
700 PUSH CS:[SI].M_Ysize ; Push Default Y size
\r
701 MOV AL, CS:[SI].M_Pages ; Get Default # of Pages
\r
702 mov ah,0 ; Hi Byte = 0
\r
703 PUSH AX ; Push # Pages
\r
705 CALL f SET_VGA_MODEX ; Set up Mode X!
\r
708 ;POPx SI, BP ; Restore Registers
\r
711 RET 2 ; Exit & Clean Up Stack
\r
716 ; ===== BASIC GRAPHICS PRIMITIVES =====
\r
718 ;============================
\r
719 ;CLEAR_VGA_SCREEN (ColorNum%)
\r
720 ;============================
\r
722 ; Clears the active display page
\r
724 ; ENTRY: ColorNum = Color Value to fill the page with
\r
726 ; EXIT: No meaningful values returned
\r
732 CVS_COLOR DB ?,? ; Color to Set Screen to
\r
735 PUBLIC CLEAR_VGA_SCREEN
\r
737 CLEAR_VGA_SCREEN PROC FAR
\r
739 ;PUSHx BP, DI ; Preserve Important Registers
\r
742 MOV BP, SP ; Set up Stack Frame
\r
744 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
745 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
747 MOV AL, [BP].CVS_COLOR ; Get Color
\r
748 MOV AH, AL ; Copy for Word Write
\r
749 CLD ; Block fill Forwards
\r
751 MOV CX, PAGE_SIZE ; Get Size of Page
\r
752 SHR CX, 1 ; Divide by 2 for Words
\r
753 REP STOSW ; Block Fill VGA memory
\r
755 ;POPx DI, BP ; Restore Saved Registers
\r
758 RET 2 ; Exit & Clean Up Stack
\r
760 CLEAR_VGA_SCREEN ENDP
\r
763 ;===================================
\r
764 ;SET_POINT (Xpos%, Ypos%, ColorNum%)
\r
765 ;===================================
\r
767 ; Plots a single Pixel on the active display page
\r
769 ; ENTRY: Xpos = X position to plot pixel at
\r
770 ; Ypos = Y position to plot pixel at
\r
771 ; ColorNum = Color to plot pixel with
\r
773 ; EXIT: No meaningful values returned
\r
779 SETP_Color DB ?,? ; Color of Point to Plot
\r
780 SETP_Ypos DW ? ; Y pos of Point to Plot
\r
781 SETP_Xpos DW ? ; X pos of Point to Plot
\r
788 ;PUSHx BP, DI ; Preserve Registers
\r
791 MOV BP, SP ; Set up Stack Frame
\r
793 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
795 MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel
\r
796 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
798 MOV BX, [BP].SETP_Xpos ; Get Xpos
\r
799 MOV CX, BX ; Copy to extract Plane # from
\r
800 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
801 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
802 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
804 MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register
\r
805 AND CL, PLANE_BITS ; Get Plane Bits
\r
806 SHL AH, CL ; Get Plane Select Value
\r
807 OUT_16 SC_Index, AX ; Select Plane
\r
809 MOV AL,[BP].SETP_Color ; Get Pixel Color
\r
810 MOV ES:[DI+BX], AL ; Draw Pixel
\r
812 ;POPx DI, BP ; Restore Saved Registers
\r
815 RET 6 ; Exit and Clean up Stack
\r
820 ;==========================
\r
821 ;READ_POINT% (Xpos%, Ypos%)
\r
822 ;==========================
\r
824 ; Read the color of a pixel from the Active Display Page
\r
826 ; ENTRY: Xpos = X position of pixel to read
\r
827 ; Ypos = Y position of pixel to read
\r
829 ; EXIT: AX = Color of Pixel at (Xpos, Ypos)
\r
835 RP_Ypos DW ? ; Y pos of Point to Read
\r
836 RP_Xpos DW ? ; X pos of Point to Read
\r
841 READ_POINT PROC FAR
\r
843 ;PUSHx BP, DI ; Preserve Registers
\r
846 MOV BP, SP ; Set up Stack Frame
\r
848 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
850 MOV AX, [BP].RP_Ypos ; Get Line # of Pixel
\r
851 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
853 MOV BX, [BP].RP_Xpos ; Get Xpos
\r
855 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
856 SHR BX, 1 ; X offset (Bytes) = Xpos/4
\r
857 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
859 MOV AL, READ_MAP ; GC Read Mask Register
\r
860 MOV AH, CL ; Get Xpos
\r
861 AND AH, PLANE_BITS ; & mask out Plane #
\r
862 OUT_16 GC_INDEX, AX ; Select Plane to read in
\r
864 mov ah,0 ; Clear Return Value Hi byte
\r
865 MOV AL, ES:[DI+BX] ; Get Color of Pixel
\r
867 ;POPx DI, BP ; Restore Saved Registers
\r
870 RET 4 ; Exit and Clean up Stack
\r
875 ;======================================================
\r
876 ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
877 ;======================================================
\r
879 ; Fills a rectangular block on the active display Page
\r
881 ; ENTRY: Xpos1 = Left X position of area to fill
\r
882 ; Ypos1 = Top Y position of area to fill
\r
883 ; Xpos2 = Right X position of area to fill
\r
884 ; Ypos2 = Bottom Y position of area to fill
\r
885 ; ColorNum = Color to fill area with
\r
887 ; EXIT: No meaningful values returned
\r
891 DW ?x1 ; DS, DI, SI, BP
\r
892 DW ?x1 ; DS, DI, SI, BP
\r
893 DW ?x1 ; DS, DI, SI, BP
\r
894 DW ?x1 ; DS, DI, SI, BP
\r
896 FB_Color DB ?,? ; Fill Color
\r
897 FB_Ypos2 DW ? ; Y pos of Lower Right Pixel
\r
898 FB_Xpos2 DW ? ; X pos of Lower Right Pixel
\r
899 FB_Ypos1 DW ? ; Y pos of Upper Left Pixel
\r
900 FB_Xpos1 DW ? ; X pos of Upper Left Pixel
\r
905 FILL_BLOCK PROC FAR
\r
907 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
912 MOV BP, SP ; Set up Stack Frame
\r
914 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
915 CLD ; Direction Flag = Forward
\r
917 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
919 ; Validate Pixel Coordinates
\r
920 ; If necessary, Swap so X1 <= X2, Y1 <= Y2
\r
922 MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2?
\r
923 MOV BX, [BP].FB_Ypos2 ; BX = Y2
\r
927 MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1
\r
928 XCHG AX, BX ; on stack for future use
\r
931 SUB BX, AX ; Get Y width
\r
932 INC BX ; Add 1 to avoid 0 value
\r
933 MOV [BP].FB_Ypos2, BX ; Save in Ypos2
\r
935 MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line
\r
936 ADD DI, AX ; DI = Start of Line Y1
\r
938 MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2
\r
939 MOV BX, [BP].FB_Xpos2 ;
\r
941 JLE @FB_NOSWAP2 ; Skip Ahead if Ok
\r
943 MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2
\r
944 XCHG AX, BX ; on stack for future use
\r
946 ; All our Input Values are in order, Now determine
\r
947 ; How many full "bands" 4 pixels wide (aligned) there
\r
948 ; are, and if there are partial bands (<4 pixels) on
\r
949 ; the left and right edges.
\r
952 MOV DX, AX ; DX = X1 (Pixel Position)
\r
953 SHR DX, 1 ; DX/4 = Bytes into Line
\r
954 SHR DX, 1 ; DX/4 = Bytes into Line
\r
955 ADD DI, DX ; DI = Addr of Upper-Left Corner
\r
957 MOV CX, BX ; CX = X2 (Pixel Position)
\r
958 SHR CX, 1 ; CX/4 = Bytes into Line
\r
959 SHR CX, 1 ; CX/4 = Bytes into Line
\r
961 CMP DX, CX ; Start and end in same band?
\r
962 JNE @FB_NORMAL ; if not, check for l & r edges
\r
963 JMP @FB_ONE_BAND_ONLY ; if so, then special processing
\r
966 SUB CX, DX ; CX = # bands -1
\r
967 MOV SI, AX ; SI = PLANE#(X1)
\r
968 AND SI, PLANE_BITS ; if Left edge is aligned then
\r
969 JZ @FB_L_PLANE_FLUSH ; no special processing..
\r
971 ; Draw "Left Edge" vertical strip of 1-3 pixels...
\r
973 OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask
\r
975 MOV SI, DI ; SI = Copy of Start Addr (UL)
\r
977 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
978 MOV AL, [BP].FB_Color ; Get Fill Color
\r
979 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
982 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
983 ADD SI, BX ; Point to Next Line (Below)
\r
984 LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn
\r
986 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
987 ADD SI, BX ; Point to Next Line (Below)
\r
988 LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn
\r
992 INC DI ; Point to Middle (or Right) Block
\r
993 DEC CX ; Reset CX instead of JMP @FB_RIGHT
\r
996 INC CX ; Add in Left band to middle block
\r
998 ; DI = Addr of 1st middle Pixel (band) to fill
\r
999 ; CX = # of Bands to fill -1
\r
1002 MOV SI, [BP].FB_Xpos2 ; Get Xpos2
\r
1003 AND SI, PLANE_BITS ; Get Plane values
\r
1004 CMP SI, 0003 ; Plane = 3?
\r
1005 JE @FB_R_EDGE_FLUSH ; Hey, add to middle
\r
1007 ; Draw "Right Edge" vertical strip of 1-3 pixels...
\r
1009 OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask
\r
1011 MOV SI, DI ; Get Addr of Left Edge
\r
1012 ADD SI, CX ; Add Width-1 (Bands)
\r
1013 DEC SI ; To point to top of Right Edge
\r
1015 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1016 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1017 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1020 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
1021 ADD SI, BX ; Point to Next Line (Below)
\r
1022 LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn
\r
1024 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
1025 ADD SI, BX ; Point to Next Line (Below)
\r
1026 LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn
\r
1030 DEC CX ; Minus 1 for Middle bands
\r
1031 JZ @FB_EXIT ; Uh.. no Middle bands...
\r
1035 ; DI = Addr of Upper Left block to fill
\r
1036 ; CX = # of Bands to fill in (width)
\r
1038 OUT_8 SC_Data, ALL_PLANES ; Write to All Planes
\r
1040 MOV DX, SCREEN_WIDTH ; DX = DI Increment
\r
1041 SUB DX, CX ; = Screen_Width-# Planes Filled
\r
1043 MOV BX, CX ; BX = Quick Refill for CX
\r
1044 MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill
\r
1045 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1048 REP STOSB ; Fill in entire line
\r
1050 MOV CX, BX ; Recharge CX (Line Width)
\r
1051 ADD DI, DX ; Point to start of Next Line
\r
1052 LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn
\r
1054 JMP s @FB_EXIT ; Outa here
\r
1056 @FB_ONE_BAND_ONLY:
\r
1057 MOV SI, AX ; Get Left Clip Mask, Save X1
\r
1058 AND SI, PLANE_BITS ; Mask out Row #
\r
1059 MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1060 MOV SI, BX ; Get Right Clip Mask, Save X2
\r
1061 AND SI, PLANE_BITS ; Mask out Row #
\r
1062 AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte
\r
1064 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
1066 MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1067 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1068 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1071 MOV ES:[DI], AL ; Fill in Pixels
\r
1072 ADD DI, BX ; Point to Next Line (Below)
\r
1073 LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn
\r
1075 MOV ES:[DI], AL ; Fill in Pixels
\r
1076 ADD DI, BX ; Point to Next Line (Below)
\r
1077 LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn
\r
1080 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
1085 RET 10 ; Exit and Clean up Stack
\r
1090 ;=====================================================
\r
1091 ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
1092 ;=====================================================
\r
1094 ; Draws a Line on the active display page
\r
1096 ; ENTRY: Xpos1 = X position of first point on line
\r
1097 ; Ypos1 = Y position of first point on line
\r
1098 ; Xpos2 = X position of last point on line
\r
1099 ; Ypos2 = Y position of last point on line
\r
1100 ; ColorNum = Color to draw line with
\r
1102 ; EXIT: No meaningful values returned
\r
1106 DW ?x1 ; DI, SI, BP
\r
1107 DW ?x1 ; DI, SI, BP
\r
1108 DW ?x1 ; DI, SI, BP
\r
1110 DL_ColorF DB ?,? ; Line Draw Color
\r
1111 DL_Ypos2 DW ? ; Y pos of last point
\r
1112 DL_Xpos2 DW ? ; X pos of last point
\r
1113 DL_Ypos1 DW ? ; Y pos of first point
\r
1114 DL_Xpos1 DW ? ; X pos of first point
\r
1119 DRAW_LINE PROC FAR
\r
1121 ;PUSHx BP, SI, DI ; Preserve Important Registers
\r
1125 MOV BP, SP ; Set up Stack Frame
\r
1126 CLD ; Direction Flag = Forward
\r
1128 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
1129 MOV CH, [BP].DL_ColorF ; Save Line Color in CH
\r
1133 MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2?
\r
1134 MOV DI, [BP].DL_Xpos2 ; DX = X2
\r
1135 CMP SI, DI ; Is X1 < X2
\r
1136 JE @DL_VLINE ; If X1=X2, Draw Vertical Line
\r
1137 JL @DL_NOSWAP1 ; If X1 < X2, don't swap
\r
1139 XCHG SI, DI ; X2 IS > X1, SO SWAP THEM
\r
1143 ; SI = X1, DI = X2
\r
1145 MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2?
\r
1146 CMP AX, [BP].DL_Ypos2 ; Y1 = Y2?
\r
1147 JE @DL_HORZ ; If so, Draw a Horizontal Line
\r
1149 JMP @DL_BREZHAM ; Diagonal line... go do it...
\r
1151 ; This Code draws a Horizontal Line in Mode X where:
\r
1152 ; SI = X1, DI = X2, and AX = Y1/Y2
\r
1156 MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width
\r
1157 MOV DX, AX ; CX = Line offset into Page
\r
1159 MOV AX, SI ; Get Left edge, Save X1
\r
1160 AND SI, PLANE_BITS ; Mask out Row #
\r
1161 MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1162 MOV CX, DI ; Get Right edge, Save X2
\r
1163 AND DI, PLANE_BITS ; Mask out Row #
\r
1164 MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte
\r
1166 SHR AX, 1 ; Get X1 Byte # (=X1/4)
\r
1167 SHR CX, 1 ; Get X2 Byte # (=X2/4)
\r
1168 SHR AX, 1 ; Get X1 Byte # (=X1/4)
\r
1169 SHR CX, 1 ; Get X2 Byte # (=X2/4)
\r
1171 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1172 ADD DI, DX ; Point to Start of Line
\r
1173 ADD DI, AX ; Point to Pixel X1
\r
1175 SUB CX, AX ; CX = # Of Bands (-1) to set
\r
1176 JNZ @DL_LONGLN ; jump if longer than one segment
\r
1178 AND BL, BH ; otherwise, merge clip masks
\r
1182 OUT_8 SC_Data, BL ; Set the Left Clip Mask
\r
1184 MOV AL, [BP].DL_ColorF ; Get Line Color
\r
1185 MOV BL, AL ; BL = Copy of Line Color
\r
1186 STOSB ; Set Left (1-4) Pixels
\r
1188 JCXZ @DL_EXIT ; Done if only one Line Segment
\r
1190 DEC CX ; CX = # of Middle Segments
\r
1191 JZ @DL_XRSEG ; If no middle segments....
\r
1193 ; Draw Middle Segments
\r
1195 OUT_8 DX, ALL_PLANES ; Write to ALL Planes
\r
1197 MOV AL, BL ; Get Color from BL
\r
1198 REP STOSB ; Draw Middle (4 Pixel) Segments
\r
1201 OUT_8 DX, BH ; Select Planes for Right Clip Mask
\r
1202 MOV AL, BL ; Get Color Value
\r
1203 STOSB ; Draw Right (1-4) Pixels
\r
1205 JMP s @DL_EXIT ; We Are Done...
\r
1208 ; This Code Draws A Vertical Line. On entry:
\r
1209 ; CH = Line Color, SI & DI = X1
\r
1213 MOV AX, [BP].DL_Ypos1 ; AX = Y1
\r
1214 MOV SI, [BP].DL_Ypos2 ; SI = Y2
\r
1215 CMP AX, SI ; Is Y1 < Y2?
\r
1216 JLE @DL_NOSWAP2 ; if so, Don't Swap them
\r
1218 XCHG AX, SI ; Ok, NOW Y1 < Y2
\r
1222 SUB SI, AX ; SI = Line Height (Y2-Y1+1)
\r
1225 ; AX = Y1, DI = X1, Get offset into Page into AX
\r
1227 MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width
\r
1228 MOV DX, DI ; Copy Xpos into DX
\r
1229 SHR DI, 1 ; DI = Xpos/4
\r
1230 SHR DI, 1 ; DI = Xpos/4
\r
1231 ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1
\r
1233 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1234 ADD DI, AX ; Point to Pixel X1, Y1
\r
1238 MOV CL, DL ; CL = Save X1
\r
1239 AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #)
\r
1240 MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1
\r
1241 SHL AH, CL ; Change to Correct Plane #
\r
1242 OUT_16 SC_Index, AX ; Select Plane
\r
1244 MOV AL, CH ; Get Saved Color
\r
1245 MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By
\r
1248 MOV ES:[DI], AL ; Draw Single Pixel
\r
1249 ADD DI, BX ; Point to Next Line
\r
1250 LOOPjz SI, @DL_EXIT ; Lines--, Exit if done
\r
1252 MOV ES:[DI], AL ; Draw Single Pixel
\r
1253 ADD DI, BX ; Point to Next Line
\r
1254 LOOPx SI, @DL_VLoop ; Lines--, Loop until Done
\r
1258 JMP @DL_EXIT2 ; Done!
\r
1260 ; This code Draws a diagonal line in Mode X
\r
1263 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1265 MOV AX, [BP].DL_Ypos1 ; get Y1 value
\r
1266 MOV BX, [BP].DL_Ypos2 ; get Y2 value
\r
1267 MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos
\r
1269 CMP BX, AX ; Y2-Y1 is?
\r
1270 JNC @DL_DeltaYOK ; if Y2>=Y1 then goto...
\r
1272 XCHG BX, AX ; Swap em...
\r
1273 MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos
\r
1276 MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1
\r
1278 ADD DI, AX ; DI -> Start of Line Y1 on Page
\r
1279 MOV AX, CX ; AX = Xpos (X1)
\r
1280 SHR AX, 1 ; /4 = Byte Offset into Line
\r
1281 SHR AX, 1 ; /4 = Byte Offset into Line
\r
1282 ADD DI, AX ; DI = Starting pos (X1,Y1)
\r
1284 MOV AL, 11h ; Staring Mask
\r
1285 AND CL, PLANE_BITS ; Get Plane #
\r
1286 SHL AL, CL ; and shift into place
\r
1287 MOV AH, [BP].DL_ColorF ; Color in Hi Bytes
\r
1289 PUSH AX ; Save Mask,Color...
\r
1291 MOV AH, AL ; Plane # in AH
\r
1292 MOV AL, MAP_MASK ; Select Plane Register
\r
1293 OUT_16 SC_Index, AX ; Select initial plane
\r
1295 MOV AX, [BP].DL_Xpos1 ; get X1 value
\r
1296 MOV BX, [BP].DL_Ypos1 ; get Y1 value
\r
1297 MOV CX, [BP].DL_Xpos2 ; get X2 value
\r
1298 MOV DX, [BP].DL_Ypos2 ; get Y2 value
\r
1300 MOV BP, SCREEN_WIDTH ; Use BP for Line width to
\r
1301 ; to avoid extra memory access
\r
1303 SUB DX, BX ; figure Delta_Y
\r
1304 JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1
\r
1306 ADD BX, DX ; put Y2 into Y1
\r
1307 NEG DX ; abs(Delta_Y)
\r
1308 XCHG AX, CX ; and exchange X1 and X2
\r
1311 MOV BX, 08000H ; seed for fraction accumulator
\r
1313 SUB CX, AX ; figure Delta_X
\r
1314 JC @DL_DrawLeft ; if negative, go left
\r
1316 JMP @DL_DrawRight ; Draw Line that slopes right
\r
1320 NEG CX ; abs(Delta_X)
\r
1322 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1323 JB @DL_SteepLeft ; yes, so go do steep line
\r
1324 ; (Delta_Y iterations)
\r
1326 ; Draw a Shallow line to the left in Mode X
\r
1329 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1330 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1331 SBB DX, 0 ; include carry
\r
1332 DIV CX ; divide by Delta_X
\r
1334 MOV SI, BX ; SI = Accumulator
\r
1335 MOV BX, AX ; BX = Add fraction
\r
1336 POP AX ; Get Color, Bit mask
\r
1337 MOV DX, SC_Data ; Sequence controller data register
\r
1338 INC CX ; Inc Delta_X so we can unroll loop
\r
1340 ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...
\r
1343 MOV ES:[DI], AH ; set first pixel, plane data set up
\r
1344 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1346 ADD SI, BX ; add numerator to accumulator
\r
1347 JNC @DL_SLLL2nc ; move down on carry
\r
1349 ADD DI, BP ; Move Down one line...
\r
1352 DEC DI ; Left one addr
\r
1353 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1354 CMP AL, 87h ; wrap?, if AL <88 then Carry set
\r
1355 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1356 OUT DX, AL ; Set up New Bit Plane mask
\r
1358 MOV ES:[DI], AH ; set pixel
\r
1359 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1361 ADD SI, BX ; add numerator to accumulator,
\r
1362 JNC @DL_SLLL3nc ; move down on carry
\r
1364 ADD DI, BP ; Move Down one line...
\r
1366 @DL_SLLL3nc: ; Now move left a pixel...
\r
1367 DEC DI ; Left one addr
\r
1368 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1369 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1370 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1371 OUT DX, AL ; Set up New Bit Plane mask
\r
1372 JMP s @DL_SLLLoop ; loop until done
\r
1375 JMP @DL_EXIT2 ; and exit
\r
1377 ; Draw a steep line to the left in Mode X
\r
1380 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1381 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1382 DIV CX ; divide by Delta_Y
\r
1384 MOV SI, BX ; SI = Accumulator
\r
1385 MOV BX, AX ; BX = Add Fraction
\r
1386 POP AX ; Get Color, Bit mask
\r
1387 MOV DX, SC_Data ; Sequence controller data register
\r
1388 INC CX ; Inc Delta_Y so we can unroll loop
\r
1390 ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
\r
1394 MOV ES:[DI], AH ; set first pixel
\r
1395 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1397 ADD SI, BX ; add numerator to accumulator
\r
1398 JNC @DL_STLnc2 ; No carry, just move down!
\r
1400 DEC DI ; Move Left one addr
\r
1401 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1402 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1403 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1404 OUT DX, AL ; Set up New Bit Plane mask
\r
1407 ADD DI, BP ; advance to next line.
\r
1409 MOV ES:[DI], AH ; set pixel
\r
1410 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1412 ADD SI, BX ; add numerator to accumulator
\r
1413 JNC @DL_STLnc3 ; No carry, just move down!
\r
1415 DEC DI ; Move Left one addr
\r
1416 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1417 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1418 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1419 OUT DX, AL ; Set up New Bit Plane mask
\r
1422 ADD DI, BP ; advance to next line.
\r
1423 JMP s @DL_STLLoop ; Loop until done
\r
1426 JMP @DL_EXIT2 ; and exit
\r
1428 ; Draw a line that goes to the Right...
\r
1431 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1432 JB @DL_SteepRight ; yes, so go do steep line
\r
1433 ; (Delta_Y iterations)
\r
1435 ; Draw a Shallow line to the Right in Mode X
\r
1438 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1439 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1440 SBB DX, 0 ; include carry
\r
1441 DIV CX ; divide by Delta_X
\r
1443 MOV SI, BX ; SI = Accumulator
\r
1444 MOV BX, AX ; BX = Add Fraction
\r
1445 POP AX ; Get Color, Bit mask
\r
1446 MOV DX, SC_Data ; Sequence controller data register
\r
1447 INC CX ; Inc Delta_X so we can unroll loop
\r
1449 ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...
\r
1452 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1453 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1455 ADD SI, BX ; add numerator to accumulator
\r
1456 JNC @DL_SLR2nc ; don't move down if carry not set
\r
1458 ADD DI, BP ; Move Down one line...
\r
1460 @DL_SLR2nc: ; Now move right a pixel...
\r
1461 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1462 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1463 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1464 OUT DX, AL ; Set up New Bit Plane mask
\r
1466 MOV ES:[DI], AH ; set pixel
\r
1467 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1469 ADD SI, BX ; add numerator to accumulator
\r
1470 JNC @DL_SLR3nc ; don't move down if carry not set
\r
1472 ADD DI, BP ; Move Down one line...
\r
1475 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1476 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1477 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1478 OUT DX, AL ; Set up New Bit Plane mask
\r
1479 JMP s @DL_SLRLoop ; loop till done
\r
1482 JMP @DL_EXIT2 ; and exit
\r
1484 ; Draw a Steep line to the Right in Mode X
\r
1487 mov ax,0 ; zero low word of Delta_Y * 10000h
\r
1488 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1489 DIV CX ; divide by Delta_Y
\r
1491 MOV SI, BX ; SI = Accumulator
\r
1492 MOV BX, AX ; BX = Add Fraction
\r
1493 POP AX ; Get Color, Bit mask
\r
1494 MOV DX, SC_Data ; Sequence controller data register
\r
1495 INC CX ; Inc Delta_Y so we can unroll loop
\r
1497 ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
\r
1500 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1501 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1503 ADD SI, BX ; add numerator to accumulator
\r
1504 JNC @STRnc2 ; if no carry then just go down...
\r
1506 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1507 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1508 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1509 OUT DX, AL ; Set up New Bit Plane mask
\r
1512 ADD DI, BP ; advance to next line.
\r
1514 MOV ES:[DI], AH ; set pixel
\r
1515 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1517 ADD SI, BX ; add numerator to accumulator
\r
1518 JNC @STRnc3 ; if no carry then just go down...
\r
1520 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1521 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1522 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1523 OUT DX, AL ; Set up New Bit Plane mask
\r
1526 ADD DI, BP ; advance to next line.
\r
1527 JMP s @STRLoop ; loop till done
\r
1530 ;POPx DI, SI, BP ; Restore Saved Registers
\r
1534 RET 10 ; Exit and Clean up Stack
\r
1539 ; ===== DAC COLOR REGISTER ROUTINES =====
\r
1541 ;=================================================
\r
1542 ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)
\r
1543 ;=================================================
\r
1545 ; Sets a single (RGB) Vga Palette Register
\r
1547 ; ENTRY: Register = The DAC # to modify (0-255)
\r
1548 ; Red = The new Red Intensity (0-63)
\r
1549 ; Green = The new Green Intensity (0-63)
\r
1550 ; Blue = The new Blue Intensity (0-63)
\r
1552 ; EXIT: No meaningful values returned
\r
1558 SDR_Blue DB ?,? ; Blue Data Value
\r
1559 SDR_Green DB ?,? ; Green Data Value
\r
1560 SDR_Red DB ?,? ; Red Data Value
\r
1561 SDR_Register DB ?,? ; Palette Register #
\r
1564 PUBLIC SET_DAC_REGISTER
\r
1566 SET_DAC_REGISTER PROC FAR
\r
1569 MOV BP, SP ; Set up Stack Frame
\r
1571 ; Select which DAC Register to modify
\r
1573 OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register
\r
1575 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1576 OUT_8 DX, [BP].SDR_Red ; Set Red Intensity
\r
1577 OUT_8 DX, [BP].SDR_Green ; Set Green Intensity
\r
1578 OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity
\r
1580 POP BP ; Restore Registers
\r
1581 RET 8 ; Exit & Clean Up Stack
\r
1583 SET_DAC_REGISTER ENDP
\r
1585 ;====================================================
\r
1586 ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)
\r
1587 ;====================================================
\r
1589 ; Reads the RGB Values of a single Vga Palette Register
\r
1591 ; ENTRY: Register = The DAC # to read (0-255)
\r
1592 ; Red = Offset to Red Variable in DS
\r
1593 ; Green = Offset to Green Variable in DS
\r
1594 ; Blue = Offset to Blue Variable in DS
\r
1596 ; EXIT: The values of the integer variables Red,
\r
1597 ; Green, and Blue are set to the values
\r
1598 ; taken from the specified DAC register.
\r
1604 GDR_Blue DW ? ; Addr of Blue Data Value in DS
\r
1605 GDR_Green DW ? ; Addr of Green Data Value in DS
\r
1606 GDR_Red DW ? ; Addr of Red Data Value in DS
\r
1607 GDR_Register DB ?,? ; Palette Register #
\r
1610 PUBLIC GET_DAC_REGISTER
\r
1612 GET_DAC_REGISTER PROC FAR
\r
1615 MOV BP, SP ; Set up Stack Frame
\r
1617 ; Select which DAC Register to read in
\r
1619 OUT_8 DAC_READ_ADDR, [BP].GDR_Register
\r
1621 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1622 mov ax,0 ; Clear AX
\r
1624 IN AL, DX ; Read Red Value
\r
1625 MOV BX, [BP].GDR_Red ; Get Address of Red%
\r
1626 MOV [BX], AX ; *Red% = AX
\r
1628 IN AL, DX ; Read Green Value
\r
1629 MOV BX, [BP].GDR_Green ; Get Address of Green%
\r
1630 MOV [BX], AX ; *Green% = AX
\r
1632 IN AL, DX ; Read Blue Value
\r
1633 MOV BX, [BP].GDR_Blue ; Get Address of Blue%
\r
1634 MOV [BX], AX ; *Blue% = AX
\r
1636 POP BP ; Restore Registers
\r
1637 RET 8 ; Exit & Clean Up Stack
\r
1639 GET_DAC_REGISTER ENDP
\r
1642 ;===========================================================
\r
1643 ;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%)
\r
1644 ;===========================================================
\r
1646 ; Sets a Block of Vga Palette Registers
\r
1648 ; ENTRY: PalData = Far Pointer to Block of palette data
\r
1649 ; StartReg = First Register # in range to set (0-255)
\r
1650 ; EndReg = Last Register # in Range to set (0-255)
\r
1651 ; Sync = Wait for Vertical Retrace Flag (Boolean)
\r
1653 ; EXIT: No meaningful values returned
\r
1655 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1656 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1660 DW ?x1 ; BP, DS, SI
\r
1661 DW ?x1 ; BP, DS, SI
\r
1662 DW ?x1 ; BP, DS, SI
\r
1664 LDR_Sync DW ? ; Vertical Sync Flag
\r
1665 LDR_EndReg DB ?,? ; Last Register #
\r
1666 LDR_StartReg DB ?,? ; First Register #
\r
1667 LDR_PalData DD ? ; Far Ptr to Palette Data
\r
1670 PUBLIC LOAD_DAC_REGISTERS
\r
1672 LOAD_DAC_REGISTERS PROC FAR
\r
1674 ;PUSHx BP, DS, SI ; Save Registers
\r
1678 mov BP, SP ; Set up Stack Frame
\r
1680 mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag
\r
1681 or AX, AX ; is Sync Flag = 0?
\r
1682 jz @LDR_Load ; if so, skip call
\r
1684 call f SYNC_DISPLAY ; wait for vsync
\r
1686 ; Determine register #'s, size to copy, etc
\r
1690 lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data
\r
1691 mov DX, DAC_WRITE_ADDR ; DAC register # selector
\r
1693 mov ax,0, BX ; Clear for byte loads
\r
1694 mov AL, [BP].LDR_StartReg ; Get Start Register
\r
1695 mov BL, [BP].LDR_EndReg ; Get End Register
\r
1697 sub BX, AX ; BX = # of DAC registers -1
\r
1698 inc BX ; BX = # of DAC registers
\r
1699 mov CX, BX ; CX = # of DAC registers
\r
1700 add CX, BX ; CX = " " * 2
\r
1701 add CX, BX ; CX = " " * 3
\r
1702 cld ; Block OUTs forward
\r
1703 out DX, AL ; set up correct register #
\r
1705 ; Load a block of DAC Registers
\r
1707 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1709 ;rep outsb ; block set DAC registers
\r
1711 ;POPx SI, DS, BP ; Restore Registers
\r
1715 ret 10 ; Exit & Clean Up Stack
\r
1717 LOAD_DAC_REGISTERS ENDP
\r
1720 ;====================================================
\r
1721 ;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%)
\r
1722 ;====================================================
\r
1724 ; Reads a Block of Vga Palette Registers
\r
1726 ; ENTRY: PalData = Far Pointer to block to store palette data
\r
1727 ; StartReg = First Register # in range to read (0-255)
\r
1728 ; EndReg = Last Register # in Range to read (0-255)
\r
1730 ; EXIT: No meaningful values returned
\r
1732 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1733 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1737 DW ?x1 ; BP, ES, DI
\r
1738 DW ?x1 ; BP, ES, DI
\r
1739 DW ?x1 ; BP, ES, DI
\r
1741 RDR_EndReg DB ?,? ; Last Register #
\r
1742 RDR_StartReg DB ?,? ; First Register #
\r
1743 RDR_PalData DD ? ; Far Ptr to Palette Data
\r
1746 PUBLIC READ_DAC_REGISTERS
\r
1748 READ_DAC_REGISTERS PROC FAR
\r
1750 ;PUSHx BP, ES, DI ; Save Registers
\r
1754 mov BP, SP ; Set up Stack Frame
\r
1756 ; Determine register #'s, size to copy, etc
\r
1758 les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer
\r
1759 mov DX, DAC_READ_ADDR ; DAC register # selector
\r
1761 mov ax,0, BX ; Clear for byte loads
\r
1762 mov AL, [BP].RDR_StartReg ; Get Start Register
\r
1763 mov BL, [BP].RDR_EndReg ; Get End Register
\r
1765 sub BX, AX ; BX = # of DAC registers -1
\r
1766 inc BX ; BX = # of DAC registers
\r
1767 mov CX, BX ; CX = # of DAC registers
\r
1768 add CX, BX ; CX = " " * 2
\r
1769 add CX, BX ; CX = " " * 3
\r
1770 cld ; Block INs forward
\r
1772 ; Read a block of DAC Registers
\r
1774 out DX, AL ; set up correct register #
\r
1775 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1777 ;rep insb ; block read DAC registers
\r
1779 ;POPx DI, ES, BP ; Restore Registers
\r
1783 ret 8 ; Exit & Clean Up Stack
\r
1785 READ_DAC_REGISTERS ENDP
\r
1788 ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====
\r
1790 ;=========================
\r
1791 ;SET_ACTIVE_PAGE (PageNo%)
\r
1792 ;=========================
\r
1794 ; Sets the active display Page to be used for future drawing
\r
1796 ; ENTRY: PageNo = Display Page to make active
\r
1797 ; (values: 0 to Number of Pages - 1)
\r
1799 ; EXIT: No meaningful values returned
\r
1805 SAP_Page DW ? ; Page # for Drawing
\r
1808 PUBLIC SET_ACTIVE_PAGE
\r
1810 SET_ACTIVE_PAGE PROC FAR
\r
1812 PUSH BP ; Preserve Registers
\r
1813 MOV BP, SP ; Set up Stack Frame
\r
1815 MOV BX, [BP].SAP_Page ; Get Desired Page #
\r
1816 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1817 JAE @SAP_Exit ; IF Not, Do Nothing
\r
1819 MOV ACTIVE_PAGE, BX ; Set Active Page #
\r
1821 SHL BX, 1 ; Scale Page # to Word
\r
1822 MOV AX, PAGE_ADDR[BX] ; Get offset to Page
\r
1824 MOV CURRENT_PAGE, AX ; And set for future LES's
\r
1827 POP BP ; Restore Registers
\r
1828 RET 2 ; Exit and Clean up Stack
\r
1830 SET_ACTIVE_PAGE ENDP
\r
1837 ; Returns the Video Page # currently used for Drawing
\r
1839 ; ENTRY: No Parameters are passed
\r
1841 ; EXIT: AX = Current Video Page used for Drawing
\r
1844 PUBLIC GET_ACTIVE_PAGE
\r
1846 GET_ACTIVE_PAGE PROC FAR
\r
1848 MOV AX, ACTIVE_PAGE ; Get Active Page #
\r
1849 RET ; Exit and Clean up Stack
\r
1851 GET_ACTIVE_PAGE ENDP
\r
1854 ;===============================
\r
1855 ;SET_DISPLAY_PAGE (DisplayPage%)
\r
1856 ;===============================
\r
1858 ; Sets the currently visible display page.
\r
1859 ; When called this routine syncronizes the display
\r
1860 ; to the vertical blank.
\r
1862 ; ENTRY: PageNo = Display Page to show on the screen
\r
1863 ; (values: 0 to Number of Pages - 1)
\r
1865 ; EXIT: No meaningful values returned
\r
1871 SDP_Page DW ? ; Page # to Display...
\r
1874 PUBLIC SET_DISPLAY_PAGE
\r
1876 SET_DISPLAY_PAGE PROC FAR
\r
1878 PUSH BP ; Preserve Registers
\r
1879 MOV BP, SP ; Set up Stack Frame
\r
1881 MOV BX, [BP].SDP_Page ; Get Desired Page #
\r
1882 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1883 JAE @SDP_Exit ; IF Not, Do Nothing
\r
1885 MOV DISPLAY_PAGE, BX ; Set Display Page #
\r
1887 SHL BX, 1 ; Scale Page # to Word
\r
1888 MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page
\r
1889 ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling
\r
1891 ; Wait if we are currently in a Vertical Retrace
\r
1893 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1896 IN AL, DX ; Get VGA status
\r
1897 AND AL, VERT_RETRACE ; In Display mode yet?
\r
1898 JNZ @DP_WAIT0 ; If Not, wait for it
\r
1900 ; Set the Start Display Address to the new page
\r
1902 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
1904 MOV AL, START_DISP_LO ; Display Start Low Register
\r
1905 MOV AH, CL ; Low 8 Bits of Start Addr
\r
1906 OUT DX, AX ; Set Display Addr Low
\r
1908 MOV AL, START_DISP_HI ; Display Start High Register
\r
1909 MOV AH, CH ; High 8 Bits of Start Addr
\r
1910 OUT DX, AX ; Set Display Addr High
\r
1912 ; Wait for a Vertical Retrace to smooth out things
\r
1914 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1917 IN AL, DX ; Get VGA status
\r
1918 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
1919 JZ @DP_WAIT1 ; If Not, wait for it
\r
1921 ; Now Set Display Starting Address
\r
1925 POP BP ; Restore Registers
\r
1926 RET 2 ; Exit and Clean up Stack
\r
1928 SET_DISPLAY_PAGE ENDP
\r
1931 ;=================
\r
1932 ;GET_DISPLAY_PAGE%
\r
1933 ;=================
\r
1935 ; Returns the Video Page # currently displayed
\r
1937 ; ENTRY: No Parameters are passed
\r
1939 ; EXIT: AX = Current Video Page being displayed
\r
1942 PUBLIC GET_DISPLAY_PAGE
\r
1944 GET_DISPLAY_PAGE PROC FAR
\r
1946 MOV AX, DISPLAY_PAGE ; Get Display Page #
\r
1947 RET ; Exit & Clean Up Stack
\r
1949 GET_DISPLAY_PAGE ENDP
\r
1952 ;=======================================
\r
1953 ;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)
\r
1954 ;=======================================
\r
1956 ; Since a Logical Screen can be larger than the Physical
\r
1957 ; Screen, Scrolling is possible. This routine sets the
\r
1958 ; Upper Left Corner of the Screen to the specified Pixel.
\r
1959 ; Also Sets the Display page to simplify combined page
\r
1960 ; flipping and scrolling. When called this routine
\r
1961 ; syncronizes the display to the vertical blank.
\r
1963 ; ENTRY: DisplayPage = Display Page to show on the screen
\r
1964 ; Xpos = # of pixels to shift screen right
\r
1965 ; Ypos = # of lines to shift screen down
\r
1967 ; EXIT: No meaningful values returned
\r
1973 SW_Ypos DW ? ; Y pos of UL Screen Corner
\r
1974 SW_Xpos DW ? ; X pos of UL Screen Corner
\r
1975 SW_Page DW ? ; (new) Display Page
\r
1980 SET_WINDOW PROC FAR
\r
1982 PUSH BP ; Preserve Registers
\r
1983 MOV BP, SP ; Set up Stack Frame
\r
1985 ; Check if our Scroll Offsets are Valid
\r
1987 MOV BX, [BP].SW_Page ; Get Desired Page #
\r
1988 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1989 JAE @SW_Exit ; IF Not, Do Nothing
\r
1991 MOV AX, [BP].SW_Ypos ; Get Desired Y Offset
\r
1992 CMP AX, MAX_YOFFSET ; Is it Within Limits?
\r
1993 JA @SW_Exit ; if not, exit
\r
1995 MOV CX, [BP].SW_Xpos ; Get Desired X Offset
\r
1996 CMP CX, MAX_XOFFSET ; Is it Within Limits?
\r
1997 JA @SW_Exit ; if not, exit
\r
1999 ; Compute proper Display start address to use
\r
2001 MUL SCREEN_WIDTH ; AX = YOffset * Line Width
\r
2002 SHR CX, 1 ; CX / 4 = Bytes into Line
\r
2003 SHR CX, 1 ; CX / 4 = Bytes into Line
\r
2004 ADD AX, CX ; AX = Offset of Upper Left Pixel
\r
2006 MOV CURRENT_MOFFSET, AX ; Save Offset Info
\r
2008 MOV DISPLAY_PAGE, BX ; Set Current Page #
\r
2009 SHL BX, 1 ; Scale Page # to Word
\r
2010 ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page
\r
2011 MOV BX, AX ; BX = Desired Display Start
\r
2013 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2015 ; Wait if we are currently in a Vertical Retrace
\r
2018 IN AL, DX ; Get VGA status
\r
2019 AND AL, VERT_RETRACE ; In Display mode yet?
\r
2020 JNZ @SW_WAIT0 ; If Not, wait for it
\r
2022 ; Set the Start Display Address to the new window
\r
2024 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
2025 MOV AL, START_DISP_LO ; Display Start Low Register
\r
2026 MOV AH, BL ; Low 8 Bits of Start Addr
\r
2027 OUT DX, AX ; Set Display Addr Low
\r
2029 MOV AL, START_DISP_HI ; Display Start High Register
\r
2030 MOV AH, BH ; High 8 Bits of Start Addr
\r
2031 OUT DX, AX ; Set Display Addr High
\r
2033 ; Wait for a Vertical Retrace to smooth out things
\r
2035 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2038 IN AL, DX ; Get VGA status
\r
2039 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
2040 JZ @SW_WAIT1 ; If Not, wait for it
\r
2042 ; Now Set the Horizontal Pixel Pan values
\r
2044 OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register
\r
2046 MOV AX, [BP].SW_Xpos ; Get Desired X Offset
\r
2047 AND AL, 03 ; Get # of Pixels to Pan (0-3)
\r
2048 SHL AL, 1 ; Shift for 256 Color Mode
\r
2049 OUT DX, AL ; Fine tune the display!
\r
2052 POP BP ; Restore Saved Registers
\r
2053 RET 6 ; Exit and Clean up Stack
\r
2062 ; Returns the X coordinate of the Pixel currently display
\r
2063 ; in the upper left corner of the display
\r
2065 ; ENTRY: No Parameters are passed
\r
2067 ; EXIT: AX = Current Horizontal Scroll Offset
\r
2070 PUBLIC GET_X_OFFSET
\r
2072 GET_X_OFFSET PROC FAR
\r
2074 MOV AX, CURRENT_XOFFSET ; Get current horz offset
\r
2075 RET ; Exit & Clean Up Stack
\r
2084 ; Returns the Y 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 Vertical Scroll Offset
\r
2092 PUBLIC GET_Y_OFFSET
\r
2094 GET_Y_OFFSET PROC FAR
\r
2096 MOV AX, CURRENT_YOFFSET ; Get current vertical offset
\r
2097 RET ; Exit & Clean Up Stack
\r
2106 ; Pauses the computer until the next Vertical Retrace starts
\r
2108 ; ENTRY: No Parameters are passed
\r
2110 ; EXIT: No meaningful values returned
\r
2113 PUBLIC SYNC_DISPLAY
\r
2115 SYNC_DISPLAY PROC FAR
\r
2117 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2119 ; Wait for any current retrace to end
\r
2122 IN AL, DX ; Get VGA status
\r
2123 AND AL, VERT_RETRACE ; In Display mode yet?
\r
2124 JNZ @SD_WAIT0 ; If Not, wait for it
\r
2126 ; Wait for the start of the next vertical retrace
\r
2129 IN AL, DX ; Get VGA status
\r
2130 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
2131 JZ @SD_WAIT1 ; If Not, wait for it
\r
2133 RET ; Exit & Clean Up Stack
\r
2138 ; ===== TEXT DISPLAY ROUTINES =====
\r
2140 ;==================================================
\r
2141 ;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2142 ;==================================================
\r
2144 ; Draws an ASCII Text Character using the currently selected
\r
2145 ; 8x8 font on the active display page. It would be a simple
\r
2146 ; exercise to make this routine process variable height fonts.
\r
2148 ; ENTRY: CharNum = ASCII character # to draw
\r
2149 ; Xpos = X position to draw Character at
\r
2150 ; Ypos = Y position of to draw Character at
\r
2151 ; ColorF = Color to draw text character in
\r
2152 ; ColorB = Color to set background to
\r
2154 ; EXIT: No meaningful values returned
\r
2158 GPC_Width DW ? ; Screen Width-1
\r
2159 GPC_Lines DB ?,? ; Scan lines to Decode
\r
2160 GPC_T_SETS DW ? ; Saved Charset Segment
\r
2161 GPC_T_SETO DW ? ; Saved Charset Offset
\r
2162 DW ?x1 ; DI, SI, DS, BP
\r
2163 DW ?x1 ; DS, DI, SI, BP
\r
2164 DW ?x1 ; DS, DI, SI, BP
\r
2165 DW ?x1 ; DS, DI, SI, BP
\r
2167 GPC_ColorB DB ?,? ; Background Color
\r
2168 GPC_ColorF DB ?,? ; Text Color
\r
2169 GPC_Ypos DW ? ; Y Position to Print at
\r
2170 GPC_Xpos DW ? ; X position to Print at
\r
2171 GPC_Char DB ?,? ; Character to Print
\r
2178 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2183 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2184 MOV BP, SP ; Set up Stack Frame
\r
2186 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2188 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2189 MOV BX, AX ; BX = Screen Width
\r
2190 DEC BX ; = Screen Width-1
\r
2191 MOV [BP].GPC_Width, BX ; Save for later use
\r
2193 MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width
\r
2194 ADD DI, AX ; DI -> Start of Line Ypos
\r
2196 MOV AX, [BP].GPC_Xpos ; Get Xpos of Character
\r
2197 MOV CX, AX ; Save Copy of Xpos
\r
2198 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2199 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2200 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2202 ;Get Source ADDR of Character Bit Map & Save
\r
2204 MOV AL, [BP].GPC_Char ; Get Character #
\r
2205 TEST AL, 080h ; Is Hi Bit Set?
\r
2206 JZ @GPC_LowChar ; Nope, use low char set ptr
\r
2208 AND AL, 07Fh ; Mask Out Hi Bit
\r
2209 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2210 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2211 JMP s @GPC_Set_Char ; Go Setup Character Ptr
\r
2215 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2216 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2219 MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack
\r
2221 MOV AH, 0 ; Valid #'s are 0..127
\r
2222 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2223 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2224 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2225 ADD BX, AX ; BX = Offset of Selected char
\r
2226 MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack
\r
2228 AND CX, PLANE_BITS ; Get Plane #
\r
2229 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2230 SHL CH, CL ; And shift into position
\r
2231 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2233 MOV AL, 04 ; 4-Plane # = # of initial
\r
2234 SUB AL, CL ; shifts to align bit mask
\r
2235 MOV CL, AL ; Shift Count for SHL
\r
2237 ;Get segment of character map
\r
2239 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2240 INC DX ; DX -> SC_Data
\r
2242 MOV AL, 08 ; 8 Lines to Process
\r
2243 MOV [BP].GPC_Lines, AL ; Save on Stack
\r
2245 MOV DS, [BP].GPC_T_SETS ; Point to character set
\r
2247 @GPC_DECODE_CHAR_BYTE:
\r
2249 MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String
\r
2251 MOV BH, [SI] ; Get Bit Map
\r
2252 INC SI ; Point to Next Line
\r
2253 MOV [BP].GPC_T_SETO, SI ; And save new Pointer...
\r
2255 mov ax,0 ; Clear AX
\r
2257 ;mov bl,0 ; Clear BL
\r
2259 ROL BX, CL ; BL holds left edge bits
\r
2260 MOV SI, BX ; Use as Table Index
\r
2261 AND SI, CHAR_BITS ; Get Low Bits
\r
2262 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2263 JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2265 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2266 OUT DX, AL ; Set up Screen Mask
\r
2267 MOV ES:[DI], AH ; Write Foreground color
\r
2269 @GPC_NO_LEFT1BITS:
\r
2270 XOR AL, CH ; Invert mask for Background
\r
2271 JZ @GPC_NO_LEFT0BITS ; Hey, no need for this
\r
2273 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2274 OUT DX, AL ; Set up Screen Mask
\r
2275 MOV ES:[DI], AH ; Write Foreground color
\r
2277 ;Now Do Middle/Last Band
\r
2279 @GPC_NO_LEFT0BITS:
\r
2280 INC DI ; Point to next Byte
\r
2281 ROL BX, 1 ; Shift 4 bits
\r
2282 ROL BX, 1 ; Shift 4 bits
\r
2283 ROL BX, 1 ; Shift 4 bits
\r
2284 ROL BX, 1 ; Shift 4 bits
\r
2286 MOV SI, BX ; Make Lookup Pointer
\r
2287 AND SI, CHAR_BITS ; Get Low Bits
\r
2288 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2289 JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2291 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2292 OUT DX, AL ; Set up Screen Mask
\r
2293 MOV ES:[DI], AH ; Write Foreground color
\r
2295 @GPC_NO_MIDDLE1BITS:
\r
2296 XOR AL, ALL_PLANES ; Invert mask for Background
\r
2297 JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this
\r
2299 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2300 OUT DX, AL ; Set up Screen Mask
\r
2301 MOV ES:[DI], AH ; Write Foreground color
\r
2303 @GPC_NO_MIDDLE0BITS:
\r
2304 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2305 CMP CL, 4 ; Aligned by 4?
\r
2306 JZ @GPC_NEXT_LINE ; If so, Exit now..
\r
2308 INC DI ; Point to next Byte
\r
2309 ROL BX, 1 ; Shift 4 bits
\r
2310 ROL BX, 1 ; Shift 4 bits
\r
2311 ROL BX, 1 ; Shift 4 bits
\r
2312 ROL BX, 1 ; Shift 4 bits
\r
2314 MOV SI, BX ; Make Lookup Pointer
\r
2315 AND SI, CHAR_BITS ; Get Low Bits
\r
2316 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2317 JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2319 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2320 OUT DX, AL ; Set up Screen Mask
\r
2321 MOV ES:[DI], AH ; Write Foreground color
\r
2323 @GPC_NO_RIGHT1BITS:
\r
2325 XOR AL, CH ; Invert mask for Background
\r
2326 JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this
\r
2328 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2329 OUT DX, AL ; Set up Screen Mask
\r
2330 MOV ES:[DI], AH ; Write Foreground color
\r
2332 @GPC_NO_RIGHT0BITS:
\r
2333 DEC DI ; Adjust for Next Line Advance
\r
2336 ADD DI, [BP].GPC_Width ; Point to Next Line
\r
2337 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2339 DEC [BP].GPC_Lines ; Count Down Lines
\r
2340 JZ @GPC_EXIT ; Ok... Done!
\r
2342 JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey!
\r
2345 ADD SP, 08 ; Deallocate stack workspace
\r
2346 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2351 RET 10 ; Exit and Clean up Stack
\r
2356 ;==========================================
\r
2357 ;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)
\r
2358 ;==========================================
\r
2360 ; Transparently draws an ASCII Text Character using the
\r
2361 ; currently selected 8x8 font on the active display page.
\r
2363 ; ENTRY: CharNum = ASCII character # to draw
\r
2364 ; Xpos = X position to draw Character at
\r
2365 ; Ypos = Y position of to draw Character at
\r
2366 ; ColorF = Color to draw text character in
\r
2368 ; EXIT: No meaningful values returned
\r
2372 TGP_Width DW ? ; Screen Width-1
\r
2373 TGP_Lines DB ?,? ; Scan lines to Decode
\r
2374 TGP_T_SETS DW ? ; Saved Charset Segment
\r
2375 TGP_T_SETO DW ? ; Saved Charset Offset
\r
2376 DW ?x1 ; DI, SI, DS, BP
\r
2377 DW ?x1 ; DS, DI, SI, BP
\r
2378 DW ?x1 ; DS, DI, SI, BP
\r
2379 DW ?x1 ; DS, DI, SI, BP
\r
2381 TGP_ColorF DB ?,? ; Text Color
\r
2382 TGP_Ypos DW ? ; Y Position to Print at
\r
2383 TGP_Xpos DW ? ; X position to Print at
\r
2384 TGP_Char DB ?,? ; Character to Print
\r
2391 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2396 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2397 MOV BP, SP ; Set up Stack Frame
\r
2399 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2401 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2402 MOV BX, AX ; BX = Screen Width
\r
2403 DEC BX ; = Screen Width-1
\r
2404 MOV [BP].TGP_Width, BX ; Save for later use
\r
2406 MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width
\r
2407 ADD DI, AX ; DI -> Start of Line Ypos
\r
2409 MOV AX, [BP].TGP_Xpos ; Get Xpos of Character
\r
2410 MOV CX, AX ; Save Copy of Xpos
\r
2411 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2412 SHR AX, 1 ; Bytes into Line = Xpos/4
\r
2413 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2415 ;Get Source ADDR of Character Bit Map & Save
\r
2417 MOV AL, [BP].TGP_Char ; Get Character #
\r
2418 TEST AL, 080h ; Is Hi Bit Set?
\r
2419 JZ @TGP_LowChar ; Nope, use low char set ptr
\r
2421 AND AL, 07Fh ; Mask Out Hi Bit
\r
2422 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2423 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2424 JMP s @TGP_Set_Char ; Go Setup Character Ptr
\r
2428 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2429 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2432 MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack
\r
2434 MOV AH, 0 ; Valid #'s are 0..127
\r
2435 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2436 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2437 SHL AX, 1 ; * 8 Bytes Per Bitmap
\r
2438 ADD BX, AX ; BX = Offset of Selected char
\r
2439 MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack
\r
2441 AND CX, PLANE_BITS ; Get Plane #
\r
2442 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2443 SHL CH, CL ; And shift into position
\r
2444 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2446 MOV AL, 04 ; 4-Plane # = # of initial
\r
2447 SUB AL, CL ; shifts to align bit mask
\r
2448 MOV CL, AL ; Shift Count for SHL
\r
2450 ;Get segment of character map
\r
2452 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2453 INC DX ; DX -> SC_Data
\r
2455 MOV AL, 08 ; 8 Lines to Process
\r
2456 MOV [BP].TGP_Lines, AL ; Save on Stack
\r
2458 MOV DS, [BP].TGP_T_SETS ; Point to character set
\r
2460 @TGP_DECODE_CHAR_BYTE:
\r
2462 MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String
\r
2464 MOV BH, [SI] ; Get Bit Map
\r
2465 INC SI ; Point to Next Line
\r
2466 MOV [BP].TGP_T_SETO, SI ; And save new Pointer...
\r
2468 MOV AH, [BP].TGP_ColorF ; Get Foreground Color
\r
2470 mov bl,0 ; Clear BL
\r
2471 ROL BX, CL ; BL holds left edge bits
\r
2472 MOV SI, BX ; Use as Table Index
\r
2473 AND SI, CHAR_BITS ; Get Low Bits
\r
2474 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2475 JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2477 OUT DX, AL ; Set up Screen Mask
\r
2478 MOV ES:[DI], AH ; Write Foreground color
\r
2480 ;Now Do Middle/Last Band
\r
2482 @TGP_NO_LEFT1BITS:
\r
2484 INC DI ; Point to next Byte
\r
2485 ROL BX, 1 ; Shift 4 bits
\r
2486 ROL BX, 1 ; Shift 4 bits
\r
2487 ROL BX, 1 ; Shift 4 bits
\r
2488 ROL BX, 1 ; Shift 4 bits
\r
2490 MOV SI, BX ; Make Lookup Pointer
\r
2491 AND SI, CHAR_BITS ; Get Low Bits
\r
2492 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2493 JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2495 OUT DX, AL ; Set up Screen Mask
\r
2496 MOV ES:[DI], AH ; Write Foreground color
\r
2498 @TGP_NO_MIDDLE1BITS:
\r
2499 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2500 CMP CL, 4 ; Aligned by 4?
\r
2501 JZ @TGP_NEXT_LINE ; If so, Exit now..
\r
2503 INC DI ; Point to next Byte
\r
2504 ROL BX, 1 ; Shift 4 bits
\r
2505 ROL BX, 1 ; Shift 4 bits
\r
2506 ROL BX, 1 ; Shift 4 bits
\r
2507 ROL BX, 1 ; Shift 4 bits
\r
2509 MOV SI, BX ; Make Lookup Pointer
\r
2510 AND SI, CHAR_BITS ; Get Low Bits
\r
2511 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2512 JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2514 OUT DX, AL ; Set up Screen Mask
\r
2515 MOV ES:[DI], AH ; Write Foreground color
\r
2517 @TGP_NO_RIGHT1BITS:
\r
2519 DEC DI ; Adjust for Next Line Advance
\r
2522 ADD DI, [BP].TGP_Width ; Point to Next Line
\r
2523 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2525 DEC [BP].TGP_Lines ; Count Down Lines
\r
2526 JZ @TGP_EXIT ; Ok... Done!
\r
2528 JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey!
\r
2531 ADD SP, 08 ; Deallocate stack workspace
\r
2532 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2537 RET 8 ; Exit and Clean up Stack
\r
2542 ;===============================================================
\r
2543 ;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2544 ;===============================================================
\r
2546 ; Routine to quickly Print a null terminated ASCII string on the
\r
2547 ; active display page up to a maximum length.
\r
2549 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2550 ; MaxLen = # of characters to print if no null found
\r
2551 ; Xpos = X position to draw Text at
\r
2552 ; Ypos = Y position of to draw Text at
\r
2553 ; ColorF = Color to draw text in
\r
2554 ; ColorB = Color to set background to
\r
2556 ; EXIT: No meaningful values returned
\r
2560 DW ?x1 ; DI, SI, DS, BP
\r
2561 DW ?x1 ; DI, SI, DS, BP
\r
2562 DW ?x1 ; DS, DI, SI, BP
\r
2563 DW ?x1 ; DS, DI, SI, BP
\r
2565 PS_ColorB DW ? ; Background Color
\r
2566 PS_ColorF DW ? ; Text Color
\r
2567 PS_Ypos DW ? ; Y Position to Print at
\r
2568 PS_Xpos DW ? ; X position to Print at
\r
2569 PS_Len DW ? ; Maximum Length of string to print
\r
2570 PS_Text DW ?,? ; Far Ptr to Text String
\r
2575 PRINT_STR PROC FAR
\r
2577 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2582 MOV BP, SP ; Set up Stack Frame
\r
2586 MOV CX, [BP].PS_Len ; Get Remaining text Length
\r
2587 JCXZ @PS_Exit ; Exit when out of text
\r
2589 LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text
\r
2590 MOV AL, ES:[DI] ; AL = Text Character
\r
2591 AND AX, 00FFh ; Clear High Word
\r
2592 JZ @PS_Exit ; Exit if null character
\r
2594 DEC [BP].PS_Len ; Remaining Text length--
\r
2595 INC [BP].PS_Text ; Point to Next text char
\r
2597 ; Set up Call to GPRINTC
\r
2599 PUSH AX ; Set Character Parameter
\r
2600 MOV BX, [BP].PS_Xpos ; Get Xpos
\r
2601 PUSH BX ; Set Xpos Parameter
\r
2602 ADD BX, 8 ; Advance 1 Char to Right
\r
2603 MOV [BP].PS_Xpos, BX ; Save for next time through
\r
2605 MOV BX, [BP].PS_Ypos ; Get Ypos
\r
2606 PUSH BX ; Set Ypos Parameter
\r
2608 MOV BX, [BP].PS_ColorF ; Get Text Color
\r
2609 PUSH BX ; Set ColorF Parameter
\r
2611 MOV BX, [BP].PS_ColorB ; Get Background Color
\r
2612 PUSH BX ; Set ColorB Parameter
\r
2614 CALL f GPRINTC ; Print Character!
\r
2615 JMP s @PS_Print_It ; Process next character
\r
2618 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2623 RET 14 ; Exit and Clean up Stack
\r
2628 ;================================================================
\r
2629 ;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2630 ;================================================================
\r
2632 ; Routine to quickly transparently Print a null terminated ASCII
\r
2633 ; string on the active display page up to a maximum length.
\r
2635 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2636 ; MaxLen = # of characters to print if no null found
\r
2637 ; Xpos = X position to draw Text at
\r
2638 ; Ypos = Y position of to draw Text at
\r
2639 ; ColorF = Color to draw text in
\r
2641 ; EXIT: No meaningful values returned
\r
2645 DW ?x1 ; DI, SI, DS, BP
\r
2646 DW ?x1 ; DI, SI, DS, BP
\r
2647 DW ?x1 ; DS, DI, SI, BP
\r
2648 DW ?x1 ; DS, DI, SI, BP
\r
2650 TPS_ColorF DW ? ; Text Color
\r
2651 TPS_Ypos DW ? ; Y Position to Print at
\r
2652 TPS_Xpos DW ? ; X position to Print at
\r
2653 TPS_Len DW ? ; Maximum Length of string to print
\r
2654 TPS_Text DW ?,? ; Far Ptr to Text String
\r
2659 TPRINT_STR PROC FAR
\r
2661 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2666 MOV BP, SP ; Set up Stack Frame
\r
2670 MOV CX, [BP].TPS_Len ; Get Remaining text Length
\r
2671 JCXZ @TPS_Exit ; Exit when out of text
\r
2673 LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text
\r
2674 MOV AL, ES:[DI] ; AL = Text Character
\r
2675 AND AX, 00FFh ; Clear High Word
\r
2676 JZ @TPS_Exit ; Exit if null character
\r
2678 DEC [BP].TPS_Len ; Remaining Text length--
\r
2679 INC [BP].TPS_Text ; Point to Next text char
\r
2681 ; Set up Call to TGPRINTC
\r
2683 PUSH AX ; Set Character Parameter
\r
2684 MOV BX, [BP].TPS_Xpos ; Get Xpos
\r
2685 PUSH BX ; Set Xpos Parameter
\r
2686 ADD BX, 8 ; Advance 1 Char to Right
\r
2687 MOV [BP].TPS_Xpos, BX ; Save for next time through
\r
2689 MOV BX, [BP].TPS_Ypos ; Get Ypos
\r
2690 PUSH BX ; Set Ypos Parameter
\r
2692 MOV BX, [BP].TPS_ColorF ; Get Text Color
\r
2693 PUSH BX ; Set ColorF Parameter
\r
2695 CALL f TGPRINTC ; Print Character!
\r
2696 JMP s @TPS_Print_It ; Process next character
\r
2699 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2704 RET 12 ; Exit and Clean up Stack
\r
2709 ;===========================================
\r
2710 ;SET_DISPLAY_FONT(SEG FontData, FontNumber%)
\r
2711 ;===========================================
\r
2713 ; Allows the user to specify their own font data for
\r
2714 ; wither the lower or upper 128 characters.
\r
2716 ; ENTRY: FontData = Far Pointer to Font Bitmaps
\r
2717 ; FontNumber = Which half of set this is
\r
2718 ; = 0, Lower 128 characters
\r
2719 ; = 1, Upper 128 characters
\r
2721 ; EXIT: No meaningful values returned
\r
2727 SDF_Which DW ? ; Hi Table/Low Table Flag
\r
2728 SDF_Font DD ? ; Far Ptr to Font Table
\r
2731 PUBLIC SET_DISPLAY_FONT
\r
2733 SET_DISPLAY_FONT PROC FAR
\r
2735 PUSH BP ; Preserve Registers
\r
2736 MOV BP, SP ; Set up Stack Frame
\r
2738 LES DI, [BP].SDF_Font ; Get Far Ptr to Font
\r
2740 MOV SI, o CHARSET_LOW ; Assume Lower 128 chars
\r
2741 TEST [BP].SDF_Which, 1 ; Font #1 selected?
\r
2742 JZ @SDF_Set_Font ; If not, skip ahead
\r
2744 MOV SI, o CHARSET_HI ; Ah, really it's 128-255
\r
2747 MOV [SI], DI ; Set Font Pointer Offset
\r
2748 MOV [SI+2], ES ; Set Font Pointer Segment
\r
2750 POP BP ; Restore Registers
\r
2751 RET 6 ; We are Done.. Outa here
\r
2753 SET_DISPLAY_FONT ENDP
\r
2756 ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====
\r
2758 ;======================================================
\r
2759 ;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2760 ;======================================================
\r
2762 ; Draws a variable sized Graphics Bitmap such as a
\r
2763 ; picture or an Icon on the current Display Page in
\r
2764 ; Mode X. The Bitmap is stored in a linear byte array
\r
2765 ; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)
\r
2766 ; This is the same linear manner as mode 13h graphics.
\r
2768 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2769 ; Xpos = X position to Place Upper Left pixel at
\r
2770 ; Ypos = Y position to Place Upper Left pixel at
\r
2771 ; Width = Width of the Bitmap in Pixels
\r
2772 ; Height = Height of the Bitmap in Pixels
\r
2774 ; EXIT: No meaningful values returned
\r
2778 DB_LineO DW ? ; Offset to Next Line
\r
2779 DB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2780 DB_Start DW ? ; Addr of Upper Left Pixel
\r
2781 DB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2782 DB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2783 DW ?x1 ; DI, SI, DS, BP
\r
2784 DW ?x1 ; DI, SI, DS, BP
\r
2785 DW ?x1 ; DS, DI, SI, BP
\r
2786 DW ?x1 ; DS, DI, SI, BP
\r
2788 DB_Height DW ? ; Height of Bitmap in Pixels
\r
2789 DB_Width DW ? ; Width of Bitmap in Pixels
\r
2790 DB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2791 DB_Xpos DW ? ; X position to Draw Bitmap at
\r
2792 DB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2795 PUBLIC DRAW_BITMAP
\r
2797 DRAW_BITMAP PROC FAR
\r
2799 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2804 SUB SP, 10 ; Allocate workspace
\r
2805 MOV BP, SP ; Set up Stack Frame
\r
2807 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2808 CLD ; Direction Flag = Forward
\r
2810 MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos
\r
2811 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
2813 MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos
\r
2814 MOV CL, BL ; Save Plane # in CL
\r
2815 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2816 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2818 ADD DI, AX ; ES:DI -> Start of Line
\r
2819 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
2820 MOV [BP].DB_Start, DI ; Save Starting Addr
\r
2822 ; Compute line to line offset
\r
2824 MOV BX, [BP].DB_Width ; Get Width of Image
\r
2825 MOV DX, BX ; Save Copy in DX
\r
2826 SHR BX, 1 ; /4 = width in bands
\r
2827 SHR BX, 1 ; /4 = width in bands
\r
2828 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
2829 SUB AX, BX ; - (Bitmap Width/4)
\r
2831 MOV [BP].DB_LineO, AX ; Save Line Width offset
\r
2832 MOV [BP].DB_PixCount, BX ; Minimum # pix to copy
\r
2834 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
2835 MOV [BP].DB_PixSkew, DX ; Also End of Line Skew
\r
2836 MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count
\r
2838 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
2839 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
2840 SHL AH, CL ; Select correct Plane
\r
2841 OUT_16 SC_Index, AX ; Select Plane...
\r
2842 MOV BH, AH ; BH = Saved Plane Mask
\r
2843 MOV BL, 4 ; BL = Planes to Copy
\r
2847 LDS SI, [BP].DB_Image ; DS:SI-> Source Image
\r
2848 MOV DX, [BP].DB_Height ; # of Lines to Copy
\r
2849 MOV DI, [BP].DB_Start ; ES:DI-> Dest pos
\r
2852 MOV CX, [BP].DB_PixCount ; Min # to copy
\r
2854 TEST CL, 0FCh ; 16+PixWide?
\r
2855 JZ @DB_COPY_REMAINDER ; Nope...
\r
2857 ; Pixel Copy loop has been unrolled to x4
\r
2860 MOVSB ; Copy Bitmap Pixel
\r
2861 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2862 MOVSB ; Copy Bitmap Pixel
\r
2863 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2864 MOVSB ; Copy Bitmap Pixel
\r
2865 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2866 MOVSB ; Copy Bitmap Pixel
\r
2867 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2869 SUB CL, 4 ; Pixels to Copy=-4
\r
2870 TEST CL, 0FCh ; 4+ Pixels Left?
\r
2871 JNZ @DB_COPY_LOOP ; if so, do another block
\r
2873 @DB_COPY_REMAINDER:
\r
2874 JCXZ @DB_NEXT_LINE ; Any Pixels left on line
\r
2877 MOVSB ; Copy Bitmap Pixel
\r
2878 ADD SI,3 ; Skip to Next Byte in same plane
\r
2879 LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done
\r
2883 ; any Partial Pixels? (some planes only)
\r
2885 OR CX, [BP].DB_SkewFlag ; Get Skew Count
\r
2886 JZ @DB_NEXT2 ; if no partial pixels
\r
2888 MOVSB ; Copy Bitmap Pixel
\r
2889 DEC DI ; Back up to align
\r
2890 DEC SI ; Back up to align
\r
2893 ADD SI, [BP].DB_PixSkew ; Adjust Skew
\r
2894 ADD DI, [BP].DB_LineO ; Set to Next Display Line
\r
2895 LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more
\r
2897 ; Copy Next Plane....
\r
2899 DEC BL ; Planes to Go--
\r
2900 JZ @DB_Exit ; Hey! We are done
\r
2902 ROL BH, 1 ; Next Plane in line...
\r
2903 OUT_8 SC_Data, BH ; Select Plane
\r
2905 CMP AL, 12h ; Carry Set if AL=11h
\r
2906 ADC [BP].DB_Start, 0 ; Screen Addr =+Carry
\r
2907 INC w [BP].DB_Image ; Start @ Next Byte
\r
2909 SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew
\r
2910 ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1
\r
2912 JMP s @DB_COPY_PLANE ; Go Copy the Next Plane
\r
2915 ADD SP, 10 ; Deallocate workspace
\r
2916 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2921 RET 12 ; Exit and Clean up Stack
\r
2926 ;=======================================================
\r
2927 ;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2928 ;=======================================================
\r
2930 ; Transparently Draws a variable sized Graphics Bitmap
\r
2931 ; such as a picture or an Icon on the current Display Page
\r
2932 ; in Mode X. Pixels with a value of 0 are not drawn,
\r
2933 ; leaving the previous "background" contents intact.
\r
2935 ; The Bitmap format is the same as for the DRAW_BITMAP function.
\r
2937 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2938 ; Xpos = X position to Place Upper Left pixel at
\r
2939 ; Ypos = Y position to Place Upper Left pixel at
\r
2940 ; Width = Width of the Bitmap in Pixels
\r
2941 ; Height = Height of the Bitmap in Pixels
\r
2943 ; EXIT: No meaningful values returned
\r
2947 TB_LineO DW ? ; Offset to Next Line
\r
2948 TB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2949 TB_Start DW ? ; Addr of Upper Left Pixel
\r
2950 TB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2951 TB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2952 DW ?x1 ; DI, SI, DS, BP
\r
2953 DW ?x1 ; DI, SI, DS, BP
\r
2954 DW ?x1 ; DS, DI, SI, BP
\r
2955 DW ?x1 ; DS, DI, SI, BP
\r
2957 TB_Height DW ? ; Height of Bitmap in Pixels
\r
2958 TB_Width DW ? ; Width of Bitmap in Pixels
\r
2959 TB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2960 TB_Xpos DW ? ; X position to Draw Bitmap at
\r
2961 TB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2964 PUBLIC TDRAW_BITMAP
\r
2966 TDRAW_BITMAP PROC FAR
\r
2968 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2973 SUB SP, 10 ; Allocate workspace
\r
2974 MOV BP, SP ; Set up Stack Frame
\r
2976 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2977 CLD ; Direction Flag = Forward
\r
2979 MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos
\r
2980 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
2982 MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos
\r
2983 MOV CL, BL ; Save Plane # in CL
\r
2984 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2985 SHR BX, 1 ; Xpos/4 = Offset Into Line
\r
2987 ADD DI, AX ; ES:DI -> Start of Line
\r
2988 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
2989 MOV [BP].TB_Start, DI ; Save Starting Addr
\r
2991 ; Compute line to line offset
\r
2993 MOV BX, [BP].TB_Width ; Get Width of Image
\r
2994 MOV DX, BX ; Save Copy in DX
\r
2995 SHR BX, 1 ; /4 = width in bands
\r
2996 SHR BX, 1 ; /4 = width in bands
\r
2997 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
2998 SUB AX, BX ; - (Bitmap Width/4)
\r
3000 MOV [BP].TB_LineO, AX ; Save Line Width offset
\r
3001 MOV [BP].TB_PixCount, BX ; Minimum # pix to copy
\r
3003 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
3004 MOV [BP].TB_PixSkew, DX ; Also End of Line Skew
\r
3005 MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count
\r
3007 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
3008 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
3009 SHL AH, CL ; Select correct Plane
\r
3010 OUT_16 SC_Index, AX ; Select Plane...
\r
3011 MOV BH, AH ; BH = Saved Plane Mask
\r
3012 MOV BL, 4 ; BL = Planes to Copy
\r
3016 LDS SI, [BP].TB_Image ; DS:SI-> Source Image
\r
3017 MOV DX, [BP].TB_Height ; # of Lines to Copy
\r
3018 MOV DI, [BP].TB_Start ; ES:DI-> Dest pos
\r
3020 ; Here AH is set with the value to be considered
\r
3021 ; "Transparent". It can be changed!
\r
3023 MOV AH, 0 ; Value to Detect 0
\r
3026 MOV CX, [BP].TB_PixCount ; Min # to copy
\r
3028 TEST CL, 0FCh ; 16+PixWide?
\r
3029 JZ @TB_COPY_REMAINDER ; Nope...
\r
3031 ; Pixel Copy loop has been unrolled to x4
\r
3034 LODSB ; Get Pixel Value in AL
\r
3035 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3036 CMP AL, AH ; It is "Transparent"?
\r
3037 JE @TB_SKIP_01 ; Skip ahead if so
\r
3038 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3041 LODSB ; Get Pixel Value in AL
\r
3042 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3043 CMP AL, AH ; It is "Transparent"?
\r
3044 JE @TB_SKIP_02 ; Skip ahead if so
\r
3045 MOV ES:[DI+1], AL ; Copy Pixel to VGA screen
\r
3048 LODSB ; Get Pixel Value in AL
\r
3049 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3050 CMP AL, AH ; It is "Transparent"?
\r
3051 JE @TB_SKIP_03 ; Skip ahead if so
\r
3052 MOV ES:[DI+2], AL ; Copy Pixel to VGA screen
\r
3055 LODSB ; Get Pixel Value in AL
\r
3056 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3057 CMP AL, AH ; It is "Transparent"?
\r
3058 JE @TB_SKIP_04 ; Skip ahead if so
\r
3059 MOV ES:[DI+3], AL ; Copy Pixel to VGA screen
\r
3062 ADD DI, 4 ; Adjust Pixel Write Location
\r
3063 SUB CL, 4 ; Pixels to Copy=-4
\r
3064 TEST CL, 0FCh ; 4+ Pixels Left?
\r
3065 JNZ @TB_COPY_LOOP ; if so, do another block
\r
3067 @TB_COPY_REMAINDER:
\r
3068 JCXZ @TB_NEXT_LINE ; Any Pixels left on line
\r
3071 LODSB ; Get Pixel Value in AL
\r
3072 ADD SI, 3 ; Skip to Next Byte in same plane
\r
3073 CMP AL, AH ; It is "Transparent"?
\r
3074 JE @TB_SKIP_05 ; Skip ahead if so
\r
3075 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3078 INC DI ; Advance Dest Addr
\r
3079 LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done
\r
3083 ; any Partial Pixels? (some planes only)
\r
3085 OR CX, [BP].TB_SkewFlag ; Get Skew Count
\r
3086 JZ @TB_NEXT2 ; if no partial pixels
\r
3088 LODSB ; Get Pixel Value in AL
\r
3089 DEC SI ; Backup to Align
\r
3090 CMP AL, AH ; It is "Transparent"?
\r
3091 JE @TB_NEXT2 ; Skip ahead if so
\r
3092 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
3095 ADD SI, [BP].TB_PixSkew ; Adjust Skew
\r
3096 ADD DI, [BP].TB_LineO ; Set to Next Display Line
\r
3097 LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More
\r
3099 ;Copy Next Plane....
\r
3101 DEC BL ; Planes to Go--
\r
3102 JZ @TB_Exit ; Hey! We are done
\r
3104 ROL BH, 1 ; Next Plane in line...
\r
3105 OUT_8 SC_Data, BH ; Select Plane
\r
3107 CMP AL, 12h ; Carry Set if AL=11h
\r
3108 ADC [BP].TB_Start, 0 ; Screen Addr =+Carry
\r
3109 INC w [BP].TB_Image ; Start @ Next Byte
\r
3111 SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew
\r
3112 ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1
\r
3114 JMP @TB_COPY_PLANE ; Go Copy the next Plane
\r
3117 ADD SP, 10 ; Deallocate workspace
\r
3118 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3123 RET 12 ; Exit and Clean up Stack
\r
3128 ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====
\r
3130 ;==================================
\r
3131 ;COPY_PAGE (SourcePage%, DestPage%)
\r
3132 ;==================================
\r
3134 ; Duplicate on display page onto another
\r
3136 ; ENTRY: SourcePage = Display Page # to Duplicate
\r
3137 ; DestPage = Display Page # to hold copy
\r
3139 ; EXIT: No meaningful values returned
\r
3143 DW ?x1 ; DI, SI, DS, BP
\r
3144 DW ?x1 ; DI, SI, DS, BP
\r
3145 DW ?x1 ; DS, DI, SI, BP
\r
3146 DW ?x1 ; DS, DI, SI, BP
\r
3148 CP_DestP DW ? ; Page to hold copied image
\r
3149 CP_SourceP DW ? ; Page to Make copy from
\r
3154 COPY_PAGE PROC FAR
\r
3156 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
3161 MOV BP, SP ; Set up Stack Frame
\r
3162 CLD ; Block Xfer Forwards
\r
3164 ; Make sure Page #'s are valid
\r
3166 MOV AX, [BP].CP_SourceP ; Get Source Page #
\r
3167 CMP AX, LAST_PAGE ; is it > Max Page #?
\r
3168 JAE @CP_Exit ; if so, abort
\r
3170 MOV BX, [BP].CP_DestP ; Get Destination Page #
\r
3171 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3172 JAE @CP_Exit ; if so, abort
\r
3174 CMP AX, BX ; Pages #'s the same?
\r
3175 JE @CP_Exit ; if so, abort
\r
3177 ; Setup DS:SI and ES:DI to Video Pages
\r
3179 SHL BX, 1 ; Scale index to Word
\r
3180 MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page
\r
3182 MOV BX, AX ; Index to Source page
\r
3183 SHL BX, 1 ; Scale index to Word
\r
3184 MOV SI, PAGE_ADDR[BX] ; Offset to Source Page
\r
3186 MOV CX, PAGE_SIZE ; Get size of Page
\r
3187 MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment
\r
3188 MOV ES, AX ; ES:DI -> Dest Page
\r
3189 MOV DS, AX ; DS:SI -> Source Page
\r
3191 ; Setup VGA registers for Mem to Mem copy
\r
3193 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3194 OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes
\r
3196 ; Note.. Do *NOT* use MOVSW or MOVSD - they will
\r
3197 ; Screw with the latches which are 8 bits x 4
\r
3199 REP MOVSB ; Copy entire Page!
\r
3201 ; Reset VGA for normal memory access
\r
3203 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off
\r
3206 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3211 RET 4 ; Exit and Clean up Stack
\r
3216 ;==========================================================================
\r
3217 ;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)
\r
3218 ;==========================================================================
\r
3220 ; Copies a Bitmap Image from one Display Page to Another
\r
3221 ; This Routine is Limited to copying Images with the same
\r
3222 ; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4)
\r
3223 ; Copying an Image to the Same Page is supported, but results
\r
3224 ; may be defined when the when the rectangular areas
\r
3225 ; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) -
\r
3226 ; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...
\r
3227 ; No Paramter checking to done to insure that
\r
3228 ; X2 >= X1 and Y2 >= Y1. Be Careful...
\r
3230 ; ENTRY: SourcePage = Display Page # with Source Image
\r
3231 ; X1 = Upper Left Xpos of Source Image
\r
3232 ; Y1 = Upper Left Ypos of Source Image
\r
3233 ; X2 = Lower Right Xpos of Source Image
\r
3234 ; Y2 = Lower Right Ypos of Source Image
\r
3235 ; DestPage = Display Page # to copy Image to
\r
3236 ; DestX1 = Xpos to Copy UL Corner of Image to
\r
3237 ; DestY1 = Ypos to Copy UL Corner of Image to
\r
3239 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
3243 CB_Height DW ? ; Height of Image in Lines
\r
3244 CB_Width DW ? ; Width of Image in "bands"
\r
3245 DW ?x1 ; DI, SI, DS, BP
\r
3246 DW ?x1 ; DI, SI, DS, BP
\r
3247 DW ?x1 ; DS, DI, SI, BP
\r
3248 DW ?x1 ; DS, DI, SI, BP
\r
3250 CB_DestY1 DW ? ; Destination Ypos
\r
3251 CB_DestX1 DW ? ; Destination Xpos
\r
3252 CB_DestP DW ? ; Page to Copy Bitmap To
\r
3253 CB_Y2 DW ? ; LR Ypos of Image
\r
3254 CB_X2 DW ? ; LR Xpos of Image
\r
3255 CB_Y1 DW ? ; UL Ypos of Image
\r
3256 CB_X1 DW ? ; UL Xpos of Image
\r
3257 CB_SourceP DW ? ; Page containing Source Bitmap
\r
3260 PUBLIC COPY_BITMAP
\r
3262 COPY_BITMAP PROC FAR
\r
3264 ;PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
3269 SUB SP, 4 ; Allocate WorkSpace on Stack
\r
3270 MOV BP, SP ; Set up Stack Frame
\r
3272 ; Prep Registers (and keep jumps short!)
\r
3274 MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram
\r
3275 CLD ; Block Xfer Forwards
\r
3277 ; Make sure Parameters are valid
\r
3279 MOV BX, [BP].CB_SourceP ; Get Source Page #
\r
3280 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3281 JAE @CB_Abort ; if so, abort
\r
3283 MOV CX, [BP].CB_DestP ; Get Destination Page #
\r
3284 CMP CX, LAST_PAGE ; is it > Max Page #?
\r
3285 JAE @CB_Abort ; if so, abort
\r
3287 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3288 XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1
\r
3289 AND AX, PLANE_BITS ; Check Plane Bits
\r
3290 JNZ @CB_Abort ; They should cancel out
\r
3292 ; Setup for Copy processing
\r
3294 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
3295 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3297 ; Compute Info About Images, Setup ES:SI & ES:DI
\r
3299 MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines
\r
3300 SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1
\r
3301 INC AX ; (add 1 since were not 0 based)
\r
3302 MOV [BP].CB_Height, AX ; Save on Stack for later use
\r
3304 MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels
\r
3305 MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1
\r
3306 SHR AX, 1 ; Get X2 Band (X2 / 4)
\r
3307 SHR DX, 1 ; Get X1 Band (X1 / 4)
\r
3308 SHR AX, 1 ; Get X2 Band (X2 / 4)
\r
3309 SHR DX, 1 ; Get X1 Band (X1 / 4)
\r
3310 SUB AX, DX ; AX = # of Bands - 1
\r
3311 INC AX ; AX = # of Bands
\r
3312 MOV [BP].CB_Width, AX ; Save on Stack for later use
\r
3314 SHL BX, 1 ; Scale Source Page to Word
\r
3315 MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page
\r
3316 MOV AX, [BP].CB_Y1 ; Get Source Y1 Line
\r
3317 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3318 ADD SI, AX ; SI = Offset to Line Y1
\r
3319 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3320 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3321 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3322 ADD SI, AX ; SI = Byte Offset to (X1,Y1)
\r
3324 MOV BX, CX ; Dest Page Index to BX
\r
3325 SHL BX, 1 ; Scale Source Page to Word
\r
3326 MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page
\r
3327 MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line
\r
3328 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3329 ADD DI, AX ; DI = Offset to Line Y1
\r
3330 MOV AX, [BP].CB_DestX1 ; Get Dest X1
\r
3331 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3332 SHR AX, 1 ; X1 / 4 = Byte offset
\r
3333 ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1)
\r
3335 MOV CX, [BP].CB_Width ; CX = Width of Image (Bands)
\r
3337 JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band
\r
3339 MOV BX, [BP].CB_X1 ; Get Source X1
\r
3340 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?)
\r
3341 JZ @CB_Check_Right ; if so, check right alignment
\r
3342 JNZ @CB_Left_Band ; not aligned? well..
\r
3345 mov ax,0 ; Return False (Failure)
\r
3346 JMP @CB_Exit ; and Finish Up
\r
3348 ; Copy when Left & Right Clip Masks overlap...
\r
3350 @CB_Only_One_Band:
\r
3351 MOV BX, [BP].CB_X1 ; Get Left Clip Mask
\r
3352 AND BX, PLANE_BITS ; Mask out Row #
\r
3353 MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask
\r
3354 MOV BX, [BP].CB_X2 ; Get Right Clip Mask
\r
3355 AND BX, PLANE_BITS ; Mask out Row #
\r
3356 AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte
\r
3358 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
3360 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3361 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3362 mov bx,0 ; BX = Offset into Image
\r
3365 MOV AL, ES:[SI+BX] ; Load Latches
\r
3366 MOV ES:[DI+BX], AL ; Unload Latches
\r
3367 ADD BX, DX ; Advance Offset to Next Line
\r
3368 LOOPjz CX, @CB_One_Done ; Exit Loop if Finished
\r
3370 MOV AL, ES:[SI+BX] ; Load Latches
\r
3371 MOV ES:[DI+BX], AL ; Unload Latches
\r
3372 ADD BX, DX ; Advance Offset to Next Line
\r
3373 LOOPx CX, @CB_One_Loop ; Loop until Finished
\r
3376 JMP @CB_Finish ; Outa Here!
\r
3378 ; Copy Left Edge of Bitmap
\r
3382 OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask
\r
3384 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3385 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3386 mov bx,0 ; BX = Offset into Image
\r
3389 MOV AL, ES:[SI+BX] ; Load Latches
\r
3390 MOV ES:[DI+BX], AL ; Unload Latches
\r
3391 ADD BX, DX ; Advance Offset to Next Line
\r
3392 LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished
\r
3394 MOV AL, ES:[SI+BX] ; Load Latches
\r
3395 MOV ES:[DI+BX], AL ; Unload Latches
\r
3396 ADD BX, DX ; Advance Offset to Next Line
\r
3397 LOOPx CX, @CB_Left_Loop ; Loop until Finished
\r
3400 INC DI ; Move Dest Over 1 band
\r
3401 INC SI ; Move Source Over 1 band
\r
3402 DEC [BP].CB_Width ; Band Width--
\r
3404 ; Determine if Right Edge of Bitmap needs special copy
\r
3407 MOV BX, [BP].CB_X2 ; Get Source X2
\r
3408 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?)
\r
3409 CMP BL, 03h ; Plane = 3?
\r
3410 JE @CB_Copy_Middle ; Copy the Middle then!
\r
3412 ; Copy Right Edge of Bitmap
\r
3416 OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask
\r
3418 DEC [BP].CB_Width ; Band Width--
\r
3419 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3420 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3421 MOV BX, [BP].CB_Width ; BX = Offset to Right Edge
\r
3424 MOV AL, ES:[SI+BX] ; Load Latches
\r
3425 MOV ES:[DI+BX], AL ; Unload Latches
\r
3426 ADD BX, DX ; Advance Offset to Next Line
\r
3427 LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished
\r
3429 MOV AL, ES:[SI+BX] ; Load Latches
\r
3430 MOV ES:[DI+BX], AL ; Unload Latches
\r
3431 ADD BX, DX ; Advance Offset to Next Line
\r
3432 LOOPx CX, @CB_Right_Loop ; Loop until Finished
\r
3436 ; Copy the Main Block of the Bitmap
\r
3440 MOV CX, [BP].CB_Width ; Get Width Remaining
\r
3441 JCXZ @CB_Finish ; Exit if Done
\r
3443 OUT_8 SC_Data, ALL_PLANES ; Copy all Planes
\r
3445 MOV DX, SCREEN_WIDTH ; Get Width of Screen minus
\r
3446 SUB DX, CX ; Image width (for Adjustment)
\r
3447 MOV AX, [BP].CB_Height ; AX = # of Lines to Copy
\r
3448 MOV BX, CX ; BX = Quick REP reload count
\r
3449 MOV CX, ES ; Move VGA Segment
\r
3450 MOV DS, CX ; Into DS
\r
3452 ; Actual Copy Loop. REP MOVSB does the work
\r
3455 MOV CX, BX ; Recharge Rep Count
\r
3456 REP MOVSB ; Move Bands
\r
3457 LOOPjz AX, @CB_Finish ; Exit Loop if Finished
\r
3459 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3460 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3462 MOV CX, BX ; Recharge Rep Count
\r
3463 REP MOVSB ; Move Bands
\r
3465 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3466 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3467 LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done
\r
3470 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on
\r
3473 ADD SP, 04 ; Deallocate stack workspace
\r
3474 ;POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3479 RET 16 ; Exit and Clean up Stack
\r
3483 END ; End of Code Segment
\r