EarthWeb   
   datamation.com Brought to you by EarthWeb

HomeSubscribeSearchFAQSitemapContact Us
     

   

  Search Tips
  Advanced Search
   
  

  
Go to ITKnowledge Enterprise

Zen of Graphics Programming, 2nd Edition Zen of Graphics Programming, 2nd Edition
by Michael Abrash
Coriolis, The Coriolis Group
ISBN: 1883577896   Pub Date: 04/01/96

Search this book:
 
Previous Table of Contents Next


The Split Screen in Action

All of the above points are illustrated by Listing 8.1. Listing 8.1 fills display memory starting at offset zero (the split screen area of memory) with text identifying the split screen, fills display memory starting at offset 8000H with a graphics pattern, and sets the start address to 8000H. At this point, the normal screen is being displayed (the split screen start scan line is still set to the BIOS default setting, with all bits equal to 1, so the split screen is off), with the pixels based on the contents of display memory at offset 8000H. The contents of display memory between offset 0 and offset 7FFFH are not visible at all.

LISTING 8.1 L8-1.ASM

; Demonstrates the VGA/EGA split screen in action.
;
;*********************************************************************
IS_VGA              equ 1 ;set to 0 to assemble for EGA
;
VGA_SEGMENT         equ 0a000h
SCREEN_WIDTH        equ 640
SCREEN_HEIGHT       equ 350
CRTC_INDEX          equ 3d4h ;CRT Controller Index register
OVERFLOW            equ 7    ;index of Overflow reg in CRTC
MAXIMUM_SCAN_LINE   equ 9    ;index of Maximum Scan Line register
                             ; in CRTC
START_ADDRESS_HIGH  equ 0ch  ;index of Start Address High register
                             ; in CRTC
START_ADDRESS_LOW   equ 0dh  ;index of Start Address Low register
                             ; in CRTC
LINE_COMPARE        equ 18h  ;index of Line Compare reg (bits 7-0
                             ; of split screen start scan line)
                             ; in CRTC
INPUT_STATUS_0      equ 3dah ;Input Status 0 register
WORD_OUTS_OK        equ 1    ;set to 0 to assemble for
                             ; computers that can't handle
                             ; word outs to indexed VGA registers
;*********************************************************************
; Macro to output a word value to a port.
;
OUT_WORD        macro
if WORD_OUTS_OK
       out      dx,ax
else
       out      dx,al
       inc      dx
       xchg     ah,al
       out      dx,al
       dec      dx
       xchg     ah,al
endif
       endm
;*********************************************************************
MyStack segment para stack 'STACK'
        db      512 dup (0)
MyStack ends
;*********************************************************************
Data    segment
SplitScreenLine dw   ?         ;line the split screen currently
                               ; starts after
StartAddress    dw   ?         ;display memory offset at which
                               ; scanning for video data starts
; Message displayed in split screen.
SplitScreenMsg db  'Split screen text row #'
DigitInsert        dw  ?
                   db  '...$'
Data   ends
;*********************************************************************
Code    segment
        assume cs:Code, ds:Data
;*********************************************************************
Start   proc   near
        mov    ax,Data
        mov    ds,ax
;
; Select mode 10h, 640x350 16-color graphics mode.
;
        mov    ax,0010h                   ;AH=0 is select mode function
                                          ;AL=10h is mode to select,
                                          ; 640x350 16-color graphics mode
        int    10h
;
; Put text into display memory starting at offset 0, with each row
; labelled as to number. This is the part of memory that will be
; displayed in the split screen portion of the display.
;
        mov    cx,25                      ;# of lines of text we'll draw into
                                          ; the split screen part of memory
FillSplitScreenLoop:
        mov    ah,2                       ;set cursor location function #
        sub    bh,bh                      ;set cursor in page 0
        mov    dh,25
        sub    dh,cl                      ;calculate row to draw in
        sub    dl,dl                      ;start in column 0
        int    10h                        ;set the cursor location
        mov    al,25
        sub    al,cl                      ;calculate row to draw in again
        sub    ah,ah                      ;make the value a word for division
        mov    dh,10
        div    dh                         ;split the row # into two digits
        add    ax,'00'                    ;convert the digits to ASCII
        mov    [DigitInsert],ax           ;put the digits into the text
                                          ; to be displayed
        mov    ah,9
        mov    dx,offset SplitScreenMsg
        int 21h                           ;print the text
        loop   FillSplitScreenLoop
;
; Fill display memory starting at 8000h with a diagonally striped
; pattern.
;
        mov    ax,VGA_SEGMENT
        mov    es,ax
        mov    di,8000h
        mov    dx,SCREEN_HEIGHT           ;fill all lines
        mov    ax,8888h                   ;starting fill pattern
        cld
RowLoop:
        mov    cx,SCREEN_WIDTH/8/2        ;fill 1 scan line a word at a time
        rep    stosw                      ;fill the scan line
        ror    ax,1                       ;shift pattern word
        dec    dx
        jnz    RowLoop
;
; Set the start address to 8000h and display that part of memory.
;
        mov    [StartAddress],8000h
        call   SetStartAddress
;
; Slide the split screen half way up the screen and then back down
; a quarter of the screen.
;
        mov    [SplitScreenLine],SCREEN_HEIGHT-1
                                          ;set the initial line just off
                                          ; the bottom of the screen
        mov    cx,SCREEN_HEIGHT/2
        call   SplitScreenUp
        mov    cx,SCREEN_HEIGHT/4
        call   SplitScreenDown
;
; Now move up another half a screen and then back down a quarter.
;
        mov    cx,SCREEN_HEIGHT/2
        call   SplitScreenUp
        mov    cx,SCREEN_HEIGHT/4
        call   SplitScreenDown
;
; Finally move up to the top of the screen.
;
        mov    cx,SCREEN_HEIGHT/2-2
        call   SplitScreenUp
;
; Wait for a key press (don't echo character).
;
        mov    ah,8                 ;DOS console input without echo function
        int    21h
;
; Turn the split screen off.
;
        mov    [SplitScreenLine],0ffffh
        call   SetSplitScreenScanLine
;
; Wait for a key press (don't echo character).
;
        mov    ah,8                 ;DOS console input without echo function
        int    21h
; Display the memory at 0 (the same memory the split screen displays).
;
        mov    [StartAddress],0
        call   SetStartAddress
;
; Flip between the split screen and the normal screen every 10th
; frame until a key is pressed.
;
FlipLoop:
        xor    [SplitScreenLine],0ffffh
        call   SetSplitScreenScanLine
        mov    cx,10
CountVerticalSyncsLoop:
        call   WaitForVerticalSyncEnd
        loop   CountVerticalSyncsLoop
        mov    ah,0bh                     ;DOS character available status
        int    21h
        and    al,al ;character available?
        jz     FlipLoop              ;no, toggle split screen on/off status
        mov    ah,1
        int    21h                        ;clear the character
;
; Return to text mode and DOS.
;
       mov    ax,0003h                    ;AH=0 is select mode function
                                          ;AL=3 is mode to select, text mode
       int    10h                         ;return to text mode
       mov     ah,4ch
       int     21h                        ;return to DOS
Start  endp
;*********************************************************************
; Waits for the leading edge of the vertical sync pulse.
;
; Input: none
;
; Output: none
;
; Registers altered: AL, DX
;
WaitForVerticalSyncStart proc near
        mov    dx,INPUT_STATUS_0
WaitNotVerticalSync:
        in     al,dx
        test   al,08h
        jnz    WaitNotVerticalSync
WaitVerticalSync:
        in     al,dx
        test   al,08h
        jz     WaitVerticalSync
        ret
WaitForVerticalSyncStart  endp
;*********************************************************************
; Waits for the trailing edge of the vertical sync pulse.
;
; Input: none
;
; Output: none
;
; Registers altered: AL, DX
;
WaitForVerticalSyncEnd    proc near
        mov    dx,INPUT_STATUS_0
WaitVerticalSync2:
        in     al,dx
        test   al,08h
        jz     WaitVerticalSync2
WaitNotVerticalSync2:
        in     al,dx
        test   al,08h
        jnz    WaitNotVerticalSync2
        ret
WaitForVerticalSyncEnd endp
;*********************************************************************
; Sets the start address to the value specifed by StartAddress.
; Wait for the trailing edge of vertical sync before setting so that
; one half of the address isn't loaded before the start of the frame
; and the other half after, resulting in flicker as one frame is
; displayed with mismatched halves. The new start address won't be
; loaded until the start of the next frame; that is, one full frame
; will be displayed before the new start address takes effect.
;
; Input: none
;
; Output: none
;
; Registers altered: AX, DX
;
SetStartAddress proc near
        call    WaitForVerticalSyncEnd
        mov     dx,CRTC_INDEX
        mov     al,START_ADDRESS_HIGH
        mov     ah,byte ptr [StartAddress+1]
        cli                    ;make sure both registers get set at once
        OUT_WORD
        mov     al,START_ADDRESS_LOW
        mov     ah,byte ptr [StartAddress]
        OUT_WORD
        sti
        ret
SetStartAddress endp
;*********************************************************************
; Sets the scan line the split screen starts after to the scan line
; specified by SplitScreenLine.
;
; Input: none
;
; Output: none
;
; All registers preserved
;
SetSplitScreenScanLine    proc near
        push   ax
        push   cx
        push   dx
;
; Wait for the leading edge of the vertical sync pulse. This ensures
; that we don't get mismatched portions of the split screen setting
; while setting the two or three split screen registers (register 18h
; set but register 7 not yet set when a match occurs, for example),
; which could produce brief flickering.
;
        call   WaitForVerticalSyncStart
;
; Set the split screen scan line.
;
        mov    dx,CRTC_INDEX
        mov    ah,byte ptr [SplitScreenLine]
        mov    al,LINE_COMPARE
        cli                    ;make sure all the registers get set at once
        OUT_WORD               ;set bits 7-0 of the split screen scan line
        mov ah,byte ptr [SplitScreenLine+1]
        and    ah,1
        mov    cl,4
        shl    ah,cl           ;move bit 8 of the split split screen scan
                               ; line into position for the Overflow reg
       mov    al,OVERFLOW
if IS_VGA
;
; The Split Screen, Overflow, and Line Compare registers all contain
; part of the split screen start scan line on the VGA. We'll take
; advantage of the readable registers of the VGA to leave other bits
; in the registers we access undisturbed.
;
        out    dx,al           ;set CRTC Index reg to point to Overflow
        inc    dx              ;point to CRTC Data reg
        in     al,dx           ;get the current Overflow reg setting
        and    al,not 10h      ;turn off split screen bit 8
        or     al,ah           ;insert the new split screen bit 8
                               ; (works in any mode)
        out    dx,al           ;set the new split screen bit 8
        dec    dx              ;point to CRTC Index reg
        mov    ah,byte ptr [SplitScreenLine+1]
        and    ah,2
        mov    cl,3
        ror    ah,cl           ;move bit 9 of the split split screen scan
                               ; line into position for the Maximum Scan
                               ; Line register
        mov    al,MAXIMUM_SCAN_LINE
        out    dx,al           ;set CRTC Index reg to point to Maximum
                               ; Scan Line
        inc    dx              ;point to CRTC Data reg
        in     al,dx           ;get the current Maximum Scan Line setting
        and    al,not 40h      ;turn off split screen bit 9
        or     al,ah           ;insert the new split screen bit 9
                               ; (works in any mode)
        out    dx,al           ;set the new split screen bit 9
else
;
; Only the Split Screen and Overflow registers contain part of the
; Split Screen start scan line and need to be set on the EGA.
; EGA registers are not readable, so we have to set the non-split
; screen bits of the Overflow register to a preset value, in this
; case the value for 350-scan-line modes.
;
        or     ah,0fh          ;insert the new split screen bit 8
                               ; (only works in 350-scan-line EGA modes)
        OUT_WORD               ;set the new split screen bit 8
endif
        sti
        pop    dx
        pop    cx
        pop    ax
        ret
SetSplitScreenScanLine  endp
;*********************************************************************
; Moves the split screen up the specified number of scan lines.
;
; Input: CX = # of scan lines to move the split screen up by
;
; Output: none
;
; Registers altered: CX
;
SplitScreenUp proc near
SplitScreenUpLoop:
        dec    [SplitScreenLine]
        call   SetSplitScreenScanLine
        loop   SplitScreenUpLoop
        ret
SplitScreenUp  endp
;*********************************************************************
; Moves the split screen down the specified number of scan lines.
;
; Input: CX = # of scan lines to move the split screen down by
;
; Output: none
;
; Registers altered: CX
;
SplitScreenDown proc near
SplitScreenDownLoop:
        inc    [SplitScreenLine]
        call   SetSplitScreenScanLine
        loop   SplitScreenDownLoop
        ret
SplitScreenDown endp
;*********************************************************************
Code    ends
        end    Start


Previous Table of Contents Next

homesubscribesearchfaqsitemapcontactus
Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.