home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapter30 / l30-2.asm < prev    next >
Encoding:
Assembly Source File  |  1997-06-18  |  12.7 KB  |  426 lines

  1. ;
  2. ; *** Listing 8.2 ***
  3. ;
  4. ; Demonstrates the interaction of the split screen and
  5. ; horizontal pel panning. On a VGA, first pans right in the top
  6. ; half while the split screen jerks around, because split screen
  7. ; pel panning suppression is disabled, then enables split screen
  8. ; pel panning suppression and pans right in the top half while the
  9. ; split screen remains stable. On an EGA, the split screen jerks
  10. ; around in both cases, because the EGA doesn't support split
  11. ; screen pel panning suppression.
  12. ;
  13. ; The jerking in the split screen occurs because the split screen
  14. ; is being pel panned (panned by single pixels--intrabyte panning),
  15. ; but is not and cannot be byte panned (panned by single bytes--
  16. ; "extrabyte" panning) because the start address of the split screen
  17. ; is forever fixed at 0.
  18. ;
  19. ; Assembled with TASM 4.0, linked with TLINK 6.10
  20. ; Checked by Jim Mischel 11/21/94
  21. ;*********************************************************************
  22. IS_VGA    equ    1        ;set to 0 to assemble for EGA
  23. ;
  24. VGA_SEGMENT    equ    0a000h
  25. LOGICAL_SCREEN_WIDTH equ 1024    ;# of pixels across virtual
  26.                 ; screen that we'll pan across
  27. SCREEN_HEIGHT    equ    350
  28. SPLIT_SCREEN_START equ    200    ;start scan line for split screen
  29. SPLIT_SCREEN_HEIGHT equ    SCREEN_HEIGHT-SPLIT_SCREEN_START-1
  30. CRTC_INDEX    equ    3d4h    ;CRT Controller Index register
  31. AC_INDEX        equ    3c0h    ;Attribute Controller Index reg
  32. OVERFLOW        equ    7    ;index of Overflow reg in CRTC
  33. MAXIMUM_SCAN_LINE equ    9    ;index of Maximum Scan Line register
  34.                 ; in CRTC
  35. START_ADDRESS_HIGH equ    0ch    ;index of Start Address High register
  36.                 ; in CRTC
  37. START_ADDRESS_LOW equ    0dh    ;index of Start Address Low register
  38.                 ; in CRTC
  39. HOFFSET        equ    13h    ;index of Horizontal Offset register
  40.                 ; in CRTC
  41. LINE_COMPARE    equ    18h    ;index of Line Compare reg (bits 7-0
  42.                 ; of split screen start scan line)
  43.                 ; in CRTC
  44. AC_MODE_CONTROL    equ    10h    ;index of Mode Control reg in AC
  45. PEL_PANNING    equ    13h    ;index of Pel Panning reg in AC
  46. INPUT_STATUS_0    equ    3dah    ;Input Status 0 register
  47. WORD_OUTS_OK    equ    1    ;set to 0 to assemble for
  48.                 ; computers that can't handle
  49.                 ; word outs to indexed VGA registers
  50. ;*********************************************************************
  51. ; Macro to output a word value to a port.
  52. ;
  53. OUT_WORD    macro
  54. if WORD_OUTS_OK
  55.     out    dx,ax
  56. else
  57.     out    dx,al
  58.     inc    dx
  59.     xchg    ah,al
  60.     out    dx,al
  61.     dec    dx
  62.     xchg    ah,al
  63. endif
  64.     endm
  65. ;*********************************************************************
  66. MyStack    segment para stack 'STACK'
  67.     db    512 dup (0)
  68. MyStack    ends
  69. ;*********************************************************************
  70. Data    segment
  71. SplitScreenLine    dw    ?    ;line the split screen currently
  72.                 ; starts after
  73. StartAddress    dw    ?    ;display memory offset at which
  74.                 ; scanning for video data starts
  75. PelPan        db    ?    ;current intrabyte horizontal pel
  76.                 ; panning setting
  77. Data    ends
  78. ;*********************************************************************
  79. Code    segment
  80.     assume    cs:Code, ds:Data
  81. ;*********************************************************************
  82. Start    proc    near
  83.     mov    ax,Data
  84.     mov    ds,ax
  85. ;
  86. ; Select mode 10h, 640x350 16-color graphics mode.
  87. ;
  88.     mov    ax,0010h    ;AH=0 is select mode function
  89.                 ;AL=10h is mode to select,
  90.                 ; 640x350 16-color graphics mode
  91.     int    10h
  92. ;
  93. ; Set the Offset register to make the offset from the start of one
  94. ; scan line to the start of the next the desired number of pixels.
  95. ; This gives us a virtual screen wider than the actual screen to
  96. ; pan across.
  97. ; Note that the Offset register is programmed with the logical
  98. ; screen width in words, not bytes, hence the final division by 2.
  99. ;
  100.     mov    dx,CRTC_INDEX
  101.     mov    ax,(LOGICAL_SCREEN_WIDTH/8/2 shl 8) or HOFFSET
  102.     OUT_WORD
  103. ;
  104. ; Set the start address to display the memory just past the split
  105. ; screen memory.
  106. ;
  107.     mov    [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
  108.     call    SetStartAddress
  109. ;
  110. ; Set the split screen start scan line.
  111. ;
  112.     mov    [SplitScreenLine],SPLIT_SCREEN_START
  113.     call    SetSplitScreenScanLine
  114. ;
  115. ; Fill the split screen portion of display memory (starting at
  116. ; offset 0) with a choppy diagonal pattern sloping left.
  117. ;
  118.     mov    ax,VGA_SEGMENT
  119.     mov    es,ax
  120.     sub    di,di
  121.     mov    dx,SPLIT_SCREEN_HEIGHT
  122.                 ;fill all lines in the split screen
  123.     mov    ax,0FF0h    ;starting fill pattern
  124.     cld
  125. RowLoop:
  126.     mov    cx,LOGICAL_SCREEN_WIDTH/8/4
  127.                 ;fill 1 scan line
  128. ColumnLoop:
  129.     stosw            ;draw part of a diagonal line
  130.     mov    word ptr es:[di],0 ;make vertical blank spaces so
  131.                 ; panning effects can be seen easily
  132.     inc    di
  133.     inc    di
  134.     loop    ColumnLoop
  135.     rol    ax,1        ;shift pattern word
  136.     dec    dx
  137.     jnz    RowLoop
  138. ;
  139. ; Fill the portion of display memory that will be displayed in the
  140. ; normal screen (the non-split screen part of the display) with a
  141. ; choppy diagonal pattern sloping right.
  142. ;
  143.     mov    di,SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
  144.     mov    dx,SCREEN_HEIGHT ;fill all lines
  145.     mov    ax,0c510h    ;starting fill pattern
  146.     cld
  147. RowLoop2:
  148.     mov    cx,LOGICAL_SCREEN_WIDTH/8/4
  149.                 ;fill 1 scan line
  150. ColumnLoop2:
  151.     stosw            ;draw part of a diagonal line
  152.     mov    word ptr es:[di],0 ;make vertical blank spaces so
  153.                 ; panning effects can be seen easily
  154.     inc    di
  155.     inc    di
  156.     loop    ColumnLoop2
  157.     ror    ax,1        ;shift pattern word
  158.     dec    dx
  159.     jnz    RowLoop2
  160. ;
  161. ; Pel pan the non-split screen portion of the display; because
  162. ; split screen pel panning suppression is not turned on, the split
  163. ; screen jerks back and forth as the pel panning setting cycles.
  164. ;
  165.     mov    cx,200    ;pan 200 pixels to the left
  166.     call    PanRight
  167. ;
  168. ; Wait for a key press (don't echo character).
  169. ;
  170.     mov    ah,8    ;DOS console input without echo function
  171.     int    21h
  172. ;
  173. ; Return to the original screen location, with pel panning turned off.
  174. ;
  175.     mov    [StartAddress],SPLIT_SCREEN_HEIGHT*(LOGICAL_SCREEN_WIDTH/8)
  176.     call    SetStartAddress
  177.     mov    [PelPan],0
  178.     call    SetPelPan
  179. ;
  180. ; Turn on split screen pel panning suppression, so the split screen
  181. ; won't be affected by pel panning. Not done on EGA because both
  182. ; readable registers and the split screen pel panning suppression bit
  183. ; aren't supported by EGAs.
  184. ;
  185. if IS_VGA
  186.     mov    dx,INPUT_STATUS_0
  187.     in    al,dx        ;reset the AC Index/Data toggle to
  188.                 ; Index state
  189.     mov    al,20h+AC_MODE_CONTROL
  190.                 ;bit 5 set to 1 to keep video on
  191.     mov    dx,AC_INDEX    ;point to AC Index/Data register
  192.     out    dx,al
  193.     inc    dx        ;point to AC Data reg (for reads only)
  194.     in    al,dx        ;get the current AC Mode Control reg
  195.     or    al,20h        ;enable split screen pel panning
  196.                 ; suppression
  197.     dec    dx        ;point to AC Index/Data reg (Data for
  198.                 ; writes only)
  199.     out    dx,al        ;write the new AC Mode Control setting
  200.                 ; with split screen pel panning
  201.                 ; suppression turned on
  202. endif
  203. ;
  204. ; Pel pan the non-split screen portion of the display; because
  205. ; split screen pel panning suppression is turned on, the split
  206. ; screen will not move as the pel panning setting cycles.
  207. ;
  208.     mov    cx,200    ;pan 200 pixels to the left
  209.     call    PanRight
  210. ;
  211. ; Wait for a key press (don't echo character).
  212. ;
  213.     mov    ah,8    ;DOS console input without echo function
  214.     int    21h
  215. ;
  216. ; Return to text mode and DOS.
  217. ;
  218.     mov    ax,0003h    ;AH=0 is select mode function
  219.                 ;AL=3 is mode to select, text mode
  220.     int    10h        ;return to text mode
  221.     mov    ah,4ch
  222.     int    21h        ;return to DOS
  223. Start    endp
  224. ;*********************************************************************
  225. ; Waits for the leading edge of the vertical sync pulse.
  226. ;
  227. ; Input: none
  228. ;
  229. ; Output: none
  230. ;
  231. ; Registers altered: AL, DX
  232. ;
  233. WaitForVerticalSyncStart    proc    near
  234.     mov    dx,INPUT_STATUS_0
  235. WaitNotVerticalSync:
  236.     in    al,dx
  237.     test    al,08h
  238.     jnz    WaitNotVerticalSync
  239. WaitVerticalSync:
  240.     in    al,dx
  241.     test    al,08h
  242.     jz    WaitVerticalSync
  243.     ret
  244. WaitForVerticalSyncStart    endp
  245. ;*********************************************************************
  246. ; Waits for the trailing edge of the vertical sync pulse.
  247. ;
  248. ; Input: none
  249. ;
  250. ; Output: none
  251. ;
  252. ; Registers altered: AL, DX
  253. ;
  254. WaitForVerticalSyncEnd    proc    near
  255.     mov    dx,INPUT_STATUS_0
  256. WaitVerticalSync2:
  257.     in    al,dx
  258.     test    al,08h
  259.     jz    WaitVerticalSync2
  260. WaitNotVerticalSync2:
  261.     in    al,dx
  262.     test    al,08h
  263.     jnz    WaitNotVerticalSync2
  264.     ret
  265. WaitForVerticalSyncEnd    endp
  266. ;*********************************************************************
  267. ; Sets the start address to the value specifed by StartAddress.
  268. ; Wait for the trailing edge of vertical sync before setting so that
  269. ; one half of the address isn't loaded before the start of the frame
  270. ; and the other half after, resulting in flicker as one frame is
  271. ; displayed with mismatched halves. The new start address won't be
  272. ; loaded until the start of the next frame; that is, one full frame
  273. ; will be displayed before the new start address takes effect.
  274. ;
  275. ; Input: none
  276. ;
  277. ; Output: none
  278. ;
  279. ; Registers altered: AX, DX
  280. ;
  281. SetStartAddress    proc    near
  282.     call    WaitForVerticalSyncEnd
  283.     mov    dx,CRTC_INDEX
  284.     mov    al,START_ADDRESS_HIGH
  285.     mov    ah,byte ptr [StartAddress+1]
  286.     cli        ;make sure both registers get set at once
  287.     OUT_WORD
  288.     mov    al,START_ADDRESS_LOW
  289.     mov    ah,byte ptr [StartAddress]
  290.     OUT_WORD
  291.     sti
  292.     ret
  293. SetStartAddress    endp
  294. ;*********************************************************************
  295. ; Sets the horizontal pel panning setting to the value specified
  296. ; by PelPan. Waits until the start of vertical sync to do so, so
  297. ; the new pel pan setting can be loaded during non-display time
  298. ; and can be ready by the start of the next frame.
  299. ;
  300. ; Input: none
  301. ;
  302. ; Output: none
  303. ;
  304. ; Registers altered: AL, DX
  305. ;
  306. SetPelPan    proc    near
  307.     call    WaitForVerticalSyncStart ;also resets the AC
  308.                     ; Index/Data toggle
  309.                     ; to Index state
  310.     mov    dx,AC_INDEX
  311.     mov    al,PEL_PANNING+20h
  312.                 ;bit 5 set to 1 to keep video on
  313.     out    dx,al        ;point the AC Index to Pel Pan reg
  314.     mov    al,[PelPan]
  315.     out    dx,al        ;load the new Pel Pan setting
  316.     ret
  317. SetPelPan    endp
  318. ;*********************************************************************
  319. ; Sets the scan line the split screen starts after to the scan line
  320. ; specified by SplitScreenLine.
  321. ;
  322. ; Input: none
  323. ;
  324. ; Output: none
  325. ;
  326. ; All registers preserved
  327. ;
  328. SetSplitScreenScanLine    proc    near
  329.     push    ax
  330.     push    cx
  331.     push    dx
  332. ;
  333. ; Wait for the leading edge of the vertical sync pulse. This ensures
  334. ; that we don't get mismatched portions of the split screen setting
  335. ; while setting the two or three split screen registers (register 18h
  336. ; set but register 7 not yet set when a match occurs, for example),
  337. ; which could produce brief flickering.
  338. ;
  339.     call    WaitForVerticalSyncStart
  340. ;
  341. ; Set the split screen scan line.
  342. ;
  343.     mov    dx,CRTC_INDEX
  344.     mov    ah,byte ptr [SplitScreenLine]
  345.     mov    al,LINE_COMPARE
  346.     cli        ;make sure all the registers get set at once
  347.     OUT_WORD        ;set bits 7-0 of the split screen scan line
  348.     mov        ah,byte ptr [SplitScreenLine+1]
  349.     and    ah,1
  350.     mov    cl,4
  351.     shl    ah,cl    ;move bit 8 of the split split screen scan
  352.             ; line into position for the Overflow reg
  353.     mov    al,OVERFLOW
  354. if IS_VGA
  355. ;
  356. ; The Split Screen, Overflow, and Line Compare registers all contain
  357. ; part of the split screen start scan line on the VGA. We'll take
  358. ; advantage of the readable registers of the VGA to leave other bits
  359. ; in the registers we access undisturbed.
  360. ;
  361.     out    dx,al    ;set CRTC Index reg to point to Overflow
  362.     inc    dx    ;point to CRTC Data reg
  363.     in    al,dx    ;get the current Overflow reg setting
  364.     and    al,not 10h ;turn off split screen bit 8
  365.     or    al,ah    ;insert the new split screen bit 8
  366.             ; (works in any mode)
  367.     out    dx,al    ;set the new split screen bit 8
  368.     dec    dx    ;point to CRTC Index reg
  369.     mov    ah,byte ptr [SplitScreenLine+1]
  370.     and    ah,2
  371.     mov    cl,3
  372.     ror    ah,cl    ;move bit 9 of the split split screen scan
  373.             ; line into position for the Maximum Scan
  374.             ; Line register
  375.     mov    al,MAXIMUM_SCAN_LINE
  376.     out    dx,al    ;set CRTC Index reg to point to Maximum
  377.             ; Scan Line
  378.     inc    dx    ;point to CRTC Data reg
  379.     in    al,dx    ;get the current Maximum Scan Line setting
  380.     and    al,not 40h ;turn off split screen bit 9
  381.     or    al,ah    ;insert the new split screen bit 9
  382.             ; (works in any mode)
  383.     out    dx,al    ;set the new split screen bit 9
  384. else
  385. ;
  386. ; Only the Split Screen and Overflow registers contain part of the
  387. ; Split Screen start scan line and need to be set on the EGA.
  388. ; EGA registers are not readable, so we have to set the non-split
  389. ; screen bits of the Overflow register to a preset value, in this
  390. ; case the value for 350-scan-line modes.
  391. ;
  392.     or    ah,0fh    ;insert the new split screen bit 8
  393.             ; (only works in 350-scan-line EGA modes)
  394.     OUT_WORD    ;set the new split screen bit 8
  395. endif
  396.     sti
  397.     pop    dx
  398.     pop    cx
  399.     pop    ax
  400.     ret
  401. SetSplitScreenScanLine    endp
  402. ;*********************************************************************
  403. ; Pan horizontally to the right the number of pixels specified by CX.
  404. ;
  405. ; Input: CX = # of pixels by which to pan horizontally
  406. ;
  407. ; Output: none
  408. ;
  409. ; Registers altered: AX, CX, DX
  410. ;
  411. PanRight    proc    near
  412. PanLoop:
  413.     inc    [PelPan]
  414.     and    [PelPan],07h
  415.     jnz    DoSetStartAddress
  416.     inc    [StartAddress]
  417. DoSetStartAddress:
  418.     call    SetStartAddress
  419.     call    SetPelPan
  420.     loop    PanLoop
  421.     ret
  422. PanRight    endp
  423. ;*********************************************************************
  424. Code    ends
  425.     end    Start
  426.