home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / progjorn / pj_7_6.arc / PANNING.ASM < prev    next >
Assembly Source File  |  1989-08-13  |  13KB  |  423 lines

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