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
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
170 ; ===== VGA Register Values =====
\r
172 VGA_Segment EQU 0A000h ; Vga Memory Segment
\r
174 ATTRIB_Ctrl EQU 03C0h ; VGA Attribute Controller
\r
175 GC_Index EQU 03CEh ; VGA Graphics Controller
\r
176 SC_Index EQU 03C4h ; VGA Sequencer Controller
\r
177 SC_Data EQU 03C5h ; VGA Sequencer Data Port
\r
178 CRTC_Index EQU 03D4h ; VGA CRT Controller
\r
179 CRTC_Data EQU 03D5h ; VGA CRT Controller Data
\r
180 MISC_OUTPUT EQU 03C2h ; VGA Misc Register
\r
181 INPUT_1 EQU 03DAh ; Input Status #1 Register
\r
183 DAC_WRITE_ADDR EQU 03C8h ; VGA DAC Write Addr Register
\r
184 DAC_READ_ADDR EQU 03C7h ; VGA DAC Read Addr Register
\r
185 PEL_DATA_REG EQU 03C9h ; VGA DAC/PEL data Register R/W
\r
187 PIXEL_PAN_REG EQU 033h ; Attrib Index: Pixel Pan Reg
\r
188 MAP_MASK EQU 002h ; Sequ Index: Write Map Mask reg
\r
189 READ_MAP EQU 004h ; GC Index: Read Map Register
\r
190 START_DISP_HI EQU 00Ch ; CRTC Index: Display Start Hi
\r
191 START_DISP_LO EQU 00Dh ; CRTC Index: Display Start Lo
\r
193 MAP_MASK_PLANE1 EQU 00102h ; Map Register + Plane 1
\r
194 MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1
\r
195 ALL_PLANES_ON EQU 00F02h ; Map Register + All Bit Planes
\r
197 CHAIN4_OFF EQU 00604h ; Chain 4 mode Off
\r
198 ASYNC_RESET EQU 00100h ; (A)synchronous Reset
\r
199 SEQU_RESTART EQU 00300h ; Sequencer Restart
\r
201 LATCHES_ON EQU 00008h ; Bit Mask + Data from Latches
\r
202 LATCHES_OFF EQU 0FF08h ; Bit Mask + Data from CPU
\r
204 VERT_RETRACE EQU 08h ; INPUT_1: Vertical Retrace Bit
\r
205 PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane #
\r
206 ALL_PLANES EQU 0Fh ; All Bit Planes Selected
\r
207 CHAR_BITS EQU 0Fh ; Bits 0-3 of Character Data
\r
209 GET_CHAR_PTR EQU 01130h ; VGA BIOS Func: Get Char Set
\r
210 ROM_8x8_Lo EQU 03h ; ROM 8x8 Char Set Lo Pointer
\r
211 ROM_8x8_Hi EQU 04h ; ROM 8x8 Char Set Hi Pointer
\r
213 ; Constants Specific for these routines
\r
215 NUM_MODES EQU 8 ; # of Mode X Variations
\r
217 ; Specific Mode Data Table format...
\r
219 Mode_Data_Table STRUC
\r
220 M_MiscR DB ? ; Value of MISC_OUTPUT register
\r
221 M_Pages DB ? ; Maximum Possible # of pages
\r
222 M_XSize DW ? ; X Size Displayed on screen
\r
223 M_YSize DW ? ; Y Size Displayed on screen
\r
224 M_XMax DW ? ; Maximum Possible X Size
\r
225 M_YMax DW ? ; Maximum Possible Y Size
\r
226 M_CRTC DW ? ; Table of CRTC register values
\r
227 Mode_Data_Table ENDS
\r
229 ; ===== DGROUP STORAGE NEEDED (42 BYTES) =====
\r
233 SCREEN_WIDTH DW 0 ; Width of a line in Bytes
\r
234 SCREEN_HEIGHT DW 0 ; Vertical Height in Pixels
\r
236 LAST_PAGE DW 0 ; # of Display Pages
\r
237 PAGE_ADDR DW 4 DUP (0) ; Offsets to start of each page
\r
239 PAGE_SIZE DW 0 ; Size of Page in Addr Bytes
\r
241 DISPLAY_PAGE DW 0 ; Page # currently displayed
\r
242 ACTIVE_PAGE DW 0 ; Page # currently active
\r
244 CURRENT_PAGE DW 0 ; Offset of current Page
\r
245 CURRENT_SEGMENT DW 0 ; Segment of VGA memory
\r
247 CURRENT_XOFFSET DW 0 ; Current Display X Offset
\r
248 CURRENT_YOFFSET DW 0 ; Current Display Y Offset
\r
250 CURRENT_MOFFSET DW 0 ; Current Start Offset
\r
252 MAX_XOFFSET DW 0 ; Current Display X Offset
\r
253 MAX_YOFFSET DW 0 ; Current Display Y Offset
\r
255 CHARSET_LOW DW 0, 0 ; Far Ptr to Char Set: 0-127
\r
256 CHARSET_HI DW 0, 0 ; Far Ptr to Char Set: 128-255
\r
260 ; ===== DATA TABLES =====
\r
262 ; Data Tables, Put in Code Segment for Easy Access
\r
263 ; (Like when all the other Segment Registers are in
\r
264 ; use!!) and reduced DGROUP requirements...
\r
266 ; Bit Mask Tables for Left/Right/Character Masks
\r
268 Left_Clip_Mask DB 0FH, 0EH, 0CH, 08H
\r
270 Right_Clip_Mask DB 01H, 03H, 07H, 0FH
\r
272 ; Bit Patterns for converting character fonts
\r
274 Char_Plane_Data DB 00H,08H,04H,0CH,02H,0AH,06H,0EH
\r
275 DB 01H,09H,05H,0DH,03H,0BH,07H,0FH
\r
277 ; CRTC Register Values for Various Configurations
\r
279 MODE_Single_Line: ; CRTC Setup Data for 400/480 Line modes
\r
280 DW 04009H ; Cell Height (1 Scan Line)
\r
281 DW 00014H ; Dword Mode off
\r
282 DW 0E317H ; turn on Byte Mode
\r
283 DW nil ; End of CRTC Data for 400/480 Line Mode
\r
285 MODE_Double_Line: ; CRTC Setup Data for 200/240 Line modes
\r
286 DW 04109H ; Cell Height (2 Scan Lines)
\r
287 DW 00014H ; Dword Mode off
\r
288 DW 0E317H ; turn on Byte Mode
\r
289 DW nil ; End of CRTC Data for 200/240 Line Mode
\r
291 MODE_320_Wide: ; CRTC Setup Data for 320 Horz Pixels
\r
292 DW 05F00H ; Horz total
\r
293 DW 04F01H ; Horz Displayed
\r
294 DW 05002H ; Start Horz Blanking
\r
295 DW 08203H ; End Horz Blanking
\r
296 DW 05404H ; Start H Sync
\r
297 DW 08005H ; End H Sync
\r
298 DW nil ; End of CRTC Data for 320 Horz pixels
\r
300 MODE_360_Wide: ; CRTC Setup Data for 360 Horz Pixels
\r
301 DW 06B00H ; Horz total
\r
302 DW 05901H ; Horz Displayed
\r
303 DW 05A02H ; Start Horz Blanking
\r
304 DW 08E03H ; End Horz Blanking
\r
305 DW 05E04H ; Start H Sync
\r
306 DW 08A05H ; End H Sync
\r
307 DW nil ; End of CRTC Data for 360 Horz pixels
\r
310 MODE_400_Tall: ; CRTC Setup Data for 200/400 Line modes
\r
311 DW 0BF06H ; Vertical Total
\r
312 DW 01F07H ; Overflow
\r
313 DW 09C10H ; V Sync Start
\r
314 DW 08E11H ; V Sync End/Prot Cr0 Cr7
\r
315 DW 08F12H ; Vertical Displayed
\r
316 DW 09615H ; V Blank Start
\r
317 DW 0B916H ; V Blank End
\r
318 DW nil ; End of CRTC Data for 200/400 Lines
\r
321 MODE_480_Tall: ; CRTC Setup Data for 240/480 Line modes
\r
322 DW 00D06H ; Vertical Total
\r
323 DW 03E07H ; Overflow
\r
324 DW 0EA10H ; V Sync Start
\r
325 DW 08C11H ; V Sync End/Prot Cr0 Cr7
\r
326 DW 0DF12H ; Vertical Displayed
\r
327 DW 0E715H ; V Blank Start
\r
328 DW 00616H ; V Blank End
\r
329 DW nil ; End of CRTC Data for 240/480 Lines
\r
331 ; Table of Display Mode Tables
\r
334 DW o MODE_320x200, o MODE_320x400
\r
335 DW o MODE_360x200, o MODE_360x400
\r
336 DW o MODE_320x240, o MODE_320x480
\r
337 DW o MODE_360x240, o MODE_360x480
\r
339 ; Table of Display Mode Components
\r
341 MODE_320x200: ; Data for 320 by 200 Pixels
\r
343 DB 063h ; 400 scan Lines & 25 Mhz Clock
\r
344 DB 4 ; Maximum of 4 Pages
\r
345 DW 320, 200 ; Displayed Pixels (X,Y)
\r
346 DW 1302, 816 ; Max Possible X and Y Sizes
\r
348 DW o MODE_320_Wide, o MODE_200_Tall
\r
349 DW o MODE_Double_Line, nil
\r
351 MODE_320x400: ; Data for 320 by 400 Pixels
\r
353 DB 063h ; 400 scan Lines & 25 Mhz Clock
\r
354 DB 2 ; Maximum of 2 Pages
\r
355 DW 320, 400 ; Displayed Pixels X,Y
\r
356 DW 648, 816 ; Max Possible X and Y Sizes
\r
358 DW o MODE_320_Wide, o MODE_400_Tall
\r
359 DW o MODE_Single_Line, nil
\r
361 MODE_360x240: ; Data for 360 by 240 Pixels
\r
363 DB 0E7h ; 480 scan Lines & 28 Mhz Clock
\r
364 DB 3 ; Maximum of 3 Pages
\r
365 DW 360, 240 ; Displayed Pixels X,Y
\r
366 DW 1092, 728 ; Max Possible X and Y Sizes
\r
368 DW o MODE_360_Wide, o MODE_240_Tall
\r
369 DW o MODE_Double_Line , nil
\r
371 MODE_360x480: ; Data for 360 by 480 Pixels
\r
373 DB 0E7h ; 480 scan Lines & 28 Mhz Clock
\r
374 DB 1 ; Only 1 Page Possible
\r
375 DW 360, 480 ; Displayed Pixels X,Y
\r
376 DW 544, 728 ; Max Possible X and Y Sizes
\r
378 DW o MODE_360_Wide, o MODE_480_Tall
\r
379 DW o MODE_Single_Line , nil
\r
381 MODE_320x240: ; Data for 320 by 240 Pixels
\r
383 DB 0E3h ; 480 scan Lines & 25 Mhz Clock
\r
384 DB 3 ; Maximum of 3 Pages
\r
385 DW 320, 240 ; Displayed Pixels X,Y
\r
386 DW 1088, 818 ; Max Possible X and Y Sizes
\r
388 DW o MODE_320_Wide, o MODE_240_Tall
\r
389 DW o MODE_Double_Line, nil
\r
391 MODE_320x480: ; Data for 320 by 480 Pixels
\r
393 DB 0E3h ; 480 scan Lines & 25 Mhz Clock
\r
394 DB 1 ; Only 1 Page Possible
\r
395 DW 320, 480 ; Displayed Pixels X,Y
\r
396 DW 540, 818 ; Max Possible X and Y Sizes
\r
398 DW o MODE_320_WIDE, o MODE_480_Tall
\r
399 DW o MODE_Single_Line, nil
\r
401 MODE_360x200: ; Data for 360 by 200 Pixels
\r
403 DB 067h ; 400 scan Lines & 28 Mhz Clock
\r
404 DB 3 ; Maximum of 3 Pages
\r
405 DW 360, 200 ; Displayed Pixels (X,Y)
\r
406 DW 1302, 728 ; Max Possible X and Y Sizes
\r
408 DW o MODE_360_Wide, MODE_200_Tall
\r
409 DW o MODE_Double_Line, nil
\r
411 MODE_360x400: ; Data for 360 by 400 Pixels
\r
413 DB 067h ; 400 scan Lines & 28 Mhz Clock
\r
414 DB 1 ; Maximum of 1 Pages
\r
415 DW 360, 400 ; Displayed Pixels X,Y
\r
416 DW 648, 816 ; Max Possible X and Y Sizes
\r
418 DW o MODE_360_Wide, MODE_400_Tall
\r
419 DW o MODE_Single_Line, nil
\r
422 ; ===== MODE X SETUP ROUTINES =====
\r
424 ;======================================================
\r
425 ;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%)
\r
426 ;======================================================
\r
428 ; Sets Up the specified version of Mode X. Allows for
\r
429 ; the setup of multiple video pages, and a virtual
\r
430 ; screen which can be larger than the displayed screen
\r
431 ; (which can then be scrolled a pixel at a time)
\r
433 ; ENTRY: ModeType = Desired Screen Resolution (0-7)
\r
435 ; 0 = 320 x 200, 4 Pages max, 1.2:1 Aspect Ratio
\r
436 ; 1 = 320 x 400, 2 Pages max, 2.4:1 Aspect Ratio
\r
437 ; 2 = 360 x 200, 3 Pages max, 1.35:1 Aspect Ratio
\r
438 ; 3 = 360 x 400, 1 Page max, 2.7:1 Aspect Ratio
\r
439 ; 4 = 320 x 240, 3 Pages max, 1:1 Aspect Ratio
\r
440 ; 5 = 320 x 480, 1 Page max, 2:1 Aspect Ratio
\r
441 ; 6 = 360 x 240, 3 Pages max, 1.125:1 Aspect Ratio
\r
442 ; 7 = 360 x 480, 1 Page max, 2.25:1 Aspect Ratio
\r
444 ; MaxXpos = The Desired Virtual Screen Width
\r
445 ; MaxYpos = The Desired Virtual Screen Height
\r
446 ; Pages = The Desired # of Video Pages
\r
448 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
452 SVM_Table DW ? ; Offset of Mode Info Table
\r
453 DW ?x4 ; DI, SI, DS, BP
\r
455 SVM_Pages DW ? ; # of Screen Pages desired
\r
456 SVM_Ysize DW ? ; Vertical Screen Size Desired
\r
457 SVM_Xsize DW ? ; Horizontal Screen Size Desired
\r
458 SVM_Mode DW ? ; Display Resolution Desired
\r
461 PUBLIC SET_VGA_MODEX
\r
463 SET_VGA_MODEX PROC FAR
\r
465 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
466 SUB SP, 2 ; Allocate workspace
\r
467 MOV BP, SP ; Set up Stack Frame
\r
469 ; Check Legality of Mode Request....
\r
471 MOV BX, [BP].SVM_Mode ; Get Requested Mode #
\r
472 CMP BX, NUM_MODES ; Is it 0..7?
\r
473 JAE @SVM_BadModeSetup ; If Not, Error out
\r
475 SHL BX, 1 ; Scale BX
\r
476 MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info
\r
477 MOV [BP].SVM_Table, SI ; Save ptr for later use
\r
479 ; Check # of Requested Display Pages
\r
481 MOV CX, [BP].SVM_Pages ; Get # of Requested Pages
\r
482 CLR CH ; Set Hi Word = 0!
\r
483 CMP CL, CS:[SI].M_Pages ; Check # Pages for mode
\r
484 JA @SVM_BadModeSetup ; Report Error if too Many Pages
\r
485 JCXZ @SVM_BadModeSetup ; Report Error if 0 Pages
\r
487 ; Check Validity of X Size
\r
489 AND [BP].SVM_XSize, 0FFF8h ; X size Mod 8 Must = 0
\r
491 MOV AX, [BP].SVM_XSize ; Get Logical Screen Width
\r
492 CMP AX, CS:[SI].M_XSize ; Check against Displayed X
\r
493 JB @SVM_BadModeSetup ; Report Error if too small
\r
494 CMP AX, CS:[SI].M_XMax ; Check against Max X
\r
495 JA @SVM_BadModeSetup ; Report Error if too big
\r
497 ; Check Validity of Y Size
\r
499 MOV BX, [BP].SVM_YSize ; Get Logical Screen Height
\r
500 CMP BX, CS:[SI].M_YSize ; Check against Displayed Y
\r
501 JB @SVM_BadModeSetup ; Report Error if too small
\r
502 CMP BX, CS:[SI].M_YMax ; Check against Max Y
\r
503 JA @SVM_BadModeSetup ; Report Error if too big
\r
505 ; Enough memory to Fit it all?
\r
507 SHR AX, 2 ; # of Bytes:Line = XSize/4
\r
508 MUL CX ; AX = Bytes/Line * Pages
\r
509 MUL BX ; DX:AX = Total VGA mem needed
\r
510 JNO @SVM_Continue ; Exit if Total Size > 256K
\r
512 DEC DX ; Was it Exactly 256K???
\r
513 OR DX, AX ; (DX = 1, AX = 0000)
\r
514 JZ @SVM_Continue ; if so, it's valid...
\r
518 CLR AX ; Return Value = False
\r
519 JMP @SVM_Exit ; Normal Exit
\r
523 MOV AX, 13H ; Start with Mode 13H
\r
524 INT 10H ; Let BIOS Set Mode
\r
526 OUT_16 SC_INDEX, CHAIN4_OFF ; Disable Chain 4 Mode
\r
527 OUT_16 SC_INDEX, ASYNC_RESET ; (A)synchronous Reset
\r
528 OUT_8 MISC_OUTPUT, CS:[SI].M_MiscR ; Set New Timing/Size
\r
529 OUT_16 SC_INDEX, SEQU_RESTART ; Restart Sequencer ...
\r
531 OUT_8 CRTC_INDEX, 11H ; Select Vert Retrace End Register
\r
532 INC DX ; Point to Data
\r
533 IN AL, DX ; Get Value, Bit 7 = Protect
\r
534 AND AL, 7FH ; Mask out Write Protect
\r
535 OUT DX, AL ; And send it back
\r
537 MOV DX, CRTC_INDEX ; Vga Crtc Registers
\r
538 ADD SI, M_CRTC ; SI -> CRTC Parameter Data
\r
540 ; Load Tables of CRTC Parameters from List of Tables
\r
544 MOV DI, CS:[SI] ; Get Pointer to CRTC Data Tbl
\r
545 ADD SI, 2 ; Point to next Ptr Entry
\r
546 OR DI, DI ; A nil Ptr means that we have
\r
547 JZ @SVM_Set_Data ; finished CRTC programming
\r
550 MOV AX, CS:[DI] ; Get CRTC Data from Table
\r
551 ADD DI, 2 ; Advance Pointer
\r
552 OR AX, AX ; At End of Data Table?
\r
553 JZ @SVM_Setup_Table ; If so, Exit & get next Table
\r
555 OUT DX, AX ; Reprogram VGA CRTC reg
\r
556 JMP s @SVM_Setup_CRTC ; Process Next Table Entry
\r
558 ; Initialize Page & Scroll info, DI = 0
\r
561 MOV DISPLAY_PAGE, DI ; Display Page = 0
\r
562 MOV ACTIVE_PAGE, DI ; Active Page = 0
\r
563 MOV CURRENT_PAGE, DI ; Current Page (Offset) = 0
\r
564 MOV CURRENT_XOFFSET, DI ; Horz Scroll Index = 0
\r
565 MOV CURRENT_YOFFSET, DI ; Vert Scroll Index = 0
\r
566 MOV CURRENT_MOFFSET, DI ; Memory Scroll Index = 0
\r
568 MOV AX, VGA_SEGMENT ; Segment for VGA memory
\r
569 MOV CURRENT_SEGMENT, AX ; Save for Future LES's
\r
571 ; Set Logical Screen Width, X Scroll and Our Data
\r
573 MOV SI, [BP].SVM_Table ; Get Saved Ptr to Mode Info
\r
574 MOV AX, [BP].SVM_Xsize ; Get Display Width
\r
576 MOV CX, AX ; CX = Logical Width
\r
577 SUB CX, CS:[SI].M_XSize ; CX = Max X Scroll Value
\r
578 MOV MAX_XOFFSET, CX ; Set Maximum X Scroll
\r
580 SHR AX, 2 ; Bytes = Pixels / 4
\r
581 MOV SCREEN_WIDTH, AX ; Save Width in Pixels
\r
583 SHR AX, 1 ; Offset Value = Bytes / 2
\r
584 MOV AH, 13h ; CRTC Offset Register Index
\r
585 XCHG AL, AH ; Switch format for OUT
\r
586 OUT DX, AX ; Set VGA CRTC Offset Reg
\r
588 ; Setup Data table, Y Scroll, Misc for Other Routines
\r
590 MOV AX, [BP].SVM_Ysize ; Get Logical Screen Height
\r
592 MOV CX, AX ; CX = Logical Height
\r
593 SUB BX, CS:[SI].M_YSize ; CX = Max Y Scroll Value
\r
594 MOV MAX_YOFFSET, CX ; Set Maximum Y Scroll
\r
596 MOV SCREEN_HEIGHT, AX ; Save Height in Pixels
\r
597 MUL SCREEN_WIDTH ; AX = Page Size in Bytes,
\r
598 MOV PAGE_SIZE, AX ; Save Page Size
\r
600 MOV CX, [BP].SVM_Pages ; Get # of Pages
\r
601 MOV LAST_PAGE, CX ; Save # of Pages
\r
603 CLR BX ; Page # = 0
\r
604 MOV DX, BX ; Page 0 Offset = 0
\r
608 MOV PAGE_ADDR[BX], DX ; Set Page #(BX) Offset
\r
609 ADD BX, 2 ; Page#++
\r
610 ADD DX, AX ; Compute Addr of Next Page
\r
611 LOOPx CX, @SVM_Set_Pages ; Loop until all Pages Set
\r
615 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
616 LES DI, d CURRENT_PAGE ; -> Start of VGA memory
\r
619 CLD ; Block Xfer Forwards
\r
620 MOV CX, 8000H ; 32K * 4 * 2 = 256K
\r
621 REP STOSW ; Clear dat memory!
\r
623 ; Setup Font Pointers
\r
625 MOV BH, ROM_8x8_Lo ; Ask for 8x8 Font, 0-127
\r
626 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
627 INT 10h ; Call VGA BIOS
\r
629 MOV CHARSET_LOW, BP ; Save Char Set Offset
\r
630 MOV CHARSET_LOW+2, ES ; Save Char Set Segment
\r
632 MOV BH, ROM_8x8_Hi ; Ask for 8x8 Font, 128-255
\r
633 MOV AX, GET_CHAR_PTR ; Service to Get Pointer
\r
634 INT 10h ; Call VGA BIOS
\r
636 MOV CHARSET_HI, BP ; Save Char Set Offset
\r
637 MOV CHARSET_HI+2, ES ; Save Char Set Segment
\r
639 MOV AX, True ; Return Success Code
\r
642 ADD SP, 2 ; Deallocate workspace
\r
643 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
644 RET 8 ; Exit & Clean Up Stack
\r
649 ;==================
\r
650 ;SET_MODEX% (Mode%)
\r
651 ;==================
\r
653 ; Quickie Mode Set - Sets Up Mode X to Default Configuration
\r
655 ; ENTRY: ModeType = Desired Screen Resolution (0-7)
\r
656 ; (See SET_VGA_MODEX for list)
\r
658 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
664 SM_Mode DW ? ; Desired Screen Resolution
\r
671 PUSHx BP, SI ; Preserve Important registers
\r
672 MOV BP, SP ; Set up Stack Frame
\r
674 CLR AX ; Assume Failure
\r
675 MOV BX, [BP].SM_Mode ; Get Desired Mode #
\r
676 CMP BX, NUM_MODES ; Is it a Valid Mode #?
\r
677 JAE @SMX_Exit ; If Not, don't Bother
\r
679 PUSH BX ; Push Mode Parameter
\r
681 SHL BX, 1 ; Scale BX to word Index
\r
682 MOV SI, w MODE_TABLE[BX] ; CS:SI -> Mode Info
\r
684 PUSH CS:[SI].M_XSize ; Push Default X Size
\r
685 PUSH CS:[SI].M_Ysize ; Push Default Y size
\r
686 MOV AL, CS:[SI].M_Pages ; Get Default # of Pages
\r
687 CLR AH ; Hi Byte = 0
\r
688 PUSH AX ; Push # Pages
\r
690 CALL f SET_VGA_MODEX ; Set up Mode X!
\r
693 POPx SI, BP ; Restore Registers
\r
694 RET 2 ; Exit & Clean Up Stack
\r
699 ; ===== BASIC GRAPHICS PRIMITIVES =====
\r
701 ;============================
\r
702 ;CLEAR_VGA_SCREEN (ColorNum%)
\r
703 ;============================
\r
705 ; Clears the active display page
\r
707 ; ENTRY: ColorNum = Color Value to fill the page with
\r
709 ; EXIT: No meaningful values returned
\r
715 CVS_COLOR DB ?,? ; Color to Set Screen to
\r
718 PUBLIC CLEAR_VGA_SCREEN
\r
720 CLEAR_VGA_SCREEN PROC FAR
\r
722 PUSHx BP, DI ; Preserve Important Registers
\r
723 MOV BP, SP ; Set up Stack Frame
\r
725 OUT_16 SC_INDEX, ALL_PLANES_ON ; Select All Planes
\r
726 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
728 MOV AL, [BP].CVS_COLOR ; Get Color
\r
729 MOV AH, AL ; Copy for Word Write
\r
730 CLD ; Block fill Forwards
\r
732 MOV CX, PAGE_SIZE ; Get Size of Page
\r
733 SHR CX, 1 ; Divide by 2 for Words
\r
734 REP STOSW ; Block Fill VGA memory
\r
736 POPx DI, BP ; Restore Saved Registers
\r
737 RET 2 ; Exit & Clean Up Stack
\r
739 CLEAR_VGA_SCREEN ENDP
\r
742 ;===================================
\r
743 ;SET_POINT (Xpos%, Ypos%, ColorNum%)
\r
744 ;===================================
\r
746 ; Plots a single Pixel on the active display page
\r
748 ; ENTRY: Xpos = X position to plot pixel at
\r
749 ; Ypos = Y position to plot pixel at
\r
750 ; ColorNum = Color to plot pixel with
\r
752 ; EXIT: No meaningful values returned
\r
758 SETP_Color DB ?,? ; Color of Point to Plot
\r
759 SETP_Ypos DW ? ; Y pos of Point to Plot
\r
760 SETP_Xpos DW ? ; X pos of Point to Plot
\r
767 PUSHx BP, DI ; Preserve Registers
\r
768 MOV BP, SP ; Set up Stack Frame
\r
770 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
772 MOV AX, [BP].SETP_Ypos ; Get Line # of Pixel
\r
773 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
775 MOV BX, [BP].SETP_Xpos ; Get Xpos
\r
776 MOV CX, BX ; Copy to extract Plane # from
\r
777 SHR BX, 2 ; X offset (Bytes) = Xpos/4
\r
778 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
780 MOV AX, MAP_MASK_PLANE1 ; Map Mask & Plane Select Register
\r
781 AND CL, PLANE_BITS ; Get Plane Bits
\r
782 SHL AH, CL ; Get Plane Select Value
\r
783 OUT_16 SC_Index, AX ; Select Plane
\r
785 MOV AL,[BP].SETP_Color ; Get Pixel Color
\r
786 MOV ES:[DI+BX], AL ; Draw Pixel
\r
788 POPx DI, BP ; Restore Saved Registers
\r
789 RET 6 ; Exit and Clean up Stack
\r
794 ;==========================
\r
795 ;READ_POINT% (Xpos%, Ypos%)
\r
796 ;==========================
\r
798 ; Read the color of a pixel from the Active Display Page
\r
800 ; ENTRY: Xpos = X position of pixel to read
\r
801 ; Ypos = Y position of pixel to read
\r
803 ; EXIT: AX = Color of Pixel at (Xpos, Ypos)
\r
809 RP_Ypos DW ? ; Y pos of Point to Read
\r
810 RP_Xpos DW ? ; X pos of Point to Read
\r
815 READ_POINT PROC FAR
\r
817 PUSHx BP, DI ; Preserve Registers
\r
818 MOV BP, SP ; Set up Stack Frame
\r
820 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
822 MOV AX, [BP].RP_Ypos ; Get Line # of Pixel
\r
823 MUL SCREEN_WIDTH ; Get Offset to Start of Line
\r
825 MOV BX, [BP].RP_Xpos ; Get Xpos
\r
827 SHR BX, 2 ; X offset (Bytes) = Xpos/4
\r
828 ADD BX, AX ; Offset = Width*Ypos + Xpos/4
\r
830 MOV AL, READ_MAP ; GC Read Mask Register
\r
831 MOV AH, CL ; Get Xpos
\r
832 AND AH, PLANE_BITS ; & mask out Plane #
\r
833 OUT_16 GC_INDEX, AX ; Select Plane to read in
\r
835 CLR AH ; Clear Return Value Hi byte
\r
836 MOV AL, ES:[DI+BX] ; Get Color of Pixel
\r
838 POPx DI, BP ; Restore Saved Registers
\r
839 RET 4 ; Exit and Clean up Stack
\r
844 ;======================================================
\r
845 ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
846 ;======================================================
\r
848 ; Fills a rectangular block on the active display Page
\r
850 ; ENTRY: Xpos1 = Left X position of area to fill
\r
851 ; Ypos1 = Top Y position of area to fill
\r
852 ; Xpos2 = Right X position of area to fill
\r
853 ; Ypos2 = Bottom Y position of area to fill
\r
854 ; ColorNum = Color to fill area with
\r
856 ; EXIT: No meaningful values returned
\r
860 DW ?x4 ; DS, DI, SI, BP
\r
862 FB_Color DB ?,? ; Fill Color
\r
863 FB_Ypos2 DW ? ; Y pos of Lower Right Pixel
\r
864 FB_Xpos2 DW ? ; X pos of Lower Right Pixel
\r
865 FB_Ypos1 DW ? ; Y pos of Upper Left Pixel
\r
866 FB_Xpos1 DW ? ; X pos of Upper Left Pixel
\r
871 FILL_BLOCK PROC FAR
\r
873 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
874 MOV BP, SP ; Set up Stack Frame
\r
876 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
877 CLD ; Direction Flag = Forward
\r
879 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
881 ; Validate Pixel Coordinates
\r
882 ; If necessary, Swap so X1 <= X2, Y1 <= Y2
\r
884 MOV AX, [BP].FB_Ypos1 ; AX = Y1 is Y1< Y2?
\r
885 MOV BX, [BP].FB_Ypos2 ; BX = Y2
\r
889 MOV [BP].FB_Ypos1, BX ; Swap Y1 and Y2 and save Y1
\r
890 XCHG AX, BX ; on stack for future use
\r
893 SUB BX, AX ; Get Y width
\r
894 INC BX ; Add 1 to avoid 0 value
\r
895 MOV [BP].FB_Ypos2, BX ; Save in Ypos2
\r
897 MUL SCREEN_WIDTH ; Mul Y1 by Bytes per Line
\r
898 ADD DI, AX ; DI = Start of Line Y1
\r
900 MOV AX, [BP].FB_Xpos1 ; Check X1 <= X2
\r
901 MOV BX, [BP].FB_Xpos2 ;
\r
903 JLE @FB_NOSWAP2 ; Skip Ahead if Ok
\r
905 MOV [BP].FB_Xpos2, AX ; Swap X1 AND X2 and save X2
\r
906 XCHG AX, BX ; on stack for future use
\r
908 ; All our Input Values are in order, Now determine
\r
909 ; How many full "bands" 4 pixels wide (aligned) there
\r
910 ; are, and if there are partial bands (<4 pixels) on
\r
911 ; the left and right edges.
\r
914 MOV DX, AX ; DX = X1 (Pixel Position)
\r
915 SHR DX, 2 ; DX/4 = Bytes into Line
\r
916 ADD DI, DX ; DI = Addr of Upper-Left Corner
\r
918 MOV CX, BX ; CX = X2 (Pixel Position)
\r
919 SHR CX, 2 ; CX/4 = Bytes into Line
\r
921 CMP DX, CX ; Start and end in same band?
\r
922 JNE @FB_NORMAL ; if not, check for l & r edges
\r
923 JMP @FB_ONE_BAND_ONLY ; if so, then special processing
\r
926 SUB CX, DX ; CX = # bands -1
\r
927 MOV SI, AX ; SI = PLANE#(X1)
\r
928 AND SI, PLANE_BITS ; if Left edge is aligned then
\r
929 JZ @FB_L_PLANE_FLUSH ; no special processing..
\r
931 ; Draw "Left Edge" vertical strip of 1-3 pixels...
\r
933 OUT_8 SC_Data, Left_Clip_Mask[SI] ; Set Left Edge Plane Mask
\r
935 MOV SI, DI ; SI = Copy of Start Addr (UL)
\r
937 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
938 MOV AL, [BP].FB_Color ; Get Fill Color
\r
939 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
942 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
943 ADD SI, BX ; Point to Next Line (Below)
\r
944 LOOPjz DX, @FB_LEFT_CONT ; Exit loop if all Lines Drawn
\r
946 MOV ES:[SI], AL ; Fill in Left Edge Pixels
\r
947 ADD SI, BX ; Point to Next Line (Below)
\r
948 LOOPx DX, @FB_LEFT_LOOP ; loop until left strip is drawn
\r
952 INC DI ; Point to Middle (or Right) Block
\r
953 DEC CX ; Reset CX instead of JMP @FB_RIGHT
\r
956 INC CX ; Add in Left band to middle block
\r
958 ; DI = Addr of 1st middle Pixel (band) to fill
\r
959 ; CX = # of Bands to fill -1
\r
962 MOV SI, [BP].FB_Xpos2 ; Get Xpos2
\r
963 AND SI, PLANE_BITS ; Get Plane values
\r
964 CMP SI, 0003 ; Plane = 3?
\r
965 JE @FB_R_EDGE_FLUSH ; Hey, add to middle
\r
967 ; Draw "Right Edge" vertical strip of 1-3 pixels...
\r
969 OUT_8 SC_Data, Right_Clip_Mask[SI] ; Right Edge Plane Mask
\r
971 MOV SI, DI ; Get Addr of Left Edge
\r
972 ADD SI, CX ; Add Width-1 (Bands)
\r
973 DEC SI ; To point to top of Right Edge
\r
975 MOV DX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
976 MOV AL, [BP].FB_Color ; Get Fill Color
\r
977 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
980 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
981 ADD SI, BX ; Point to Next Line (Below)
\r
982 LOOPjz DX, @FB_RIGHT_CONT ; Exit loop if all Lines Drawn
\r
984 MOV ES:[SI], AL ; Fill in Right Edge Pixels
\r
985 ADD SI, BX ; Point to Next Line (Below)
\r
986 LOOPx DX, @FB_RIGHT_LOOP ; loop until left strip is drawn
\r
990 DEC CX ; Minus 1 for Middle bands
\r
991 JZ @FB_EXIT ; Uh.. no Middle bands...
\r
995 ; DI = Addr of Upper Left block to fill
\r
996 ; CX = # of Bands to fill in (width)
\r
998 OUT_8 SC_Data, ALL_PLANES ; Write to All Planes
\r
1000 MOV DX, SCREEN_WIDTH ; DX = DI Increment
\r
1001 SUB DX, CX ; = Screen_Width-# Planes Filled
\r
1003 MOV BX, CX ; BX = Quick Refill for CX
\r
1004 MOV SI, [BP].FB_Ypos2 ; SI = # of Line to Fill
\r
1005 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1008 REP STOSB ; Fill in entire line
\r
1010 MOV CX, BX ; Recharge CX (Line Width)
\r
1011 ADD DI, DX ; Point to start of Next Line
\r
1012 LOOPx SI, @FB_MIDDLE_LOOP ; Loop until all lines drawn
\r
1014 JMP s @FB_EXIT ; Outa here
\r
1016 @FB_ONE_BAND_ONLY:
\r
1017 MOV SI, AX ; Get Left Clip Mask, Save X1
\r
1018 AND SI, PLANE_BITS ; Mask out Row #
\r
1019 MOV AL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1020 MOV SI, BX ; Get Right Clip Mask, Save X2
\r
1021 AND SI, PLANE_BITS ; Mask out Row #
\r
1022 AND AL, Right_Clip_Mask[SI] ; Get Right Edge Mask byte
\r
1024 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
1026 MOV CX, [BP].FB_Ypos2 ; Get # of Lines to draw
\r
1027 MOV AL, [BP].FB_Color ; Get Fill Color
\r
1028 MOV BX, SCREEN_WIDTH ; Get Vertical increment Value
\r
1031 MOV ES:[DI], AL ; Fill in Pixels
\r
1032 ADD DI, BX ; Point to Next Line (Below)
\r
1033 LOOPjz CX, @FB_EXIT ; Exit loop if all Lines Drawn
\r
1035 MOV ES:[DI], AL ; Fill in Pixels
\r
1036 ADD DI, BX ; Point to Next Line (Below)
\r
1037 LOOPx CX, @FB_ONE_LOOP ; loop until left strip is drawn
\r
1040 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
1041 RET 10 ; Exit and Clean up Stack
\r
1046 ;=====================================================
\r
1047 ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
\r
1048 ;=====================================================
\r
1050 ; Draws a Line on the active display page
\r
1052 ; ENTRY: Xpos1 = X position of first point on line
\r
1053 ; Ypos1 = Y position of first point on line
\r
1054 ; Xpos2 = X position of last point on line
\r
1055 ; Ypos2 = Y position of last point on line
\r
1056 ; ColorNum = Color to draw line with
\r
1058 ; EXIT: No meaningful values returned
\r
1062 DW ?x3 ; DI, SI, BP
\r
1064 DL_ColorF DB ?,? ; Line Draw Color
\r
1065 DL_Ypos2 DW ? ; Y pos of last point
\r
1066 DL_Xpos2 DW ? ; X pos of last point
\r
1067 DL_Ypos1 DW ? ; Y pos of first point
\r
1068 DL_Xpos1 DW ? ; X pos of first point
\r
1073 DRAW_LINE PROC FAR
\r
1075 PUSHx BP, SI, DI ; Preserve Important Registers
\r
1076 MOV BP, SP ; Set up Stack Frame
\r
1077 CLD ; Direction Flag = Forward
\r
1079 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
1080 MOV CH, [BP].DL_ColorF ; Save Line Color in CH
\r
1084 MOV SI, [BP].DL_Xpos1 ; AX = X1 is X1< X2?
\r
1085 MOV DI, [BP].DL_Xpos2 ; DX = X2
\r
1086 CMP SI, DI ; Is X1 < X2
\r
1087 JE @DL_VLINE ; If X1=X2, Draw Vertical Line
\r
1088 JL @DL_NOSWAP1 ; If X1 < X2, don't swap
\r
1090 XCHG SI, DI ; X2 IS > X1, SO SWAP THEM
\r
1094 ; SI = X1, DI = X2
\r
1096 MOV AX, [BP].DL_Ypos1 ; AX = Y1 is Y1 <> Y2?
\r
1097 CMP AX, [BP].DL_Ypos2 ; Y1 = Y2?
\r
1098 JE @DL_HORZ ; If so, Draw a Horizontal Line
\r
1100 JMP @DL_BREZHAM ; Diagonal line... go do it...
\r
1102 ; This Code draws a Horizontal Line in Mode X where:
\r
1103 ; SI = X1, DI = X2, and AX = Y1/Y2
\r
1107 MUL SCREEN_WIDTH ; Offset = Ypos * Screen_Width
\r
1108 MOV DX, AX ; CX = Line offset into Page
\r
1110 MOV AX, SI ; Get Left edge, Save X1
\r
1111 AND SI, PLANE_BITS ; Mask out Row #
\r
1112 MOV BL, Left_Clip_Mask[SI] ; Get Left Edge Mask
\r
1113 MOV CX, DI ; Get Right edge, Save X2
\r
1114 AND DI, PLANE_BITS ; Mask out Row #
\r
1115 MOV BH, Right_Clip_Mask[DI] ; Get Right Edge Mask byte
\r
1117 SHR AX, 2 ; Get X1 Byte # (=X1/4)
\r
1118 SHR CX, 2 ; Get X2 Byte # (=X2/4)
\r
1120 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1121 ADD DI, DX ; Point to Start of Line
\r
1122 ADD DI, AX ; Point to Pixel X1
\r
1124 SUB CX, AX ; CX = # Of Bands (-1) to set
\r
1125 JNZ @DL_LONGLN ; jump if longer than one segment
\r
1127 AND BL, BH ; otherwise, merge clip masks
\r
1131 OUT_8 SC_Data, BL ; Set the Left Clip Mask
\r
1133 MOV AL, [BP].DL_ColorF ; Get Line Color
\r
1134 MOV BL, AL ; BL = Copy of Line Color
\r
1135 STOSB ; Set Left (1-4) Pixels
\r
1137 JCXZ @DL_EXIT ; Done if only one Line Segment
\r
1139 DEC CX ; CX = # of Middle Segments
\r
1140 JZ @DL_XRSEG ; If no middle segments....
\r
1142 ; Draw Middle Segments
\r
1144 OUT_8 DX, ALL_PLANES ; Write to ALL Planes
\r
1146 MOV AL, BL ; Get Color from BL
\r
1147 REP STOSB ; Draw Middle (4 Pixel) Segments
\r
1150 OUT_8 DX, BH ; Select Planes for Right Clip Mask
\r
1151 MOV AL, BL ; Get Color Value
\r
1152 STOSB ; Draw Right (1-4) Pixels
\r
1154 JMP s @DL_EXIT ; We Are Done...
\r
1157 ; This Code Draws A Vertical Line. On entry:
\r
1158 ; CH = Line Color, SI & DI = X1
\r
1162 MOV AX, [BP].DL_Ypos1 ; AX = Y1
\r
1163 MOV SI, [BP].DL_Ypos2 ; SI = Y2
\r
1164 CMP AX, SI ; Is Y1 < Y2?
\r
1165 JLE @DL_NOSWAP2 ; if so, Don't Swap them
\r
1167 XCHG AX, SI ; Ok, NOW Y1 < Y2
\r
1171 SUB SI, AX ; SI = Line Height (Y2-Y1+1)
\r
1174 ; AX = Y1, DI = X1, Get offset into Page into AX
\r
1176 MUL SCREEN_WIDTH ; Offset = Y1 (AX) * Screen Width
\r
1177 MOV DX, DI ; Copy Xpos into DX
\r
1178 SHR DI, 2 ; DI = Xpos/4
\r
1179 ADD AX, DI ; DI = Xpos/4 + ScreenWidth * Y1
\r
1181 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1182 ADD DI, AX ; Point to Pixel X1, Y1
\r
1186 MOV CL, DL ; CL = Save X1
\r
1187 AND CL, PLANE_BITS ; Get X1 MOD 4 (Plane #)
\r
1188 MOV AX, MAP_MASK_PLANE1 ; Code to set Plane #1
\r
1189 SHL AH, CL ; Change to Correct Plane #
\r
1190 OUT_16 SC_Index, AX ; Select Plane
\r
1192 MOV AL, CH ; Get Saved Color
\r
1193 MOV BX, SCREEN_WIDTH ; Get Offset to Advance Line By
\r
1196 MOV ES:[DI], AL ; Draw Single Pixel
\r
1197 ADD DI, BX ; Point to Next Line
\r
1198 LOOPjz SI, @DL_EXIT ; Lines--, Exit if done
\r
1200 MOV ES:[DI], AL ; Draw Single Pixel
\r
1201 ADD DI, BX ; Point to Next Line
\r
1202 LOOPx SI, @DL_VLoop ; Lines--, Loop until Done
\r
1206 JMP @DL_EXIT2 ; Done!
\r
1208 ; This code Draws a diagonal line in Mode X
\r
1211 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
1213 MOV AX, [BP].DL_Ypos1 ; get Y1 value
\r
1214 MOV BX, [BP].DL_Ypos2 ; get Y2 value
\r
1215 MOV CX, [BP].DL_Xpos1 ; Get Starting Xpos
\r
1217 CMP BX, AX ; Y2-Y1 is?
\r
1218 JNC @DL_DeltaYOK ; if Y2>=Y1 then goto...
\r
1220 XCHG BX, AX ; Swap em...
\r
1221 MOV CX, [BP].DL_Xpos2 ; Get New Starting Xpos
\r
1224 MUL SCREEN_WIDTH ; Offset = SCREEN_WIDTH * Y1
\r
1226 ADD DI, AX ; DI -> Start of Line Y1 on Page
\r
1227 MOV AX, CX ; AX = Xpos (X1)
\r
1228 SHR AX, 2 ; /4 = Byte Offset into Line
\r
1229 ADD DI, AX ; DI = Starting pos (X1,Y1)
\r
1231 MOV AL, 11h ; Staring Mask
\r
1232 AND CL, PLANE_BITS ; Get Plane #
\r
1233 SHL AL, CL ; and shift into place
\r
1234 MOV AH, [BP].DL_ColorF ; Color in Hi Bytes
\r
1236 PUSH AX ; Save Mask,Color...
\r
1238 MOV AH, AL ; Plane # in AH
\r
1239 MOV AL, MAP_MASK ; Select Plane Register
\r
1240 OUT_16 SC_Index, AX ; Select initial plane
\r
1242 MOV AX, [BP].DL_Xpos1 ; get X1 value
\r
1243 MOV BX, [BP].DL_Ypos1 ; get Y1 value
\r
1244 MOV CX, [BP].DL_Xpos2 ; get X2 value
\r
1245 MOV DX, [BP].DL_Ypos2 ; get Y2 value
\r
1247 MOV BP, SCREEN_WIDTH ; Use BP for Line width to
\r
1248 ; to avoid extra memory access
\r
1250 SUB DX, BX ; figure Delta_Y
\r
1251 JNC @DL_DeltaYOK2 ; jump if Y2 >= Y1
\r
1253 ADD BX, DX ; put Y2 into Y1
\r
1254 NEG DX ; abs(Delta_Y)
\r
1255 XCHG AX, CX ; and exchange X1 and X2
\r
1258 MOV BX, 08000H ; seed for fraction accumulator
\r
1260 SUB CX, AX ; figure Delta_X
\r
1261 JC @DL_DrawLeft ; if negative, go left
\r
1263 JMP @DL_DrawRight ; Draw Line that slopes right
\r
1267 NEG CX ; abs(Delta_X)
\r
1269 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1270 JB @DL_SteepLeft ; yes, so go do steep line
\r
1271 ; (Delta_Y iterations)
\r
1273 ; Draw a Shallow line to the left in Mode X
\r
1276 CLR AX ; zero low word of Delta_Y * 10000h
\r
1277 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1278 SBB DX, 0 ; include carry
\r
1279 DIV CX ; divide by Delta_X
\r
1281 MOV SI, BX ; SI = Accumulator
\r
1282 MOV BX, AX ; BX = Add fraction
\r
1283 POP AX ; Get Color, Bit mask
\r
1284 MOV DX, SC_Data ; Sequence controller data register
\r
1285 INC CX ; Inc Delta_X so we can unroll loop
\r
1287 ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down...
\r
1290 MOV ES:[DI], AH ; set first pixel, plane data set up
\r
1291 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1293 ADD SI, BX ; add numerator to accumulator
\r
1294 JNC @DL_SLLL2nc ; move down on carry
\r
1296 ADD DI, BP ; Move Down one line...
\r
1299 DEC DI ; Left one addr
\r
1300 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1301 CMP AL, 87h ; wrap?, if AL <88 then Carry set
\r
1302 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1303 OUT DX, AL ; Set up New Bit Plane mask
\r
1305 MOV ES:[DI], AH ; set pixel
\r
1306 LOOPjz CX, @DL_SLLExit ; Delta_X--, Exit if done
\r
1308 ADD SI, BX ; add numerator to accumulator,
\r
1309 JNC @DL_SLLL3nc ; move down on carry
\r
1311 ADD DI, BP ; Move Down one line...
\r
1313 @DL_SLLL3nc: ; Now move left a pixel...
\r
1314 DEC DI ; Left one addr
\r
1315 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1316 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1317 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1318 OUT DX, AL ; Set up New Bit Plane mask
\r
1319 JMP s @DL_SLLLoop ; loop until done
\r
1322 JMP @DL_EXIT2 ; and exit
\r
1324 ; Draw a steep line to the left in Mode X
\r
1327 CLR AX ; zero low word of Delta_Y * 10000h
\r
1328 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1329 DIV CX ; divide by Delta_Y
\r
1331 MOV SI, BX ; SI = Accumulator
\r
1332 MOV BX, AX ; BX = Add Fraction
\r
1333 POP AX ; Get Color, Bit mask
\r
1334 MOV DX, SC_Data ; Sequence controller data register
\r
1335 INC CX ; Inc Delta_Y so we can unroll loop
\r
1337 ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
\r
1341 MOV ES:[DI], AH ; set first pixel
\r
1342 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1344 ADD SI, BX ; add numerator to accumulator
\r
1345 JNC @DL_STLnc2 ; No carry, just move down!
\r
1347 DEC DI ; Move Left one addr
\r
1348 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1349 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1350 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1351 OUT DX, AL ; Set up New Bit Plane mask
\r
1354 ADD DI, BP ; advance to next line.
\r
1356 MOV ES:[DI], AH ; set pixel
\r
1357 LOOPjz CX, @DL_STLExit ; Delta_Y--, Exit if done
\r
1359 ADD SI, BX ; add numerator to accumulator
\r
1360 JNC @DL_STLnc3 ; No carry, just move down!
\r
1362 DEC DI ; Move Left one addr
\r
1363 ROR AL, 1 ; Move Left one plane, back on 0 1 2
\r
1364 CMP AL, 87h ; Wrap?, if AL <88 then Carry set
\r
1365 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1366 OUT DX, AL ; Set up New Bit Plane mask
\r
1369 ADD DI, BP ; advance to next line.
\r
1370 JMP s @DL_STLLoop ; Loop until done
\r
1373 JMP @DL_EXIT2 ; and exit
\r
1375 ; Draw a line that goes to the Right...
\r
1378 CMP CX, DX ; is Delta_X < Delta_Y?
\r
1379 JB @DL_SteepRight ; yes, so go do steep line
\r
1380 ; (Delta_Y iterations)
\r
1382 ; Draw a Shallow line to the Right in Mode X
\r
1385 CLR AX ; zero low word of Delta_Y * 10000h
\r
1386 SUB AX, DX ; DX:AX <- DX * 0FFFFh
\r
1387 SBB DX, 0 ; include carry
\r
1388 DIV CX ; divide by Delta_X
\r
1390 MOV SI, BX ; SI = Accumulator
\r
1391 MOV BX, AX ; BX = Add Fraction
\r
1392 POP AX ; Get Color, Bit mask
\r
1393 MOV DX, SC_Data ; Sequence controller data register
\r
1394 INC CX ; Inc Delta_X so we can unroll loop
\r
1396 ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down...
\r
1399 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1400 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1402 ADD SI, BX ; add numerator to accumulator
\r
1403 JNC @DL_SLR2nc ; don't move down if carry not set
\r
1405 ADD DI, BP ; Move Down one line...
\r
1407 @DL_SLR2nc: ; Now move right a pixel...
\r
1408 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1409 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1410 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1411 OUT DX, AL ; Set up New Bit Plane mask
\r
1413 MOV ES:[DI], AH ; set pixel
\r
1414 LOOPjz CX, @DL_SLRExit ; Delta_X--, Exit if done..
\r
1416 ADD SI, BX ; add numerator to accumulator
\r
1417 JNC @DL_SLR3nc ; don't move down if carry not set
\r
1419 ADD DI, BP ; Move Down one line...
\r
1422 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1423 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1424 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1425 OUT DX, AL ; Set up New Bit Plane mask
\r
1426 JMP s @DL_SLRLoop ; loop till done
\r
1429 JMP @DL_EXIT2 ; and exit
\r
1431 ; Draw a Steep line to the Right in Mode X
\r
1434 CLR AX ; zero low word of Delta_Y * 10000h
\r
1435 XCHG DX, CX ; Delta_Y switched with Delta_X
\r
1436 DIV CX ; divide by Delta_Y
\r
1438 MOV SI, BX ; SI = Accumulator
\r
1439 MOV BX, AX ; BX = Add Fraction
\r
1440 POP AX ; Get Color, Bit mask
\r
1441 MOV DX, SC_Data ; Sequence controller data register
\r
1442 INC CX ; Inc Delta_Y so we can unroll loop
\r
1444 ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
\r
1447 MOV ES:[DI], AH ; set first pixel, mask is set up
\r
1448 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1450 ADD SI, BX ; add numerator to accumulator
\r
1451 JNC @STRnc2 ; if no carry then just go down...
\r
1453 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1454 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1455 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1456 OUT DX, AL ; Set up New Bit Plane mask
\r
1459 ADD DI, BP ; advance to next line.
\r
1461 MOV ES:[DI], AH ; set pixel
\r
1462 LOOPjz CX, @DL_EXIT2 ; Delta_Y--, Exit if Done
\r
1464 ADD SI, BX ; add numerator to accumulator
\r
1465 JNC @STRnc3 ; if no carry then just go down...
\r
1467 ROL AL, 1 ; Move Right one addr if Plane = 0
\r
1468 CMP AL, 12h ; Wrap? if AL >12 then Carry not set
\r
1469 ADC DI, 0 ; Adjust Address: DI = DI + Carry
\r
1470 OUT DX, AL ; Set up New Bit Plane mask
\r
1473 ADD DI, BP ; advance to next line.
\r
1474 JMP s @STRLoop ; loop till done
\r
1477 POPx DI, SI, BP ; Restore Saved Registers
\r
1478 RET 10 ; Exit and Clean up Stack
\r
1483 ; ===== DAC COLOR REGISTER ROUTINES =====
\r
1485 ;=================================================
\r
1486 ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)
\r
1487 ;=================================================
\r
1489 ; Sets a single (RGB) Vga Palette Register
\r
1491 ; ENTRY: Register = The DAC # to modify (0-255)
\r
1492 ; Red = The new Red Intensity (0-63)
\r
1493 ; Green = The new Green Intensity (0-63)
\r
1494 ; Blue = The new Blue Intensity (0-63)
\r
1496 ; EXIT: No meaningful values returned
\r
1502 SDR_Blue DB ?,? ; Blue Data Value
\r
1503 SDR_Green DB ?,? ; Green Data Value
\r
1504 SDR_Red DB ?,? ; Red Data Value
\r
1505 SDR_Register DB ?,? ; Palette Register #
\r
1508 PUBLIC SET_DAC_REGISTER
\r
1510 SET_DAC_REGISTER PROC FAR
\r
1513 MOV BP, SP ; Set up Stack Frame
\r
1515 ; Select which DAC Register to modify
\r
1517 OUT_8 DAC_WRITE_ADDR, [BP].SDR_Register
\r
1519 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1520 OUT_8 DX, [BP].SDR_Red ; Set Red Intensity
\r
1521 OUT_8 DX, [BP].SDR_Green ; Set Green Intensity
\r
1522 OUT_8 DX, [BP].SDR_Blue ; Set Blue Intensity
\r
1524 POP BP ; Restore Registers
\r
1525 RET 8 ; Exit & Clean Up Stack
\r
1527 SET_DAC_REGISTER ENDP
\r
1529 ;====================================================
\r
1530 ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)
\r
1531 ;====================================================
\r
1533 ; Reads the RGB Values of a single Vga Palette Register
\r
1535 ; ENTRY: Register = The DAC # to read (0-255)
\r
1536 ; Red = Offset to Red Variable in DS
\r
1537 ; Green = Offset to Green Variable in DS
\r
1538 ; Blue = Offset to Blue Variable in DS
\r
1540 ; EXIT: The values of the integer variables Red,
\r
1541 ; Green, and Blue are set to the values
\r
1542 ; taken from the specified DAC register.
\r
1548 GDR_Blue DW ? ; Addr of Blue Data Value in DS
\r
1549 GDR_Green DW ? ; Addr of Green Data Value in DS
\r
1550 GDR_Red DW ? ; Addr of Red Data Value in DS
\r
1551 GDR_Register DB ?,? ; Palette Register #
\r
1554 PUBLIC GET_DAC_REGISTER
\r
1556 GET_DAC_REGISTER PROC FAR
\r
1559 MOV BP, SP ; Set up Stack Frame
\r
1561 ; Select which DAC Register to read in
\r
1563 OUT_8 DAC_READ_ADDR, [BP].GDR_Register
\r
1565 MOV DX, PEL_DATA_REG ; Dac Data Register
\r
1568 IN AL, DX ; Read Red Value
\r
1569 MOV BX, [BP].GDR_Red ; Get Address of Red%
\r
1570 MOV [BX], AX ; *Red% = AX
\r
1572 IN AL, DX ; Read Green Value
\r
1573 MOV BX, [BP].GDR_Green ; Get Address of Green%
\r
1574 MOV [BX], AX ; *Green% = AX
\r
1576 IN AL, DX ; Read Blue Value
\r
1577 MOV BX, [BP].GDR_Blue ; Get Address of Blue%
\r
1578 MOV [BX], AX ; *Blue% = AX
\r
1580 POP BP ; Restore Registers
\r
1581 RET 8 ; Exit & Clean Up Stack
\r
1583 GET_DAC_REGISTER ENDP
\r
1586 ;===========================================================
\r
1587 ;LOAD_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%, Sync%)
\r
1588 ;===========================================================
\r
1590 ; Sets a Block of Vga Palette Registers
\r
1592 ; ENTRY: PalData = Far Pointer to Block of palette data
\r
1593 ; StartReg = First Register # in range to set (0-255)
\r
1594 ; EndReg = Last Register # in Range to set (0-255)
\r
1595 ; Sync = Wait for Vertical Retrace Flag (Boolean)
\r
1597 ; EXIT: No meaningful values returned
\r
1599 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1600 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1604 DW ?x3 ; BP, DS, SI
\r
1606 LDR_Sync DW ? ; Vertical Sync Flag
\r
1607 LDR_EndReg DB ?,? ; Last Register #
\r
1608 LDR_StartReg DB ?,? ; First Register #
\r
1609 LDR_PalData DD ? ; Far Ptr to Palette Data
\r
1612 PUBLIC LOAD_DAC_REGISTERS
\r
1614 LOAD_DAC_REGISTERS PROC FAR
\r
1616 PUSHx BP, DS, SI ; Save Registers
\r
1617 mov BP, SP ; Set up Stack Frame
\r
1619 mov AX, [BP].LDR_Sync ; Get Vertical Sync Flag
\r
1620 or AX, AX ; is Sync Flag = 0?
\r
1621 jz @LDR_Load ; if so, skip call
\r
1623 call f SYNC_DISPLAY ; wait for vsync
\r
1625 ; Determine register #'s, size to copy, etc
\r
1629 lds SI, [BP].LDR_PalData ; DS:SI -> Palette Data
\r
1630 mov DX, DAC_WRITE_ADDR ; DAC register # selector
\r
1632 CLR AX, BX ; Clear for byte loads
\r
1633 mov AL, [BP].LDR_StartReg ; Get Start Register
\r
1634 mov BL, [BP].LDR_EndReg ; Get End Register
\r
1636 sub BX, AX ; BX = # of DAC registers -1
\r
1637 inc BX ; BX = # of DAC registers
\r
1638 mov CX, BX ; CX = # of DAC registers
\r
1639 add CX, BX ; CX = " " * 2
\r
1640 add CX, BX ; CX = " " * 3
\r
1641 cld ; Block OUTs forward
\r
1642 out DX, AL ; set up correct register #
\r
1644 ; Load a block of DAC Registers
\r
1646 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1648 rep outsb ; block set DAC registers
\r
1650 POPx SI, DS, BP ; Restore Registers
\r
1651 ret 10 ; Exit & Clean Up Stack
\r
1653 LOAD_DAC_REGISTERS ENDP
\r
1656 ;====================================================
\r
1657 ;READ_DAC_REGISTERS (SEG PalData, StartReg%, EndReg%)
\r
1658 ;====================================================
\r
1660 ; Reads a Block of Vga Palette Registers
\r
1662 ; ENTRY: PalData = Far Pointer to block to store palette data
\r
1663 ; StartReg = First Register # in range to read (0-255)
\r
1664 ; EndReg = Last Register # in Range to read (0-255)
\r
1666 ; EXIT: No meaningful values returned
\r
1668 ; NOTES: PalData is a linear array of 3 byte Palette values
\r
1669 ; in the order: Red (0-63), Green (0-63), Blue (0-63)
\r
1673 DW ?x3 ; BP, ES, DI
\r
1675 RDR_EndReg DB ?,? ; Last Register #
\r
1676 RDR_StartReg DB ?,? ; First Register #
\r
1677 RDR_PalData DD ? ; Far Ptr to Palette Data
\r
1680 PUBLIC READ_DAC_REGISTERS
\r
1682 READ_DAC_REGISTERS PROC FAR
\r
1684 PUSHx BP, ES, DI ; Save Registers
\r
1685 mov BP, SP ; Set up Stack Frame
\r
1687 ; Determine register #'s, size to copy, etc
\r
1689 les DI, [BP].RDR_PalData ; ES:DI -> Palette Buffer
\r
1690 mov DX, DAC_READ_ADDR ; DAC register # selector
\r
1692 CLR AX, BX ; Clear for byte loads
\r
1693 mov AL, [BP].RDR_StartReg ; Get Start Register
\r
1694 mov BL, [BP].RDR_EndReg ; Get End Register
\r
1696 sub BX, AX ; BX = # of DAC registers -1
\r
1697 inc BX ; BX = # of DAC registers
\r
1698 mov CX, BX ; CX = # of DAC registers
\r
1699 add CX, BX ; CX = " " * 2
\r
1700 add CX, BX ; CX = " " * 3
\r
1701 cld ; Block INs forward
\r
1703 ; Read a block of DAC Registers
\r
1705 out DX, AL ; set up correct register #
\r
1706 mov DX, PEL_DATA_REG ; Dac Data Register
\r
1708 rep insb ; block read DAC registers
\r
1710 POPx DI, ES, BP ; Restore Registers
\r
1711 ret 8 ; Exit & Clean Up Stack
\r
1713 READ_DAC_REGISTERS ENDP
\r
1716 ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====
\r
1718 ;=========================
\r
1719 ;SET_ACTIVE_PAGE (PageNo%)
\r
1720 ;=========================
\r
1722 ; Sets the active display Page to be used for future drawing
\r
1724 ; ENTRY: PageNo = Display Page to make active
\r
1725 ; (values: 0 to Number of Pages - 1)
\r
1727 ; EXIT: No meaningful values returned
\r
1733 SAP_Page DW ? ; Page # for Drawing
\r
1736 PUBLIC SET_ACTIVE_PAGE
\r
1738 SET_ACTIVE_PAGE PROC FAR
\r
1740 PUSH BP ; Preserve Registers
\r
1741 MOV BP, SP ; Set up Stack Frame
\r
1743 MOV BX, [BP].SAP_Page ; Get Desired Page #
\r
1744 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1745 JAE @SAP_Exit ; IF Not, Do Nothing
\r
1747 MOV ACTIVE_PAGE, BX ; Set Active Page #
\r
1749 SHL BX, 1 ; Scale Page # to Word
\r
1750 MOV AX, PAGE_ADDR[BX] ; Get offset to Page
\r
1752 MOV CURRENT_PAGE, AX ; And set for future LES's
\r
1755 POP BP ; Restore Registers
\r
1756 RET 2 ; Exit and Clean up Stack
\r
1758 SET_ACTIVE_PAGE ENDP
\r
1765 ; Returns the Video Page # currently used for Drawing
\r
1767 ; ENTRY: No Parameters are passed
\r
1769 ; EXIT: AX = Current Video Page used for Drawing
\r
1772 PUBLIC GET_ACTIVE_PAGE
\r
1774 GET_ACTIVE_PAGE PROC FAR
\r
1776 MOV AX, ACTIVE_PAGE ; Get Active Page #
\r
1777 RET ; Exit and Clean up Stack
\r
1779 GET_ACTIVE_PAGE ENDP
\r
1782 ;===============================
\r
1783 ;SET_DISPLAY_PAGE (DisplayPage%)
\r
1784 ;===============================
\r
1786 ; Sets the currently visible display page.
\r
1787 ; When called this routine syncronizes the display
\r
1788 ; to the vertical blank.
\r
1790 ; ENTRY: PageNo = Display Page to show on the screen
\r
1791 ; (values: 0 to Number of Pages - 1)
\r
1793 ; EXIT: No meaningful values returned
\r
1799 SDP_Page DW ? ; Page # to Display...
\r
1802 PUBLIC SET_DISPLAY_PAGE
\r
1804 SET_DISPLAY_PAGE PROC FAR
\r
1806 PUSH BP ; Preserve Registers
\r
1807 MOV BP, SP ; Set up Stack Frame
\r
1809 MOV BX, [BP].SDP_Page ; Get Desired Page #
\r
1810 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1811 JAE @SDP_Exit ; IF Not, Do Nothing
\r
1813 MOV DISPLAY_PAGE, BX ; Set Display Page #
\r
1815 SHL BX, 1 ; Scale Page # to Word
\r
1816 MOV CX, PAGE_ADDR[BX] ; Get offset in memory to Page
\r
1817 ADD CX, CURRENT_MOFFSET ; Adjust for any scrolling
\r
1819 ; Wait if we are currently in a Vertical Retrace
\r
1821 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1824 IN AL, DX ; Get VGA status
\r
1825 AND AL, VERT_RETRACE ; In Display mode yet?
\r
1826 JNZ @DP_WAIT0 ; If Not, wait for it
\r
1828 ; Set the Start Display Address to the new page
\r
1830 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
1832 MOV AL, START_DISP_LO ; Display Start Low Register
\r
1833 MOV AH, CL ; Low 8 Bits of Start Addr
\r
1834 OUT DX, AX ; Set Display Addr Low
\r
1836 MOV AL, START_DISP_HI ; Display Start High Register
\r
1837 MOV AH, CH ; High 8 Bits of Start Addr
\r
1838 OUT DX, AX ; Set Display Addr High
\r
1840 ; Wait for a Vertical Retrace to smooth out things
\r
1842 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1845 IN AL, DX ; Get VGA status
\r
1846 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
1847 JZ @DP_WAIT1 ; If Not, wait for it
\r
1849 ; Now Set Display Starting Address
\r
1853 POP BP ; Restore Registers
\r
1854 RET 2 ; Exit and Clean up Stack
\r
1856 SET_DISPLAY_PAGE ENDP
\r
1859 ;=================
\r
1860 ;GET_DISPLAY_PAGE%
\r
1861 ;=================
\r
1863 ; Returns the Video Page # currently displayed
\r
1865 ; ENTRY: No Parameters are passed
\r
1867 ; EXIT: AX = Current Video Page being displayed
\r
1870 PUBLIC GET_DISPLAY_PAGE
\r
1872 GET_DISPLAY_PAGE PROC FAR
\r
1874 MOV AX, DISPLAY_PAGE ; Get Display Page #
\r
1875 RET ; Exit & Clean Up Stack
\r
1877 GET_DISPLAY_PAGE ENDP
\r
1880 ;=======================================
\r
1881 ;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)
\r
1882 ;=======================================
\r
1884 ; Since a Logical Screen can be larger than the Physical
\r
1885 ; Screen, Scrolling is possible. This routine sets the
\r
1886 ; Upper Left Corner of the Screen to the specified Pixel.
\r
1887 ; Also Sets the Display page to simplify combined page
\r
1888 ; flipping and scrolling. When called this routine
\r
1889 ; syncronizes the display to the vertical blank.
\r
1891 ; ENTRY: DisplayPage = Display Page to show on the screen
\r
1892 ; Xpos = # of pixels to shift screen right
\r
1893 ; Ypos = # of lines to shift screen down
\r
1895 ; EXIT: No meaningful values returned
\r
1901 SW_Ypos DW ? ; Y pos of UL Screen Corner
\r
1902 SW_Xpos DW ? ; X pos of UL Screen Corner
\r
1903 SW_Page DW ? ; (new) Display Page
\r
1908 SET_WINDOW PROC FAR
\r
1910 PUSH BP ; Preserve Registers
\r
1911 MOV BP, SP ; Set up Stack Frame
\r
1913 ; Check if our Scroll Offsets are Valid
\r
1915 MOV BX, [BP].SW_Page ; Get Desired Page #
\r
1916 CMP BX, LAST_PAGE ; Is Page # Valid?
\r
1917 JAE @SW_Exit ; IF Not, Do Nothing
\r
1919 MOV AX, [BP].SW_Ypos ; Get Desired Y Offset
\r
1920 CMP AX, MAX_YOFFSET ; Is it Within Limits?
\r
1921 JA @SW_Exit ; if not, exit
\r
1923 MOV CX, [BP].SW_Xpos ; Get Desired X Offset
\r
1924 CMP CX, MAX_XOFFSET ; Is it Within Limits?
\r
1925 JA @SW_Exit ; if not, exit
\r
1927 ; Compute proper Display start address to use
\r
1929 MUL SCREEN_WIDTH ; AX = YOffset * Line Width
\r
1930 SHR CX, 2 ; CX / 4 = Bytes into Line
\r
1931 ADD AX, CX ; AX = Offset of Upper Left Pixel
\r
1933 MOV CURRENT_MOFFSET, AX ; Save Offset Info
\r
1935 MOV DISPLAY_PAGE, BX ; Set Current Page #
\r
1936 SHL BX, 1 ; Scale Page # to Word
\r
1937 ADD AX, PAGE_ADDR[BX] ; Get offset in VGA to Page
\r
1938 MOV BX, AX ; BX = Desired Display Start
\r
1940 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1942 ; Wait if we are currently in a Vertical Retrace
\r
1945 IN AL, DX ; Get VGA status
\r
1946 AND AL, VERT_RETRACE ; In Display mode yet?
\r
1947 JNZ @SW_WAIT0 ; If Not, wait for it
\r
1949 ; Set the Start Display Address to the new window
\r
1951 MOV DX, CRTC_Index ; We Change the VGA Sequencer
\r
1952 MOV AL, START_DISP_LO ; Display Start Low Register
\r
1953 MOV AH, BL ; Low 8 Bits of Start Addr
\r
1954 OUT DX, AX ; Set Display Addr Low
\r
1956 MOV AL, START_DISP_HI ; Display Start High Register
\r
1957 MOV AH, BH ; High 8 Bits of Start Addr
\r
1958 OUT DX, AX ; Set Display Addr High
\r
1960 ; Wait for a Vertical Retrace to smooth out things
\r
1962 MOV DX, INPUT_1 ; Input Status #1 Register
\r
1965 IN AL, DX ; Get VGA status
\r
1966 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
1967 JZ @SW_WAIT1 ; If Not, wait for it
\r
1969 ; Now Set the Horizontal Pixel Pan values
\r
1971 OUT_8 ATTRIB_Ctrl, PIXEL_PAN_REG ; Select Pixel Pan Register
\r
1973 MOV AX, [BP].SW_Xpos ; Get Desired X Offset
\r
1974 AND AL, 03 ; Get # of Pixels to Pan (0-3)
\r
1975 SHL AL, 1 ; Shift for 256 Color Mode
\r
1976 OUT DX, AL ; Fine tune the display!
\r
1979 POP BP ; Restore Saved Registers
\r
1980 RET 6 ; Exit and Clean up Stack
\r
1989 ; Returns the X coordinate of the Pixel currently display
\r
1990 ; in the upper left corner of the display
\r
1992 ; ENTRY: No Parameters are passed
\r
1994 ; EXIT: AX = Current Horizontal Scroll Offset
\r
1997 PUBLIC GET_X_OFFSET
\r
1999 GET_X_OFFSET PROC FAR
\r
2001 MOV AX, CURRENT_XOFFSET ; Get current horz offset
\r
2002 RET ; Exit & Clean Up Stack
\r
2011 ; Returns the Y coordinate of the Pixel currently display
\r
2012 ; in the upper left corner of the display
\r
2014 ; ENTRY: No Parameters are passed
\r
2016 ; EXIT: AX = Current Vertical Scroll Offset
\r
2019 PUBLIC GET_Y_OFFSET
\r
2021 GET_Y_OFFSET PROC FAR
\r
2023 MOV AX, CURRENT_YOFFSET ; Get current vertical offset
\r
2024 RET ; Exit & Clean Up Stack
\r
2033 ; Pauses the computer until the next Vertical Retrace starts
\r
2035 ; ENTRY: No Parameters are passed
\r
2037 ; EXIT: No meaningful values returned
\r
2040 PUBLIC SYNC_DISPLAY
\r
2042 SYNC_DISPLAY PROC FAR
\r
2044 MOV DX, INPUT_1 ; Input Status #1 Register
\r
2046 ; Wait for any current retrace to end
\r
2049 IN AL, DX ; Get VGA status
\r
2050 AND AL, VERT_RETRACE ; In Display mode yet?
\r
2051 JNZ @SD_WAIT0 ; If Not, wait for it
\r
2053 ; Wait for the start of the next vertical retrace
\r
2056 IN AL, DX ; Get VGA status
\r
2057 AND AL, VERT_RETRACE ; Vertical Retrace Start?
\r
2058 JZ @SD_WAIT1 ; If Not, wait for it
\r
2060 RET ; Exit & Clean Up Stack
\r
2065 ; ===== TEXT DISPLAY ROUTINES =====
\r
2067 ;==================================================
\r
2068 ;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2069 ;==================================================
\r
2071 ; Draws an ASCII Text Character using the currently selected
\r
2072 ; 8x8 font on the active display page. It would be a simple
\r
2073 ; exercise to make this routine process variable height fonts.
\r
2075 ; ENTRY: CharNum = ASCII character # to draw
\r
2076 ; Xpos = X position to draw Character at
\r
2077 ; Ypos = Y position of to draw Character at
\r
2078 ; ColorF = Color to draw text character in
\r
2079 ; ColorB = Color to set background to
\r
2081 ; EXIT: No meaningful values returned
\r
2085 GPC_Width DW ? ; Screen Width-1
\r
2086 GPC_Lines DB ?,? ; Scan lines to Decode
\r
2087 GPC_T_SETS DW ? ; Saved Charset Segment
\r
2088 GPC_T_SETO DW ? ; Saved Charset Offset
\r
2089 DW ?x4 ; DI, SI, DS, BP
\r
2091 GPC_ColorB DB ?,? ; Background Color
\r
2092 GPC_ColorF DB ?,? ; Text Color
\r
2093 GPC_Ypos DW ? ; Y Position to Print at
\r
2094 GPC_Xpos DW ? ; X position to Print at
\r
2095 GPC_Char DB ?,? ; Character to Print
\r
2102 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2103 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2104 MOV BP, SP ; Set up Stack Frame
\r
2106 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2108 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2109 MOV BX, AX ; BX = Screen Width
\r
2110 DEC BX ; = Screen Width-1
\r
2111 MOV [BP].GPC_Width, BX ; Save for later use
\r
2113 MUL [BP].GPC_Ypos ; Start of Line = Ypos * Width
\r
2114 ADD DI, AX ; DI -> Start of Line Ypos
\r
2116 MOV AX, [BP].GPC_Xpos ; Get Xpos of Character
\r
2117 MOV CX, AX ; Save Copy of Xpos
\r
2118 SHR AX, 2 ; Bytes into Line = Xpos/4
\r
2119 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2121 ;Get Source ADDR of Character Bit Map & Save
\r
2123 MOV AL, [BP].GPC_Char ; Get Character #
\r
2124 TEST AL, 080h ; Is Hi Bit Set?
\r
2125 JZ @GPC_LowChar ; Nope, use low char set ptr
\r
2127 AND AL, 07Fh ; Mask Out Hi Bit
\r
2128 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2129 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2130 JMP s @GPC_Set_Char ; Go Setup Character Ptr
\r
2134 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2135 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2138 MOV [BP].GPC_T_SETS, DX ; Save Segment on Stack
\r
2140 MOV AH, 0 ; Valid #'s are 0..127
\r
2141 SHL AX, 3 ; * 8 Bytes Per Bitmap
\r
2142 ADD BX, AX ; BX = Offset of Selected char
\r
2143 MOV [BP].GPC_T_SETO, BX ; Save Offset on Stack
\r
2145 AND CX, PLANE_BITS ; Get Plane #
\r
2146 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2147 SHL CH, CL ; And shift into position
\r
2148 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2150 MOV AL, 04 ; 4-Plane # = # of initial
\r
2151 SUB AL, CL ; shifts to align bit mask
\r
2152 MOV CL, AL ; Shift Count for SHL
\r
2154 ;Get segment of character map
\r
2156 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2157 INC DX ; DX -> SC_Data
\r
2159 MOV AL, 08 ; 8 Lines to Process
\r
2160 MOV [BP].GPC_Lines, AL ; Save on Stack
\r
2162 MOV DS, [BP].GPC_T_SETS ; Point to character set
\r
2164 @GPC_DECODE_CHAR_BYTE:
\r
2166 MOV SI, [BP].GPC_T_SETO ; Get DS:SI = String
\r
2168 MOV BH, [SI] ; Get Bit Map
\r
2169 INC SI ; Point to Next Line
\r
2170 MOV [BP].GPC_T_SETO, SI ; And save new Pointer...
\r
2175 ROL BX, CL ; BL holds left edge bits
\r
2176 MOV SI, BX ; Use as Table Index
\r
2177 AND SI, CHAR_BITS ; Get Low Bits
\r
2178 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2179 JZ @GPC_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2181 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2182 OUT DX, AL ; Set up Screen Mask
\r
2183 MOV ES:[DI], AH ; Write Foreground color
\r
2185 @GPC_NO_LEFT1BITS:
\r
2186 XOR AL, CH ; Invert mask for Background
\r
2187 JZ @GPC_NO_LEFT0BITS ; Hey, no need for this
\r
2189 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2190 OUT DX, AL ; Set up Screen Mask
\r
2191 MOV ES:[DI], AH ; Write Foreground color
\r
2193 ;Now Do Middle/Last Band
\r
2195 @GPC_NO_LEFT0BITS:
\r
2196 INC DI ; Point to next Byte
\r
2197 ROL BX, 4 ; Shift 4 bits
\r
2199 MOV SI, BX ; Make Lookup Pointer
\r
2200 AND SI, CHAR_BITS ; Get Low Bits
\r
2201 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2202 JZ @GPC_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2204 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2205 OUT DX, AL ; Set up Screen Mask
\r
2206 MOV ES:[DI], AH ; Write Foreground color
\r
2208 @GPC_NO_MIDDLE1BITS:
\r
2209 XOR AL, ALL_PLANES ; Invert mask for Background
\r
2210 JZ @GPC_NO_MIDDLE0BITS ; Hey, no need for this
\r
2212 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2213 OUT DX, AL ; Set up Screen Mask
\r
2214 MOV ES:[DI], AH ; Write Foreground color
\r
2216 @GPC_NO_MIDDLE0BITS:
\r
2217 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2218 CMP CL, 4 ; Aligned by 4?
\r
2219 JZ @GPC_NEXT_LINE ; If so, Exit now..
\r
2221 INC DI ; Point to next Byte
\r
2222 ROL BX, 4 ; Shift 4 bits
\r
2224 MOV SI, BX ; Make Lookup Pointer
\r
2225 AND SI, CHAR_BITS ; Get Low Bits
\r
2226 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2227 JZ @GPC_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2229 MOV AH, [BP].GPC_ColorF ; Get Foreground Color
\r
2230 OUT DX, AL ; Set up Screen Mask
\r
2231 MOV ES:[DI], AH ; Write Foreground color
\r
2233 @GPC_NO_RIGHT1BITS:
\r
2235 XOR AL, CH ; Invert mask for Background
\r
2236 JZ @GPC_NO_RIGHT0BITS ; Hey, no need for this
\r
2238 MOV AH, [BP].GPC_ColorB ; Get background Color
\r
2239 OUT DX, AL ; Set up Screen Mask
\r
2240 MOV ES:[DI], AH ; Write Foreground color
\r
2242 @GPC_NO_RIGHT0BITS:
\r
2243 DEC DI ; Adjust for Next Line Advance
\r
2246 ADD DI, [BP].GPC_Width ; Point to Next Line
\r
2247 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2249 DEC [BP].GPC_Lines ; Count Down Lines
\r
2250 JZ @GPC_EXIT ; Ok... Done!
\r
2252 JMP @GPC_DECODE_CHAR_BYTE ; Again! Hey!
\r
2255 ADD SP, 08 ; Deallocate stack workspace
\r
2256 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2257 RET 10 ; Exit and Clean up Stack
\r
2262 ;==========================================
\r
2263 ;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)
\r
2264 ;==========================================
\r
2266 ; Transparently draws an ASCII Text Character using the
\r
2267 ; currently selected 8x8 font on the active display page.
\r
2269 ; ENTRY: CharNum = ASCII character # to draw
\r
2270 ; Xpos = X position to draw Character at
\r
2271 ; Ypos = Y position of to draw Character at
\r
2272 ; ColorF = Color to draw text character in
\r
2274 ; EXIT: No meaningful values returned
\r
2278 TGP_Width DW ? ; Screen Width-1
\r
2279 TGP_Lines DB ?,? ; Scan lines to Decode
\r
2280 TGP_T_SETS DW ? ; Saved Charset Segment
\r
2281 TGP_T_SETO DW ? ; Saved Charset Offset
\r
2282 DW ?x4 ; DI, SI, DS, BP
\r
2284 TGP_ColorF DB ?,? ; Text Color
\r
2285 TGP_Ypos DW ? ; Y Position to Print at
\r
2286 TGP_Xpos DW ? ; X position to Print at
\r
2287 TGP_Char DB ?,? ; Character to Print
\r
2294 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2295 SUB SP, 8 ; Allocate WorkSpace on Stack
\r
2296 MOV BP, SP ; Set up Stack Frame
\r
2298 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2300 MOV AX, SCREEN_WIDTH ; Get Logical Line Width
\r
2301 MOV BX, AX ; BX = Screen Width
\r
2302 DEC BX ; = Screen Width-1
\r
2303 MOV [BP].TGP_Width, BX ; Save for later use
\r
2305 MUL [BP].TGP_Ypos ; Start of Line = Ypos * Width
\r
2306 ADD DI, AX ; DI -> Start of Line Ypos
\r
2308 MOV AX, [BP].TGP_Xpos ; Get Xpos of Character
\r
2309 MOV CX, AX ; Save Copy of Xpos
\r
2310 SHR AX, 2 ; Bytes into Line = Xpos/4
\r
2311 ADD DI, AX ; DI -> (Xpos, Ypos)
\r
2313 ;Get Source ADDR of Character Bit Map & Save
\r
2315 MOV AL, [BP].TGP_Char ; Get Character #
\r
2316 TEST AL, 080h ; Is Hi Bit Set?
\r
2317 JZ @TGP_LowChar ; Nope, use low char set ptr
\r
2319 AND AL, 07Fh ; Mask Out Hi Bit
\r
2320 MOV BX, CHARSET_HI ; BX = Char Set Ptr:Offset
\r
2321 MOV DX, CHARSET_HI+2 ; DX = Char Set Ptr:Segment
\r
2322 JMP s @TGP_Set_Char ; Go Setup Character Ptr
\r
2326 MOV BX, CHARSET_LOW ; BX = Char Set Ptr:Offset
\r
2327 MOV DX, CHARSET_LOW+2 ; DX = Char Set Ptr:Segment
\r
2330 MOV [BP].TGP_T_SETS, DX ; Save Segment on Stack
\r
2332 MOV AH, 0 ; Valid #'s are 0..127
\r
2333 SHL AX, 3 ; * 8 Bytes Per Bitmap
\r
2334 ADD BX, AX ; BX = Offset of Selected char
\r
2335 MOV [BP].TGP_T_SETO, BX ; Save Offset on Stack
\r
2337 AND CX, PLANE_BITS ; Get Plane #
\r
2338 MOV CH, ALL_PLANES ; Get Initial Plane mask
\r
2339 SHL CH, CL ; And shift into position
\r
2340 AND CH, ALL_PLANES ; And mask to lower nibble
\r
2342 MOV AL, 04 ; 4-Plane # = # of initial
\r
2343 SUB AL, CL ; shifts to align bit mask
\r
2344 MOV CL, AL ; Shift Count for SHL
\r
2346 ;Get segment of character map
\r
2348 OUT_8 SC_Index, MAP_MASK ; Setup Plane selections
\r
2349 INC DX ; DX -> SC_Data
\r
2351 MOV AL, 08 ; 8 Lines to Process
\r
2352 MOV [BP].TGP_Lines, AL ; Save on Stack
\r
2354 MOV DS, [BP].TGP_T_SETS ; Point to character set
\r
2356 @TGP_DECODE_CHAR_BYTE:
\r
2358 MOV SI, [BP].TGP_T_SETO ; Get DS:SI = String
\r
2360 MOV BH, [SI] ; Get Bit Map
\r
2361 INC SI ; Point to Next Line
\r
2362 MOV [BP].TGP_T_SETO, SI ; And save new Pointer...
\r
2364 MOV AH, [BP].TGP_ColorF ; Get Foreground Color
\r
2367 ROL BX, CL ; BL holds left edge bits
\r
2368 MOV SI, BX ; Use as Table Index
\r
2369 AND SI, CHAR_BITS ; Get Low Bits
\r
2370 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2371 JZ @TGP_NO_LEFT1BITS ; Skip if No Pixels to set
\r
2373 OUT DX, AL ; Set up Screen Mask
\r
2374 MOV ES:[DI], AH ; Write Foreground color
\r
2376 ;Now Do Middle/Last Band
\r
2378 @TGP_NO_LEFT1BITS:
\r
2380 INC DI ; Point to next Byte
\r
2381 ROL BX, 4 ; Shift 4 bits
\r
2383 MOV SI, BX ; Make Lookup Pointer
\r
2384 AND SI, CHAR_BITS ; Get Low Bits
\r
2385 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2386 JZ @TGP_NO_MIDDLE1BITS ; Skip if no pixels to set
\r
2388 OUT DX, AL ; Set up Screen Mask
\r
2389 MOV ES:[DI], AH ; Write Foreground color
\r
2391 @TGP_NO_MIDDLE1BITS:
\r
2392 XOR CH, ALL_PLANES ; Invert Clip Mask
\r
2393 CMP CL, 4 ; Aligned by 4?
\r
2394 JZ @TGP_NEXT_LINE ; If so, Exit now..
\r
2396 INC DI ; Point to next Byte
\r
2397 ROL BX, 4 ; Shift 4 bits
\r
2399 MOV SI, BX ; Make Lookup Pointer
\r
2400 AND SI, CHAR_BITS ; Get Low Bits
\r
2401 MOV AL, Char_Plane_Data[SI] ; Get Mask in AL
\r
2402 JZ @TGP_NO_RIGHT1BITS ; Skip if No Pixels to set
\r
2404 OUT DX, AL ; Set up Screen Mask
\r
2405 MOV ES:[DI], AH ; Write Foreground color
\r
2407 @TGP_NO_RIGHT1BITS:
\r
2409 DEC DI ; Adjust for Next Line Advance
\r
2412 ADD DI, [BP].TGP_Width ; Point to Next Line
\r
2413 XOR CH, CHAR_BITS ; Flip the Clip mask back
\r
2415 DEC [BP].TGP_Lines ; Count Down Lines
\r
2416 JZ @TGP_EXIT ; Ok... Done!
\r
2418 JMP @TGP_DECODE_CHAR_BYTE ; Again! Hey!
\r
2421 ADD SP, 08 ; Deallocate stack workspace
\r
2422 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2423 RET 8 ; Exit and Clean up Stack
\r
2428 ;===============================================================
\r
2429 ;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2430 ;===============================================================
\r
2432 ; Routine to quickly Print a null terminated ASCII string on the
\r
2433 ; active display page up to a maximum length.
\r
2435 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2436 ; MaxLen = # of characters to print if no null found
\r
2437 ; Xpos = X position to draw Text at
\r
2438 ; Ypos = Y position of to draw Text at
\r
2439 ; ColorF = Color to draw text in
\r
2440 ; ColorB = Color to set background to
\r
2442 ; EXIT: No meaningful values returned
\r
2446 DW ?x4 ; DI, SI, DS, BP
\r
2448 PS_ColorB DW ? ; Background Color
\r
2449 PS_ColorF DW ? ; Text Color
\r
2450 PS_Ypos DW ? ; Y Position to Print at
\r
2451 PS_Xpos DW ? ; X position to Print at
\r
2452 PS_Len DW ? ; Maximum Length of string to print
\r
2453 PS_Text DW ?,? ; Far Ptr to Text String
\r
2458 PRINT_STR PROC FAR
\r
2460 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2461 MOV BP, SP ; Set up Stack Frame
\r
2465 MOV CX, [BP].PS_Len ; Get Remaining text Length
\r
2466 JCXZ @PS_Exit ; Exit when out of text
\r
2468 LES DI, d [BP].PS_Text ; ES:DI -> Current Char in Text
\r
2469 MOV AL, ES:[DI] ; AL = Text Character
\r
2470 AND AX, 00FFh ; Clear High Word
\r
2471 JZ @PS_Exit ; Exit if null character
\r
2473 DEC [BP].PS_Len ; Remaining Text length--
\r
2474 INC [BP].PS_Text ; Point to Next text char
\r
2476 ; Set up Call to GPRINTC
\r
2478 PUSH AX ; Set Character Parameter
\r
2479 MOV BX, [BP].PS_Xpos ; Get Xpos
\r
2480 PUSH BX ; Set Xpos Parameter
\r
2481 ADD BX, 8 ; Advance 1 Char to Right
\r
2482 MOV [BP].PS_Xpos, BX ; Save for next time through
\r
2484 MOV BX, [BP].PS_Ypos ; Get Ypos
\r
2485 PUSH BX ; Set Ypos Parameter
\r
2487 MOV BX, [BP].PS_ColorF ; Get Text Color
\r
2488 PUSH BX ; Set ColorF Parameter
\r
2490 MOV BX, [BP].PS_ColorB ; Get Background Color
\r
2491 PUSH BX ; Set ColorB Parameter
\r
2493 CALL f GPRINTC ; Print Character!
\r
2494 JMP s @PS_Print_It ; Process next character
\r
2497 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2498 RET 14 ; Exit and Clean up Stack
\r
2503 ;================================================================
\r
2504 ;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
\r
2505 ;================================================================
\r
2507 ; Routine to quickly transparently Print a null terminated ASCII
\r
2508 ; string on the active display page up to a maximum length.
\r
2510 ; ENTRY: String = Far Pointer to ASCII string to print
\r
2511 ; MaxLen = # of characters to print if no null found
\r
2512 ; Xpos = X position to draw Text at
\r
2513 ; Ypos = Y position of to draw Text at
\r
2514 ; ColorF = Color to draw text in
\r
2516 ; EXIT: No meaningful values returned
\r
2520 DW ?x4 ; DI, SI, DS, BP
\r
2522 TPS_ColorF DW ? ; Text Color
\r
2523 TPS_Ypos DW ? ; Y Position to Print at
\r
2524 TPS_Xpos DW ? ; X position to Print at
\r
2525 TPS_Len DW ? ; Maximum Length of string to print
\r
2526 TPS_Text DW ?,? ; Far Ptr to Text String
\r
2531 TPRINT_STR PROC FAR
\r
2533 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2534 MOV BP, SP ; Set up Stack Frame
\r
2538 MOV CX, [BP].TPS_Len ; Get Remaining text Length
\r
2539 JCXZ @TPS_Exit ; Exit when out of text
\r
2541 LES DI, d [BP].TPS_Text ; ES:DI -> Current Char in Text
\r
2542 MOV AL, ES:[DI] ; AL = Text Character
\r
2543 AND AX, 00FFh ; Clear High Word
\r
2544 JZ @TPS_Exit ; Exit if null character
\r
2546 DEC [BP].TPS_Len ; Remaining Text length--
\r
2547 INC [BP].TPS_Text ; Point to Next text char
\r
2549 ; Set up Call to TGPRINTC
\r
2551 PUSH AX ; Set Character Parameter
\r
2552 MOV BX, [BP].TPS_Xpos ; Get Xpos
\r
2553 PUSH BX ; Set Xpos Parameter
\r
2554 ADD BX, 8 ; Advance 1 Char to Right
\r
2555 MOV [BP].TPS_Xpos, BX ; Save for next time through
\r
2557 MOV BX, [BP].TPS_Ypos ; Get Ypos
\r
2558 PUSH BX ; Set Ypos Parameter
\r
2560 MOV BX, [BP].TPS_ColorF ; Get Text Color
\r
2561 PUSH BX ; Set ColorF Parameter
\r
2563 CALL f TGPRINTC ; Print Character!
\r
2564 JMP s @TPS_Print_It ; Process next character
\r
2567 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2568 RET 12 ; Exit and Clean up Stack
\r
2573 ;===========================================
\r
2574 ;SET_DISPLAY_FONT(SEG FontData, FontNumber%)
\r
2575 ;===========================================
\r
2577 ; Allows the user to specify their own font data for
\r
2578 ; wither the lower or upper 128 characters.
\r
2580 ; ENTRY: FontData = Far Pointer to Font Bitmaps
\r
2581 ; FontNumber = Which half of set this is
\r
2582 ; = 0, Lower 128 characters
\r
2583 ; = 1, Upper 128 characters
\r
2585 ; EXIT: No meaningful values returned
\r
2591 SDF_Which DW ? ; Hi Table/Low Table Flag
\r
2592 SDF_Font DD ? ; Far Ptr to Font Table
\r
2595 PUBLIC SET_DISPLAY_FONT
\r
2597 SET_DISPLAY_FONT PROC FAR
\r
2599 PUSH BP ; Preserve Registers
\r
2600 MOV BP, SP ; Set up Stack Frame
\r
2602 LES DI, [BP].SDF_Font ; Get Far Ptr to Font
\r
2604 MOV SI, o CHARSET_LOW ; Assume Lower 128 chars
\r
2605 TEST [BP].SDF_Which, 1 ; Font #1 selected?
\r
2606 JZ @SDF_Set_Font ; If not, skip ahead
\r
2608 MOV SI, o CHARSET_HI ; Ah, really it's 128-255
\r
2611 MOV [SI], DI ; Set Font Pointer Offset
\r
2612 MOV [SI+2], ES ; Set Font Pointer Segment
\r
2614 POP BP ; Restore Registers
\r
2615 RET 6 ; We are Done.. Outa here
\r
2617 SET_DISPLAY_FONT ENDP
\r
2620 ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====
\r
2622 ;======================================================
\r
2623 ;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2624 ;======================================================
\r
2626 ; Draws a variable sized Graphics Bitmap such as a
\r
2627 ; picture or an Icon on the current Display Page in
\r
2628 ; Mode X. The Bitmap is stored in a linear byte array
\r
2629 ; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)
\r
2630 ; This is the same linear manner as mode 13h graphics.
\r
2632 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2633 ; Xpos = X position to Place Upper Left pixel at
\r
2634 ; Ypos = Y position to Place Upper Left pixel at
\r
2635 ; Width = Width of the Bitmap in Pixels
\r
2636 ; Height = Height of the Bitmap in Pixels
\r
2638 ; EXIT: No meaningful values returned
\r
2642 DB_LineO DW ? ; Offset to Next Line
\r
2643 DB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2644 DB_Start DW ? ; Addr of Upper Left Pixel
\r
2645 DB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2646 DB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2647 DW ?x4 ; DI, SI, DS, BP
\r
2649 DB_Height DW ? ; Height of Bitmap in Pixels
\r
2650 DB_Width DW ? ; Width of Bitmap in Pixels
\r
2651 DB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2652 DB_Xpos DW ? ; X position to Draw Bitmap at
\r
2653 DB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2656 PUBLIC DRAW_BITMAP
\r
2658 DRAW_BITMAP PROC FAR
\r
2660 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2661 SUB SP, 10 ; Allocate workspace
\r
2662 MOV BP, SP ; Set up Stack Frame
\r
2664 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2665 CLD ; Direction Flag = Forward
\r
2667 MOV AX, [BP].DB_Ypos ; Get UL Corner Ypos
\r
2668 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
2670 MOV BX, [BP].DB_Xpos ; Get UL Corner Xpos
\r
2671 MOV CL, BL ; Save Plane # in CL
\r
2672 SHR BX, 2 ; Xpos/4 = Offset Into Line
\r
2674 ADD DI, AX ; ES:DI -> Start of Line
\r
2675 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
2676 MOV [BP].DB_Start, DI ; Save Starting Addr
\r
2678 ; Compute line to line offset
\r
2680 MOV BX, [BP].DB_Width ; Get Width of Image
\r
2681 MOV DX, BX ; Save Copy in DX
\r
2682 SHR BX, 2 ; /4 = width in bands
\r
2683 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
2684 SUB AX, BX ; - (Bitmap Width/4)
\r
2686 MOV [BP].DB_LineO, AX ; Save Line Width offset
\r
2687 MOV [BP].DB_PixCount, BX ; Minimum # pix to copy
\r
2689 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
2690 MOV [BP].DB_PixSkew, DX ; Also End of Line Skew
\r
2691 MOV [BP].DB_SkewFlag, DX ; Save as Flag/Count
\r
2693 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
2694 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
2695 SHL AH, CL ; Select correct Plane
\r
2696 OUT_16 SC_Index, AX ; Select Plane...
\r
2697 MOV BH, AH ; BH = Saved Plane Mask
\r
2698 MOV BL, 4 ; BL = Planes to Copy
\r
2702 LDS SI, [BP].DB_Image ; DS:SI-> Source Image
\r
2703 MOV DX, [BP].DB_Height ; # of Lines to Copy
\r
2704 MOV DI, [BP].DB_Start ; ES:DI-> Dest pos
\r
2707 MOV CX, [BP].DB_PixCount ; Min # to copy
\r
2709 TEST CL, 0FCh ; 16+PixWide?
\r
2710 JZ @DB_COPY_REMAINDER ; Nope...
\r
2712 ; Pixel Copy loop has been unrolled to x4
\r
2715 MOVSB ; Copy Bitmap Pixel
\r
2716 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2717 MOVSB ; Copy Bitmap Pixel
\r
2718 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2719 MOVSB ; Copy Bitmap Pixel
\r
2720 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2721 MOVSB ; Copy Bitmap Pixel
\r
2722 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2724 SUB CL, 4 ; Pixels to Copy=-4
\r
2725 TEST CL, 0FCh ; 4+ Pixels Left?
\r
2726 JNZ @DB_COPY_LOOP ; if so, do another block
\r
2728 @DB_COPY_REMAINDER:
\r
2729 JCXZ @DB_NEXT_LINE ; Any Pixels left on line
\r
2732 MOVSB ; Copy Bitmap Pixel
\r
2733 ADD SI,3 ; Skip to Next Byte in same plane
\r
2734 LOOPx CX, @DB_COPY2 ; Pixels to Copy--, Loop until done
\r
2738 ; any Partial Pixels? (some planes only)
\r
2740 OR CX, [BP].DB_SkewFlag ; Get Skew Count
\r
2741 JZ @DB_NEXT2 ; if no partial pixels
\r
2743 MOVSB ; Copy Bitmap Pixel
\r
2744 DEC DI ; Back up to align
\r
2745 DEC SI ; Back up to align
\r
2748 ADD SI, [BP].DB_PixSkew ; Adjust Skew
\r
2749 ADD DI, [BP].DB_LineO ; Set to Next Display Line
\r
2750 LOOPx DX, @DB_COPY_LINE ; Lines to Copy--, Loop if more
\r
2752 ; Copy Next Plane....
\r
2754 DEC BL ; Planes to Go--
\r
2755 JZ @DB_Exit ; Hey! We are done
\r
2757 ROL BH, 1 ; Next Plane in line...
\r
2758 OUT_8 SC_Data, BH ; Select Plane
\r
2760 CMP AL, 12h ; Carry Set if AL=11h
\r
2761 ADC [BP].DB_Start, 0 ; Screen Addr =+Carry
\r
2762 INC w [BP].DB_Image ; Start @ Next Byte
\r
2764 SUB [BP].DB_SkewFlag, 1 ; Reduce Planes to Skew
\r
2765 ADC [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1
\r
2767 JMP s @DB_COPY_PLANE ; Go Copy the Next Plane
\r
2770 ADD SP, 10 ; Deallocate workspace
\r
2771 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2772 RET 12 ; Exit and Clean up Stack
\r
2777 ;=======================================================
\r
2778 ;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
\r
2779 ;=======================================================
\r
2781 ; Transparently Draws a variable sized Graphics Bitmap
\r
2782 ; such as a picture or an Icon on the current Display Page
\r
2783 ; in Mode X. Pixels with a value of 0 are not drawn,
\r
2784 ; leaving the previous "background" contents intact.
\r
2786 ; The Bitmap format is the same as for the DRAW_BITMAP function.
\r
2788 ; ENTRY: Image = Far Pointer to Bitmap Data
\r
2789 ; Xpos = X position to Place Upper Left pixel at
\r
2790 ; Ypos = Y position to Place Upper Left pixel at
\r
2791 ; Width = Width of the Bitmap in Pixels
\r
2792 ; Height = Height of the Bitmap in Pixels
\r
2794 ; EXIT: No meaningful values returned
\r
2798 TB_LineO DW ? ; Offset to Next Line
\r
2799 TB_PixCount DW ? ; (Minimum) # of Pixels/Line
\r
2800 TB_Start DW ? ; Addr of Upper Left Pixel
\r
2801 TB_PixSkew DW ? ; # of bytes to Adjust EOL
\r
2802 TB_SkewFlag DW ? ; Extra Pix on Plane Flag
\r
2803 DW ?x4 ; DI, SI, DS, BP
\r
2805 TB_Height DW ? ; Height of Bitmap in Pixels
\r
2806 TB_Width DW ? ; Width of Bitmap in Pixels
\r
2807 TB_Ypos DW ? ; Y position to Draw Bitmap at
\r
2808 TB_Xpos DW ? ; X position to Draw Bitmap at
\r
2809 TB_Image DD ? ; Far Pointer to Graphics Bitmap
\r
2812 PUBLIC TDRAW_BITMAP
\r
2814 TDRAW_BITMAP PROC FAR
\r
2816 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2817 SUB SP, 10 ; Allocate workspace
\r
2818 MOV BP, SP ; Set up Stack Frame
\r
2820 LES DI, d CURRENT_PAGE ; Point to Active VGA Page
\r
2821 CLD ; Direction Flag = Forward
\r
2823 MOV AX, [BP].TB_Ypos ; Get UL Corner Ypos
\r
2824 MUL SCREEN_WIDTH ; AX = Offset to Line Ypos
\r
2826 MOV BX, [BP].TB_Xpos ; Get UL Corner Xpos
\r
2827 MOV CL, BL ; Save Plane # in CL
\r
2828 SHR BX, 2 ; Xpos/4 = Offset Into Line
\r
2830 ADD DI, AX ; ES:DI -> Start of Line
\r
2831 ADD DI, BX ; ES:DI -> Upper Left Pixel
\r
2832 MOV [BP].TB_Start, DI ; Save Starting Addr
\r
2834 ; Compute line to line offset
\r
2836 MOV BX, [BP].TB_Width ; Get Width of Image
\r
2837 MOV DX, BX ; Save Copy in DX
\r
2838 SHR BX, 2 ; /4 = width in bands
\r
2839 MOV AX, SCREEN_WIDTH ; Get Screen Width
\r
2840 SUB AX, BX ; - (Bitmap Width/4)
\r
2842 MOV [BP].TB_LineO, AX ; Save Line Width offset
\r
2843 MOV [BP].TB_PixCount, BX ; Minimum # pix to copy
\r
2845 AND DX, PLANE_BITS ; Get "partial band" size (0-3)
\r
2846 MOV [BP].TB_PixSkew, DX ; Also End of Line Skew
\r
2847 MOV [BP].TB_SkewFlag, DX ; Save as Flag/Count
\r
2849 AND CX, PLANE_BITS ; CL = Starting Plane #
\r
2850 MOV AX, MAP_MASK_PLANE2 ; Plane Mask & Plane Select
\r
2851 SHL AH, CL ; Select correct Plane
\r
2852 OUT_16 SC_Index, AX ; Select Plane...
\r
2853 MOV BH, AH ; BH = Saved Plane Mask
\r
2854 MOV BL, 4 ; BL = Planes to Copy
\r
2858 LDS SI, [BP].TB_Image ; DS:SI-> Source Image
\r
2859 MOV DX, [BP].TB_Height ; # of Lines to Copy
\r
2860 MOV DI, [BP].TB_Start ; ES:DI-> Dest pos
\r
2862 ; Here AH is set with the value to be considered
\r
2863 ; "Transparent". It can be changed!
\r
2865 MOV AH, 0 ; Value to Detect 0
\r
2868 MOV CX, [BP].TB_PixCount ; Min # to copy
\r
2870 TEST CL, 0FCh ; 16+PixWide?
\r
2871 JZ @TB_COPY_REMAINDER ; Nope...
\r
2873 ; Pixel Copy loop has been unrolled to x4
\r
2876 LODSB ; Get Pixel Value in AL
\r
2877 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2878 CMP AL, AH ; It is "Transparent"?
\r
2879 JE @TB_SKIP_01 ; Skip ahead if so
\r
2880 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
2883 LODSB ; Get Pixel Value in AL
\r
2884 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2885 CMP AL, AH ; It is "Transparent"?
\r
2886 JE @TB_SKIP_02 ; Skip ahead if so
\r
2887 MOV ES:[DI+1], AL ; Copy Pixel to VGA screen
\r
2890 LODSB ; Get Pixel Value in AL
\r
2891 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2892 CMP AL, AH ; It is "Transparent"?
\r
2893 JE @TB_SKIP_03 ; Skip ahead if so
\r
2894 MOV ES:[DI+2], AL ; Copy Pixel to VGA screen
\r
2897 LODSB ; Get Pixel Value in AL
\r
2898 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2899 CMP AL, AH ; It is "Transparent"?
\r
2900 JE @TB_SKIP_04 ; Skip ahead if so
\r
2901 MOV ES:[DI+3], AL ; Copy Pixel to VGA screen
\r
2904 ADD DI, 4 ; Adjust Pixel Write Location
\r
2905 SUB CL, 4 ; Pixels to Copy=-4
\r
2906 TEST CL, 0FCh ; 4+ Pixels Left?
\r
2907 JNZ @TB_COPY_LOOP ; if so, do another block
\r
2909 @TB_COPY_REMAINDER:
\r
2910 JCXZ @TB_NEXT_LINE ; Any Pixels left on line
\r
2913 LODSB ; Get Pixel Value in AL
\r
2914 ADD SI, 3 ; Skip to Next Byte in same plane
\r
2915 CMP AL, AH ; It is "Transparent"?
\r
2916 JE @TB_SKIP_05 ; Skip ahead if so
\r
2917 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
2920 INC DI ; Advance Dest Addr
\r
2921 LOOPx CX, @TB_COPY2 ; Pixels to Copy--, Loop until done
\r
2925 ; any Partial Pixels? (some planes only)
\r
2927 OR CX, [BP].TB_SkewFlag ; Get Skew Count
\r
2928 JZ @TB_NEXT2 ; if no partial pixels
\r
2930 LODSB ; Get Pixel Value in AL
\r
2931 DEC SI ; Backup to Align
\r
2932 CMP AL, AH ; It is "Transparent"?
\r
2933 JE @TB_NEXT2 ; Skip ahead if so
\r
2934 MOV ES:[DI], AL ; Copy Pixel to VGA screen
\r
2937 ADD SI, [BP].TB_PixSkew ; Adjust Skew
\r
2938 ADD DI, [BP].TB_LineO ; Set to Next Display Line
\r
2939 LOOPx DX, @TB_COPY_LINE ; Lines to Copy--, Loop if More
\r
2941 ;Copy Next Plane....
\r
2943 DEC BL ; Planes to Go--
\r
2944 JZ @TB_Exit ; Hey! We are done
\r
2946 ROL BH, 1 ; Next Plane in line...
\r
2947 OUT_8 SC_Data, BH ; Select Plane
\r
2949 CMP AL, 12h ; Carry Set if AL=11h
\r
2950 ADC [BP].TB_Start, 0 ; Screen Addr =+Carry
\r
2951 INC w [BP].TB_Image ; Start @ Next Byte
\r
2953 SUB [BP].TB_SkewFlag, 1 ; Reduce Planes to Skew
\r
2954 ADC [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1
\r
2956 JMP @TB_COPY_PLANE ; Go Copy the next Plane
\r
2959 ADD SP, 10 ; Deallocate workspace
\r
2960 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
2961 RET 12 ; Exit and Clean up Stack
\r
2966 ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====
\r
2968 ;==================================
\r
2969 ;COPY_PAGE (SourcePage%, DestPage%)
\r
2970 ;==================================
\r
2972 ; Duplicate on display page onto another
\r
2974 ; ENTRY: SourcePage = Display Page # to Duplicate
\r
2975 ; DestPage = Display Page # to hold copy
\r
2977 ; EXIT: No meaningful values returned
\r
2981 DW ?x4 ; DI, SI, DS, BP
\r
2983 CP_DestP DW ? ; Page to hold copied image
\r
2984 CP_SourceP DW ? ; Page to Make copy from
\r
2989 COPY_PAGE PROC FAR
\r
2991 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
2992 MOV BP, SP ; Set up Stack Frame
\r
2993 CLD ; Block Xfer Forwards
\r
2995 ; Make sure Page #'s are valid
\r
2997 MOV AX, [BP].CP_SourceP ; Get Source Page #
\r
2998 CMP AX, LAST_PAGE ; is it > Max Page #?
\r
2999 JAE @CP_Exit ; if so, abort
\r
3001 MOV BX, [BP].CP_DestP ; Get Destination Page #
\r
3002 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3003 JAE @CP_Exit ; if so, abort
\r
3005 CMP AX, BX ; Pages #'s the same?
\r
3006 JE @CP_Exit ; if so, abort
\r
3008 ; Setup DS:SI and ES:DI to Video Pages
\r
3010 SHL BX, 1 ; Scale index to Word
\r
3011 MOV DI, PAGE_ADDR[BX] ; Offset to Dest Page
\r
3013 MOV BX, AX ; Index to Source page
\r
3014 SHL BX, 1 ; Scale index to Word
\r
3015 MOV SI, PAGE_ADDR[BX] ; Offset to Source Page
\r
3017 MOV CX, PAGE_SIZE ; Get size of Page
\r
3018 MOV AX, CURRENT_SEGMENT ; Get Video Mem Segment
\r
3019 MOV ES, AX ; ES:DI -> Dest Page
\r
3020 MOV DS, AX ; DS:SI -> Source Page
\r
3022 ; Setup VGA registers for Mem to Mem copy
\r
3024 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3025 OUT_16 SC_Index, ALL_PLANES_ON ; Copy all Planes
\r
3027 ; Note.. Do *NOT* use MOVSW or MOVSD - they will
\r
3028 ; Screw with the latches which are 8 bits x 4
\r
3030 REP MOVSB ; Copy entire Page!
\r
3032 ; Reset VGA for normal memory access
\r
3034 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = off
\r
3037 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3038 RET 4 ; Exit and Clean up Stack
\r
3043 ;==========================================================================
\r
3044 ;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)
\r
3045 ;==========================================================================
\r
3047 ; Copies a Bitmap Image from one Display Page to Another
\r
3048 ; This Routine is Limited to copying Images with the same
\r
3049 ; Plane Alignment. To Work: (X1 MOD 4) must = (DestX1 MOD 4)
\r
3050 ; Copying an Image to the Same Page is supported, but results
\r
3051 ; may be defined when the when the rectangular areas
\r
3052 ; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) -
\r
3053 ; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...
\r
3054 ; No Paramter checking to done to insure that
\r
3055 ; X2 >= X1 and Y2 >= Y1. Be Careful...
\r
3057 ; ENTRY: SourcePage = Display Page # with Source Image
\r
3058 ; X1 = Upper Left Xpos of Source Image
\r
3059 ; Y1 = Upper Left Ypos of Source Image
\r
3060 ; X2 = Lower Right Xpos of Source Image
\r
3061 ; Y2 = Lower Right Ypos of Source Image
\r
3062 ; DestPage = Display Page # to copy Image to
\r
3063 ; DestX1 = Xpos to Copy UL Corner of Image to
\r
3064 ; DestY1 = Ypos to Copy UL Corner of Image to
\r
3066 ; EXIT: AX = Success Flag: 0 = Failure / -1= Success
\r
3070 CB_Height DW ? ; Height of Image in Lines
\r
3071 CB_Width DW ? ; Width of Image in "bands"
\r
3072 DW ?x4 ; DI, SI, DS, BP
\r
3074 CB_DestY1 DW ? ; Destination Ypos
\r
3075 CB_DestX1 DW ? ; Destination Xpos
\r
3076 CB_DestP DW ? ; Page to Copy Bitmap To
\r
3077 CB_Y2 DW ? ; LR Ypos of Image
\r
3078 CB_X2 DW ? ; LR Xpos of Image
\r
3079 CB_Y1 DW ? ; UL Ypos of Image
\r
3080 CB_X1 DW ? ; UL Xpos of Image
\r
3081 CB_SourceP DW ? ; Page containing Source Bitmap
\r
3084 PUBLIC COPY_BITMAP
\r
3086 COPY_BITMAP PROC FAR
\r
3088 PUSHx BP, DS, SI, DI ; Preserve Important Registers
\r
3089 SUB SP, 4 ; Allocate WorkSpace on Stack
\r
3090 MOV BP, SP ; Set up Stack Frame
\r
3092 ; Prep Registers (and keep jumps short!)
\r
3094 MOV ES, CURRENT_SEGMENT ; ES -> VGA Ram
\r
3095 CLD ; Block Xfer Forwards
\r
3097 ; Make sure Parameters are valid
\r
3099 MOV BX, [BP].CB_SourceP ; Get Source Page #
\r
3100 CMP BX, LAST_PAGE ; is it > Max Page #?
\r
3101 JAE @CB_Abort ; if so, abort
\r
3103 MOV CX, [BP].CB_DestP ; Get Destination Page #
\r
3104 CMP CX, LAST_PAGE ; is it > Max Page #?
\r
3105 JAE @CB_Abort ; if so, abort
\r
3107 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3108 XOR AX, [BP].CB_DestX1 ; Compare Bits 0-1
\r
3109 AND AX, PLANE_BITS ; Check Plane Bits
\r
3110 JNZ @CB_Abort ; They should cancel out
\r
3112 ; Setup for Copy processing
\r
3114 OUT_8 SC_INDEX, MAP_MASK ; Set up for Plane Select
\r
3115 OUT_16 GC_Index, LATCHES_ON ; Data from Latches = on
\r
3117 ; Compute Info About Images, Setup ES:SI & ES:DI
\r
3119 MOV AX, [BP].CB_Y2 ; Height of Bitmap in lines
\r
3120 SUB AX, [BP].CB_Y1 ; is Y2 - Y1 + 1
\r
3121 INC AX ; (add 1 since were not 0 based)
\r
3122 MOV [BP].CB_Height, AX ; Save on Stack for later use
\r
3124 MOV AX, [BP].CB_X2 ; Get # of "Bands" of 4 Pixels
\r
3125 MOV DX, [BP].CB_X1 ; the Bitmap Occupies as X2-X1
\r
3126 SHR AX, 2 ; Get X2 Band (X2 / 4)
\r
3127 SHR DX, 2 ; Get X1 Band (X1 / 4)
\r
3128 SUB AX, DX ; AX = # of Bands - 1
\r
3129 INC AX ; AX = # of Bands
\r
3130 MOV [BP].CB_Width, AX ; Save on Stack for later use
\r
3132 SHL BX, 1 ; Scale Source Page to Word
\r
3133 MOV SI, PAGE_ADDR[BX] ; SI = Offset of Source Page
\r
3134 MOV AX, [BP].CB_Y1 ; Get Source Y1 Line
\r
3135 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3136 ADD SI, AX ; SI = Offset to Line Y1
\r
3137 MOV AX, [BP].CB_X1 ; Get Source X1
\r
3138 SHR AX, 2 ; X1 / 4 = Byte offset
\r
3139 ADD SI, AX ; SI = Byte Offset to (X1,Y1)
\r
3141 MOV BX, CX ; Dest Page Index to BX
\r
3142 SHL BX, 1 ; Scale Source Page to Word
\r
3143 MOV DI, PAGE_ADDR[BX] ; DI = Offset of Dest Page
\r
3144 MOV AX, [BP].CB_DestY1 ; Get Dest Y1 Line
\r
3145 MUL SCREEN_WIDTH ; AX = Offset to Line Y1
\r
3146 ADD DI, AX ; DI = Offset to Line Y1
\r
3147 MOV AX, [BP].CB_DestX1 ; Get Dest X1
\r
3148 SHR AX, 2 ; X1 / 4 = Byte offset
\r
3149 ADD DI, AX ; DI = Byte Offset to (D-X1,D-Y1)
\r
3151 MOV CX, [BP].CB_Width ; CX = Width of Image (Bands)
\r
3153 JE @CB_Only_One_Band ; 0 Means Image Width of 1 Band
\r
3155 MOV BX, [BP].CB_X1 ; Get Source X1
\r
3156 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 00?)
\r
3157 JZ @CB_Check_Right ; if so, check right alignment
\r
3158 JNZ @CB_Left_Band ; not aligned? well..
\r
3161 CLR AX ; Return False (Failure)
\r
3162 JMP @CB_Exit ; and Finish Up
\r
3164 ; Copy when Left & Right Clip Masks overlap...
\r
3166 @CB_Only_One_Band:
\r
3167 MOV BX, [BP].CB_X1 ; Get Left Clip Mask
\r
3168 AND BX, PLANE_BITS ; Mask out Row #
\r
3169 MOV AL, Left_Clip_Mask[BX] ; Get Left Edge Mask
\r
3170 MOV BX, [BP].CB_X2 ; Get Right Clip Mask
\r
3171 AND BX, PLANE_BITS ; Mask out Row #
\r
3172 AND AL, Right_Clip_Mask[BX] ; Get Right Edge Mask byte
\r
3174 OUT_8 SC_Data, AL ; Clip For Left & Right Masks
\r
3176 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3177 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3178 CLR BX ; BX = Offset into Image
\r
3181 MOV AL, ES:[SI+BX] ; Load Latches
\r
3182 MOV ES:[DI+BX], AL ; Unload Latches
\r
3183 ADD BX, DX ; Advance Offset to Next Line
\r
3184 LOOPjz CX, @CB_One_Done ; Exit Loop if Finished
\r
3186 MOV AL, ES:[SI+BX] ; Load Latches
\r
3187 MOV ES:[DI+BX], AL ; Unload Latches
\r
3188 ADD BX, DX ; Advance Offset to Next Line
\r
3189 LOOPx CX, @CB_One_Loop ; Loop until Finished
\r
3192 JMP @CB_Finish ; Outa Here!
\r
3194 ; Copy Left Edge of Bitmap
\r
3198 OUT_8 SC_Data, Left_Clip_Mask[BX] ; Set Left Edge Plane Mask
\r
3200 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3201 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3202 CLR BX ; BX = Offset into Image
\r
3205 MOV AL, ES:[SI+BX] ; Load Latches
\r
3206 MOV ES:[DI+BX], AL ; Unload Latches
\r
3207 ADD BX, DX ; Advance Offset to Next Line
\r
3208 LOOPjz CX, @CB_Left_Done ; Exit Loop if Finished
\r
3210 MOV AL, ES:[SI+BX] ; Load Latches
\r
3211 MOV ES:[DI+BX], AL ; Unload Latches
\r
3212 ADD BX, DX ; Advance Offset to Next Line
\r
3213 LOOPx CX, @CB_Left_Loop ; Loop until Finished
\r
3216 INC DI ; Move Dest Over 1 band
\r
3217 INC SI ; Move Source Over 1 band
\r
3218 DEC [BP].CB_Width ; Band Width--
\r
3220 ; Determine if Right Edge of Bitmap needs special copy
\r
3223 MOV BX, [BP].CB_X2 ; Get Source X2
\r
3224 AND BX, PLANE_BITS ; Aligned? (bits 0-1 = 11?)
\r
3225 CMP BL, 03h ; Plane = 3?
\r
3226 JE @CB_Copy_Middle ; Copy the Middle then!
\r
3228 ; Copy Right Edge of Bitmap
\r
3232 OUT_8 SC_Data, Right_Clip_Mask[BX] ; Set Right Edge Plane Mask
\r
3234 DEC [BP].CB_Width ; Band Width--
\r
3235 MOV CX, [BP].CB_Height ; CX = # of Lines to Copy
\r
3236 MOV DX, SCREEN_WIDTH ; DX = Width of Screen
\r
3237 MOV BX, [BP].CB_Width ; BX = Offset to Right Edge
\r
3240 MOV AL, ES:[SI+BX] ; Load Latches
\r
3241 MOV ES:[DI+BX], AL ; Unload Latches
\r
3242 ADD BX, DX ; Advance Offset to Next Line
\r
3243 LOOPjz CX, @CB_Right_Done ; Exit Loop if Finished
\r
3245 MOV AL, ES:[SI+BX] ; Load Latches
\r
3246 MOV ES:[DI+BX], AL ; Unload Latches
\r
3247 ADD BX, DX ; Advance Offset to Next Line
\r
3248 LOOPx CX, @CB_Right_Loop ; Loop until Finished
\r
3252 ; Copy the Main Block of the Bitmap
\r
3256 MOV CX, [BP].CB_Width ; Get Width Remaining
\r
3257 JCXZ @CB_Finish ; Exit if Done
\r
3259 OUT_8 SC_Data, ALL_PLANES ; Copy all Planes
\r
3261 MOV DX, SCREEN_WIDTH ; Get Width of Screen minus
\r
3262 SUB DX, CX ; Image width (for Adjustment)
\r
3263 MOV AX, [BP].CB_Height ; AX = # of Lines to Copy
\r
3264 MOV BX, CX ; BX = Quick REP reload count
\r
3265 MOV CX, ES ; Move VGA Segment
\r
3266 MOV DS, CX ; Into DS
\r
3268 ; Actual Copy Loop. REP MOVSB does the work
\r
3271 MOV CX, BX ; Recharge Rep Count
\r
3272 REP MOVSB ; Move Bands
\r
3273 LOOPjz AX, @CB_Finish ; Exit Loop if Finished
\r
3275 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3276 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3278 MOV CX, BX ; Recharge Rep Count
\r
3279 REP MOVSB ; Move Bands
\r
3281 ADD SI, DX ; Adjust DS:SI to Next Line
\r
3282 ADD DI, DX ; Adjust ES:DI to Next Line
\r
3283 LOOPx AX, @CB_Middle_Copy ; Copy Lines until Done
\r
3286 OUT_16 GC_Index, LATCHES_OFF ; Data from Latches = on
\r
3289 ADD SP, 04 ; Deallocate stack workspace
\r
3290 POPx DI, SI, DS, BP ; Restore Saved Registers
\r
3291 RET 16 ; Exit and Clean up Stack
\r
3295 END ; End of Code Segment
\r