home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / PXDTUT5.ZIP / PXDTUT5.TXT < prev   
Text File  |  1997-08-14  |  30KB  |  808 lines

  1.  
  2.  
  3.  
  4.                   |====================================|
  5.                   |                                    |
  6.                   |   TELEMACHOS proudly presents :    |
  7.                   |                                    |
  8.                   |    Part 5 of the PXD trainers  -   |
  9.                   |                                    |
  10.                   |        SVGA using VESA 1.2         |
  11.                   |                                    |
  12.                   |                                    |
  13.                   |====================================|
  14.  
  15.          ___---__-->   The Peroxide Programming Tips   <--__---___
  16.  
  17. <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
  18.  
  19.  
  20. Intoduction
  21. -----------
  22.  
  23. Hi folks... It's been a while, I know, but I have been busy living my REAL
  24. life :)  (YEAH, I know : REAL LIFE SUXX!)
  25.  
  26. There have been quite a few people mailing me about my last two tutorials and
  27. one of them made me discover a little error in my gouraud routines.
  28. Actually it's not an error - I just presume that there is a maximum of 64
  29. colors in the shading table. If using more a few variables / regs will overflow
  30. resulting in graphical errors. The problems can be fixed by reducing the
  31. shl 8 statement to shl 7 when calculating the fixed point step values.
  32. Then later on when the vars has been calculated as 9.7 fixed point values you
  33. just have to multiply them by two to get them back to 8.8 fixed point.
  34. Now things should work correct.
  35. Also, in the gouraud polygonside scanner change the type of the variable
  36. "color" from integer to word.
  37.  
  38. This tutorial will be on SVGA graphic using the VESA 1.2 BIOS implemention.
  39. In the past I have seen quite a few shareware SVGA programming libs - but so
  40. far all of them has sucked pretty much. Either they presume a granularity of
  41. 64K - or they are written in pure asm without any decent comments - making
  42. them virtually impossible to learn from.
  43. Or they use BIOS calls to switch banks which suck just as much as code without
  44. comments.
  45. So what we'll do is to build a small pascal/asm SVGA lib that supports *ALL*
  46. SVGA cards on the market (at least we can try :) ).
  47. Also I'll try to explain everything about SVGA in a way so that the reader
  48. actually understands VESA-coding after reading this text.
  49. If you are bored with theory stop reading right now and skip to the headline
  50. called "THE CODE". But I strongly recommend you to read the entire text -
  51. otherwise you'll be coding VESA graphics in half an hour but not understand
  52. what you're doing :)
  53.  
  54. BTW. Some lamer seems to find it extremely funny to reset the hit-counter on
  55. my homepage. If you're reading this : Please don't do it again - it makes me
  56. very unhappy and I lie fever-striken on my bed for several days each time
  57. it happen.
  58. If you really enjoy resetting counters THAT much drop me a mail and I'll code
  59. you an internet-hit-counter-resetter-simulater FOR FREE!!!!!!!
  60. If any of you NON-lamers who reads this - you know, the kind of people who
  61. spend their time actually CODING instead of resetting counters, spreading
  62. virusses and beating their little brothers - I would like to know if any of
  63. you know how to make a hit-counter that cannot be reset by the weak-minded
  64. people of the net.
  65.  
  66.  
  67. If you want to get in contact with me, there are several ways of doing it :
  68.  
  69. 1) E-mail me               :      tm@image.dk
  70.  
  71. 2) Snail mail me           :      Kasper Fauerby
  72.                                   Saloparken 226
  73.                                   8300 Odder
  74.                                   Denmark
  75.  
  76. 3) Call me  (Voice ! )     :    +45 86 54 07 60
  77.  
  78.  
  79. Get this serie from the major demo-related FTP-sites - currently :
  80.  
  81.   GARBO ARCHIVES  (forgot the address)  :  /pc/programming/
  82.  
  83.   ftp.teeri.oulu.fi  :   /msdos/programming/docs/
  84.  
  85.   ftp.cdrom.com      :  something with demos/incomming/code.....
  86.  
  87. Or grap it from my homepage :
  88.  
  89.    Telemachos' Codin' Corner   http://www.image.dk/~tm
  90.  
  91.  
  92.  
  93. WHAT IS VESA AND WHY DO WE NEED IT ?
  94. ------------------------------------
  95.  
  96. Well... as you all know the standard mode $13 is a linear mode taking up
  97. 64000 bytes of memory. This fits into a single segment and therefore it is
  98. extremely easy to code. When mode $13 was introduced all agreed on using
  99. segment $a000 as base for the mode. Therefore our mode $13 code will work on
  100. EVERY SINGLE VGA-card available.
  101. When SVGA was introduced for the first time it was IBM who developed a very
  102. expensive GFX-card capable of doing extremely high resolutions - for that time,
  103. that is.
  104. But IBM never released the register information for programming the card.
  105. In time other companies developed SVGA cards - each with their own way of
  106. laying out the gfx-cards registers. The result was that it became almost
  107. impossible to code applications for SVGA - if the application was to support
  108. the different gfx cards the programmers had to do routines for EVERY SINGLE
  109. gfx card on the market. The result was that most programmers chosed not to
  110. support SVGA at all. The high resolution was'nt worth the time spend on doing
  111. the code.
  112. VESA saw the problem and came up with a BIOS extension that supplied some
  113. standard routines for coding the different SVGA cards available at the time
  114. being.
  115. For a long time it has been VESA 1.2 that has been the standard in SVGA coding.
  116. But now UniVBE 5.3 has been released making VESA 2.0 available on almost every
  117. graphic card out there.
  118. But for us pascal coders VESA 2.0 is pretty uninterresting. First of all :
  119. The main improvement in VESA 2.0 if something called Linear Frame Buffer (LFB)
  120. This means that you map your entire VGA-memory into one single linear buffer.
  121. Then you can adress each pixel on the SVGA screen lineary - just as in good
  122. old mode $13. But this is obviously only available to those coding in protected
  123. mode - and I take it that most of my readers are'nt.
  124. Another thing is that most gfx cards out there only has VESA 1.2 installed -
  125. so in order to use VESA 2.0 you'll have to assume that the user owns UniVBE 5.3
  126. So for now we'll stick to good old VESA 1.2
  127.  
  128.  
  129. THE WORKING OF A SVGA CARD - THE THEORY FOR OUR CODE
  130. -----------------------------------------------------
  131.  
  132. As mentioned before each pixel takes up 1 byte of memory. In mode $13 this is
  133. OK as the screen is only 320 X 200 = 64000 bytes. This way the video memory
  134. needed for a single screen of graphic fits into one single segment.
  135. But a SVGA mode takes up much more space. Lets take the standard 640X480 SVGA
  136. mode. This mode takes up 640 X 480 = 307200 bytes = 4,6875 segments of RAM.
  137. Hmm... how do we adress all this memory. The modenr for this mode is $101
  138. Try and set this mode using the following VESA code : (I'll explain the code
  139. later on)
  140.  
  141. asm
  142.  mov ah,4Fh
  143.  mov al,02h
  144.  mov bx,$101
  145.  int 10h
  146. end;
  147.  
  148. Now try and address the video mem via the good old $a000 segment.... Yes, just
  149. fill the entire segent with some color. Woila! You have just plotted your first
  150. pixels in 640 X 480 X 256. But as you might have discovered you are limited to
  151. accessing only the uppermost part of the screen. The narrow band of graphic you
  152. see takes up exactly 1 segment of memory.
  153. What you have just discovered is the greatest pain in SVGA programming :
  154. the need of windowing. Imagine the entire SVGA-memory laid out lineary. You can
  155. form it to many different sizes. One size is 640 pixels wide, another 800 and
  156. yet another 1024. But all the time you only have access to 1 segment of the
  157. memory. Think of this segment as a window you can look through into the entire
  158. video memory. Fortunately you can move this window to many different positions
  159. in the video memory. If you move it around enough you'll discover that you can
  160. see every byte in video memory through it - just only one segment at a time.
  161.  
  162. We call all those different window positions for banks. Well, VESA does provide
  163. us with standard procedures to set the graphic modes, test them and move the
  164. bank window but still SVGA is a little complicated. First of all there is
  165. the GRANULARITY of the video card. The granularity decides how the window can
  166. be moved around in the video memory. A granularity of 64K means that the window
  167. can be moved only in 64K chunks - ie. an entire window at a time. Some cards
  168. have finer granularity - Cirrus Logic fx. has a granularity of 4K which allows
  169. the windows to overlap. Each window position is called a bank even though some
  170. of the memory can be accesed through multiple window positions.
  171. The window size is an entirely different matter from the granularity. On most
  172. cards the window size is 64K (actually on every card I have seen so far) but
  173. some cards implement 128K. This is however not important to us as the greatest
  174. granularity is 64K - so as long the window is not below 64K in size we can
  175. acces all memory by moving the window.
  176.  
  177. It is pretty safe to assume that the video memory is accesed from the $a000
  178. segment but to be sure one should always test this by making a BIOS call before
  179. trying to write to memory. Some cards have multiple windows - We call them
  180. window A and Window B. This is because some cards have ReadOnly access in one
  181. window and WriteOnly in another. So this is another thing to check : Can we
  182. do both our reads and writes in the same window ?
  183.  
  184.  
  185.  
  186. THE VESA FUNCTIONS EXPLAINED
  187. -----------------------------
  188.  
  189. All VESA functions is reached from a sub-function of the BIOS interrupt $10.
  190. This subfunction is 4Fh so in all interrupt calls we must load the ah register
  191. with 4Fh and the al register with the VESA function number we want.
  192.  
  193. I'll just run over the different VESA BIOS functions and then do the code in
  194. the CODE section.
  195.  
  196. Function 00h -  Return SVGA info
  197. ---------------------------------
  198.  
  199. Input :      AH  : 4Fh
  200.              AL  : 00h
  201.           ES:DI  : Pointer to 256bytes buffer.
  202.  
  203. Returns :    AX  : Status
  204.  
  205.  
  206. The status register is set up as follows :
  207.  
  208.         AL == 4Fh:      Function is supported
  209.         Al != 4Fh:      Function is not supported
  210.         AH == 00h:      Function call successful
  211.         AH == 01h:      Function call failed
  212.  
  213. Now, as we see we load ah with our VESA subfunction number and AL with the
  214. VESA function number. ES:DI must point to a 256bytes buffer. This can be any
  215. buffer of this size. Fx. buffer : Array[0..255] of byte;
  216. But using a buffer like this leaves us with an enormous amount of converting
  217. from byte to word and so on... So I'll give you a structure to use instead :
  218.  
  219.  
  220. TYPE
  221.  
  222.  ListOfAvailModesT = Array[0..255] of word; {terminated by -1 ($FFFF) }
  223.  ListOfAvailModesP = ^ListOfAvailModesT;
  224.  
  225.  VESAInfoT = record
  226.               VESASignature : array[0..3] of byte;
  227.               VESAVersion   : word;
  228.               OEMStringPtr  : Pchar;
  229.               Capabilities  : array[0..3] of byte;
  230.               VideoModePtr  : ListOfAvailModesP;
  231.               TotalMemory   : word;
  232.               Reserved      : Array[0..235] of byte;
  233.              end;
  234.  
  235. The VESASignature is 4 bytes and when converted to a string they must form the
  236. word 'VESA'. Otherwise it is not a valid VESA-structure.
  237.  
  238. The VESAVersion is a word with the high-byte being the major version number and
  239. the low byte being the minor version number.
  240.  
  241. OEMStringPtr is a pointer to a 0-terminated String which contains the ident
  242. string of the SVGA card. But we are in luck - in pascal the type Pchar means
  243. a pointer to such a string, so we don't have to think any more about this one.
  244.  
  245. Capabilities is mostly unused. If bit 0 in the first byte is set it means that
  246. the DAC can be reprogrammed to another DAC width (standard is 6-bit)
  247.  
  248. VideoModePtr : Now this is a little tricky. This is a pointer to a list of
  249. words - each word containing a valid graphic mode on the card. The list is
  250. terminated by -1 ($FFFF).
  251.  
  252. TotalMemory contains the number of 64K blocks of RAM installed on the card.
  253.  
  254. The reserved field is reserved for future VESA expansions.
  255.  
  256.  
  257. This function is the first function your application should run for checking
  258. if VESA is available at all.
  259.  
  260.  
  261.  
  262. Function 01h - Return VESA MODE information
  263. -------------------------------------------
  264.  
  265. Input :        AH = 4Fh
  266.                AL = 01h
  267.                CX = Mode number (must be from the mode list from func 00h)
  268.             ES:DI = pointer to 256 bytes buffer
  269.  
  270. Returm         AX = Status
  271.  
  272.  
  273. Again I'll give you a structure to use for the 256 bytes buffer. I'll leave out
  274. some fields for true-color stuff that we will not discuss in this text.
  275.  
  276. TYPE
  277.  
  278.  ModeAttributesT = (Available,
  279.                    Reserved,
  280.                    BIOSFunctionsSupport,
  281.                    color,
  282.                    graphic,
  283.                    bit5,
  284.                    bit6,
  285.                    bit7,
  286.                    bit8);
  287.  
  288.  
  289.  WindowAttributesT  = (Supported,R,W);   {rest of the bits are unused...}
  290.  
  291.  
  292.  VESAModeInfoT = record
  293.                    ModeAttributes     : set of ModeAttributesT;
  294.                    WinAAttributes     : set of WindowAttributesT;
  295.                    WinBAttributes     : set of WindowAttributesT;
  296.                    WinGranularity     : word;
  297.                    WinSize            : word;
  298.                    WinASegment        : word;
  299.                    WinBSegment        : word;
  300.                    BankSwitch         : procedure;
  301.                    BytesPerScanLine   : word;
  302.  
  303.                    {Xtended Information}
  304.                    XResolution        : word;
  305.                    YResolution        : word;
  306.                    XCharSize          : byte;
  307.                    YCharSize          : byte;
  308.                    NumberOfPlanes     : byte;
  309.                    BitsPerPixel       : byte;
  310.                    NumberOfBanks      : byte;
  311.                    MemoryModel        : byte;
  312.                    BankSize           : byte;
  313.                    NumberOfImagePages : byte;
  314.  
  315.                    Reserved           : Array[0..225] of byte;
  316.                    {reserved is for something we won't think about now...
  317.                     true color and stuff...                               }
  318.                  end;
  319.  
  320.  
  321. WOW.... This sure is a tough one to get through. Well.. to start from the top.
  322.  
  323. ModeAttributes : This is a word with every bit meaning something different.
  324. That's why I made the ModeAttributesT. It contains different information about
  325. the mode from CX. If bit 0 is set the mode is available - if not : Your guess.
  326. The rest of this field should be obvious from the names in ModeAttributes :
  327. is it a color mode ? Is it a graphic or text mode? The BIOSSupport field
  328. decided if you can use BIOS scroll, TTY output and BIOS pixel output in the
  329. selected mode.
  330.  
  331. WinAAttributes and WinBAttributes : These are pretty important as they tell you
  332. if you can read or write to the two windows (A and B). Some cards has only one
  333. window availble so a window CAN be Read AND Writeable.
  334.  
  335.  
  336. WinGranularity : This field contains the granularity in KB.
  337.  
  338. WinSize : The Size of the window in KB.
  339.  
  340. WinASegent and WinBSegment : This decides where in memory the window base is
  341. placed. Usually WinASegment will be $A000 - but check it out to be sure.
  342. If a window reports $0000 as address DON'T use that address :)
  343.  
  344. BankSwitch : This is a pointer to the hardware bankswitch function. A far call
  345. can be made to this address for quick bankshifting. Lucky us - pascal allows us
  346. to use the type "procedure" here so we don't have to worry about the pointer
  347. stuff... just call this field from an assembler routine. More on this facility
  348. under function 05h later on.
  349.  
  350. BytesPerScanLine : The logical number of bytes pr y-line in memory. This is
  351. usually the same as the maximum x-value in the graphic mode.
  352.  
  353. The Xtended fields should be pretty self-explaining. One word of warning though.
  354. I have experienced some problems with the NumberOfBanks and BankSize fields on
  355. my Cirrus Logic card. Don't trust these fields blindly.
  356.  
  357.  
  358. function 02 - Set VESA mode
  359. ----------------------------
  360.  
  361. Input :       AH = 4Fh
  362.               AL = 02h
  363.               BX = Video Mode
  364.                    bit 15 : 1 = Don't clear video RAM
  365.                             0 = Clear video RAM
  366.  
  367.  
  368. Returns :     AX = Status
  369.  
  370.  
  371.  
  372. OK.. Use this one to set the VESA modes. The modes is as follows :
  373.  
  374.  
  375.                 GRAPHICS                                TEXT
  376.  
  377. 15-bit   7-bit    Resolution   Colors   15-bit   7-bit    Columns   Rows
  378. mode     mode                           mode     mode
  379. number   number                         number   number
  380. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  381. 100h     -        640x400      256      108h     -        80        60
  382. 101h     -        640x480      256
  383.                                         109h     -        132       25
  384. 102h     6Ah      800x600      16       10Ah     -        132       43
  385. 103h     -        800x600      256      10Bh     -        132       50
  386.                                         10Ch     -        132       60
  387. 104h     -        1024x768     16
  388. 105h     -        1024x768     256
  389.  
  390. 106h     -        1280x1024    16
  391. 107h     -        1280x1024    256
  392.  
  393. 10Dh     -        320x200      32K   (1:5:5:5)
  394. 10Eh     -        320x200      64K   (5:6:5)
  395. 10Fh     -        320x200      16.8M (8:8:8)
  396. 110h     -        640x480      32K   (1:5:5:5)
  397. 111h     -        640x480      64K   (5:6:5)
  398. 112h     -        640x480      16.8M (8:8:8)
  399. 113h     -        800x600      32K   (1:5:5:5)
  400. 114h     -        800x600      64K   (5:6:5)
  401. 115h     -        800x600      16.8M (8:8:8)
  402. 116h     -        1024x768     32K   (1:5:5:5)
  403. 117h     -        1024x768     64K   (5:6:5)
  404. 118h     -        1024x768     16.8M (8:8:8)
  405. 119h     -        1280x1024    32K   (1:5:5:5)
  406. 11Ah     -        1280x1024    64K   (5:6:5)
  407. 11Bh     -        1280x1024    16.8M (8:8:8)
  408.  
  409.  
  410.  
  411. Function 03h - Return current Video Mode
  412. -----------------------------------------
  413.  
  414. Input :          AH = 4Fh
  415.                  AL = 03h
  416.  
  417. Returns :        AX = Status
  418.                  BX = Current Video mode
  419.  
  420.  
  421. Not much to say about this one I guess...
  422.  
  423.  
  424.  
  425. Function 05h - Set Window position / Bank Switch
  426. -------------------------------------------------
  427.  
  428. Input :          AH = 4Fh
  429.                  AL = 05h
  430.                  BH = 00h
  431.                  BL = Window nr
  432.                        Window A = 0
  433.                        Window B = 1
  434.                  DX = Window position in granularity units.
  435.                       This means bank number.
  436.  
  437. Returns :        AX = Status
  438.  
  439.  
  440. Now, this routine sets the window position that we talked about earlier. The
  441. key to making a good VESA unit is to make certain that it is the correct
  442. bank numbers that is passed to this function. On a SVGA card with a granularity
  443. of 64K each bank matches one segment of memory and one potion of the screen.
  444. If we want to clear out Screen we usually selects bank nr 0 and then fill
  445. the $A000 segment with one color. Then we want to move on to the next section
  446. of the screen. So we increase our banknr by 1 and do the same trick. But WAIT
  447. A SECOND!! This will ONLY work with granunarities of 64K. 'Cause on cards with
  448. a granularity of fx. 4K we might have set the window to bank 0. And we might
  449. have filled the entire window - but by doing this we have filled SEVERAL banks!
  450. With a granularity of 4K we have filled 64K / 4K = 16 banks! So the next bank
  451. we should set should NOT be 1 but 16!
  452. This is where most errors I have seen in SVGA libs lies.
  453.  
  454. As we all know calling BIOS is pretty SLOW! And with small granularities we
  455. might have to do it MANY times during a screen-update so we're pretty lucky
  456. that we have the brain to use the far function address we got from function
  457. 01h.
  458. When using it we don't have to set the AX register before call. Just the BX
  459. and DX register. Beware though : Both AX and DX is destroyed in the call so
  460. be sure to save the information in them if you wanna reuse them.
  461.  
  462.  
  463. Function 06h - Set/Get logical Scanlenght
  464. ------------------------------------------
  465.  
  466. Input :        AH = 4Fh
  467.                AL = 06h
  468.                BL = 00h {Set scanlength}
  469.                CX = Desired width in pixels
  470.  
  471. Returns :      AX = Status
  472.                BX = Bytes per Scanline
  473.                CX = Actual pixels per Scanline
  474.                DX = Maximum number of scanlines based on mode and memory
  475.  
  476. Input :        AH = 4Fh
  477.                AL = 06h
  478.                BL = 01h {Get scanlength}
  479.  
  480. Returns :      AX = Status
  481.                BX = Bytes per Scanline
  482.                CX = Actual pixels per Scanline
  483.                DX = Maximum number of Scanlines.
  484.  
  485.  
  486. Now this function can be VERY useful. It allows you to set a logical width
  487. in video memory. It is based on this width that you calculate the offset for
  488. a pixel - just like in mode $13h.
  489. If you set this value to a power of 2 you can make sure that there will never
  490. be any bank-crossing along a horizontal scanline. This can speed up your code
  491. if you update the screen Scanline per Scanline 'cause you only have to do a
  492. bank check once per Scanline - and not once per pixel as you would in fx. mode
  493. 640 X 480!
  494. Also you can use function 07h to place the actual screen anywhere in this
  495. logical memory and this way do hardware scrolls!
  496. If you plan on using 640 X 480 and you know that your video card has 1MB of RAM
  497. installed you could set the logical scanlength to 1024 and thereby ease the
  498. offset calculation from :
  499.  
  500.    ofs := y shl 9 + y shl 7 + X
  501.  
  502. to
  503.  
  504.    ofs := y shl 10 + X;
  505.  
  506.  
  507. It's a waste of memory, but if you are smart you store something in the memory
  508. outside the screen.
  509.  
  510.  
  511. Function 07h -  Set / Get display start
  512. ----------------------------------------
  513.  
  514. Input :         AH = 4Fh
  515.                 AL = 07h
  516.                 BH = 00h
  517.                 BL = 00h   {set display start}
  518.                 CX = Xpos
  519.                 DX = Ypos
  520.  
  521. Returns :       AX = Status
  522.  
  523.  
  524. Input :         AH = 4Fh
  525.                 AL = 07h
  526.                 BL = 01h  {get display start}
  527.  
  528. Returns :       AX = Status
  529.                 BH = 00h
  530.                 CX = Xpos
  531.                 DX = Ypos
  532.  
  533.  
  534. This one sets the position of the screen in video memory.
  535.  
  536.  
  537. Function 08h - Set/Get DAC pallette control
  538. --------------------------------------------
  539.  
  540. Input :        AH = 4Fh
  541.                AL = 08h
  542.                BL = 00h  {Set DAC pallette width}
  543.                BH = desired number of bits per primary color
  544.  
  545. Returns :      AX = Status
  546.                BH = Current number of bits per primary color
  547.  
  548. Input :        AH = 4Fh
  549.                AL = 08h
  550.                BL = 01h   {get DAC pallette width}
  551.  
  552. Returns :      AX = Status
  553.                BH = Current number of bits per primary color
  554.  
  555.  
  556. This function sets the DAC pallette width - check if this function is
  557. available by checking bit 0 in the Capabilities field in VESAInfo.
  558.  
  559.  
  560. THE CODE :
  561. -----------
  562.  
  563. First lets get the VESA information and save it in a variable called
  564. VESAInfo :
  565.  
  566.  
  567. FUNCTION GetVESAInfo : boolean;
  568. Assembler;
  569. asm
  570.  mov ah,4Fh          {The usual VESA sub-function number}
  571.  mov al,00h          {This is VEAS function 00h         }
  572.  lea di,VESAInfo     {load the address of VESAInfo into es:di}
  573.  int 10h             {call the BIOS interrupt}
  574.  cmp ah,0            {ah returns 0 if succes}
  575.  jne @fail
  576.  mov ax,1
  577.  jmp @out
  578. @fail:
  579.  mov ax,0            {the ax register will be passed to the function}
  580. @out:
  581. end;
  582.  
  583.  
  584. The same way we get the Info for the mode we wanna set :
  585.  
  586.  
  587. FUNCTION GetVESAModeInfo(mode : word) : boolean;
  588. Assembler;
  589. asm
  590.  mov ah,4Fh
  591.  mov al,01h               {VESA function 01h}
  592.  xor cx,cx
  593.  mov cx,mode              {load the desired mode in cx}
  594.  lea di,VESAModeInfo      {load the address to VESAModeInfo into es:di}
  595.  int 10h                  {call BIOS video interrupt}
  596.  cmp ah,0
  597.  jne @fail
  598.  mov ax,1
  599.  jmp @out
  600. @fail:
  601.  mov ax,0                 {we put the result in ax }
  602. @out:
  603. end;
  604.  
  605.  
  606.  
  607. OK... Now we need to be able to switch the banks :
  608.  
  609.  
  610. Procedure SetBank(nr : word);
  611. Assembler;
  612. asm
  613.  xor bl,bl                         {Window A selected}
  614.  mov dx,nr
  615.  call [VESAModeInfo.BankSwitch]    {here we call the bankSwitch procedure}
  616.  mov dx,nr                         {dx is destroyed by far procedure call}
  617.  mov cur_page,dx                   {update global page variable}
  618. end;
  619.  
  620.  
  621. Now this routine assumes that Window A is Read/Writeable. BX desides which
  622. window is active bl = 0 means Window A and bl = 1 means Window B.
  623. It is a good idea to have a global variable that keeps track of which bank is
  624. active at the moment so you don't change to the bank that is allready active!
  625.  
  626.  
  627. This done I think we need to set the mode up :
  628.  
  629.  
  630. FUNCTION SetVESAMode(mode : word) : boolean;
  631. Assembler;
  632. asm
  633.  mov ax,03h
  634.  int 10h              {start from textmode}
  635.  
  636.  mov ah,4Fh
  637.  mov al,02h
  638.  mov bx,mode
  639.  int 10h
  640.  cmp ah,0
  641.  jne @fail           {set the VESA mode through VESA function 02h}
  642.  
  643.  mov ah,4Fh
  644.  mov al,05h
  645.  xor bx,bx
  646.  mov dx,0
  647.  int 10h             {set bank 0 from BIOS call this time - to be safe }
  648.  mov cur_page,0      {initialize global page variable to bank 0}
  649.  cmp ah,0
  650.  jne @fail
  651.  
  652.  mov ax,1
  653.  jmp @out
  654. @fail:
  655.  mov ax,0           {return fail or succes to function}
  656. @out:
  657. end;
  658.  
  659.  
  660. Now lets plot a pixel, shall we ??
  661.  
  662.  
  663. PROCEDURE   VESAputpixel(x, y : WORD; c : BYTE);
  664. VAR
  665.   bank   : WORD;
  666.   offs   : longint;
  667. BEGIN
  668.  
  669.   offs := LONGINT(y) * VESAModeInfo.Xresolution + x;
  670.   bank := offs SHR (16-BankShiftModifier);
  671.   offs := offs - (bank SHL (16-BankShiftModifier));
  672.  
  673.   IF bank <> Cur_page THEN {page = global var - active page}
  674.   BEGIN
  675.     cur_page := bank;
  676.     ASM
  677.       Xor bl,bl
  678.       mov dx,bank
  679.       call [VESAModeInfo.BankSwitch]
  680.     END;
  681.    END;
  682.  
  683.   ASM
  684.     MOV AX, $A000
  685.     MOV ES, ax
  686.     MOV DI, WORD(offs)
  687.     MOV AL, c
  688.     MOV ES:[DI], AL
  689.   END;
  690. END;
  691.  
  692.  
  693. Now in this routine I use a variable called BankShiftModifier. This is because
  694. the routine assumes a granularity of 64K when using the shr 16 and shl 16
  695. statements. With a granularity of fx. 4K it should be shr 12 and shl 12.
  696. So we'll have to calculate the modifier when we recieve the information about
  697. the granularity from function 01h.
  698.  
  699. Case VESAModeInfo.WinGranularity of
  700.  1  : BankShiftModifier := 6;
  701.  2  : BankShiftModifier := 5;
  702.  4  : BankShiftModifier := 4;
  703.  8  : BankShiftModifier := 3;
  704.  16 : BankShiftModifier := 2;
  705.  32 : BankShiftModifier := 1;
  706.  64 : BankShiftModifier := 0;
  707. end;    {With granularities smaller than 64 but with page-size 64K the
  708.          banknr for each full segment of SVGA graphic will not be 0,1,2,3
  709.          but multiplied with BankMult ( 2^BankShiftModifier for easy bit
  710.          shifting)                                                         }
  711. BankMult := 64 div VESAModeInfo.WinGranularity;
  712.  
  713. Now, I know of granularities of 64K, 32K and 4K... But it can't hurt to have
  714. the other posibilities as well... you never know with SVGA.
  715. The Variable BankMult is used for our next routine - The clear routine.
  716. As mentioned when discussing function 05h the banks won't be 0,1,2,3,4 and so
  717. on when dealing with granularities smaller than 64K. Each Segment filled is
  718. the same as 16 banks filled with a granularity of 4K
  719.  
  720. So here goes : The ClearScreen routine :
  721.  
  722.  
  723. PROCEDURE ClearScreen(color : byte);
  724. VAR
  725.  Xres, Yres : longint;
  726.  number_of_segments : longint;
  727.  i : integer;
  728. BEGIN
  729.  Xres := VESAModeInfo.Xresolution;
  730.  Yres := VESAModeInfo.Yresolution;
  731.  number_of_segments  := Round(((Xres *  Yres)/65536)+0.5)-1;
  732.  
  733.  for i := 0 to number_of_segments do
  734.   BEGIN
  735.    SetBank(i*BankMult);
  736.     ASM
  737.      mov     cx, 32768;
  738.      mov     ax,$A000
  739.      mov     es,ax
  740.      xor     di,di
  741.      mov     al,[color]
  742.      mov     ah,al
  743.      rep     stosw
  744.     END;
  745.   END;
  746. END;
  747.  
  748.  
  749. And now the final two small routines :
  750.  
  751. Procedure SetLogicalScanline(width : word);
  752. Assembler;
  753. asm
  754.  mov ah,4Fh
  755.  mov al,06h
  756.  mov bl,0
  757.  mov cx,width
  758.  int 10h
  759. end;
  760.  
  761.  
  762. Procedure SetScreenPosition(x,y : word);
  763. Assembler;
  764. asm
  765.  mov ah,4Fh
  766.  mov al,07h
  767.  xor bx,bx
  768.  mov cx,[x]
  769.  mov dx,[y]
  770.  int 10h
  771. end;
  772.  
  773.  
  774.  
  775.  
  776. LAST REMARKS
  777. -------------
  778.  
  779. Well, that's about all for now.
  780. Hope you found this doc useful - and BTW : If you DO make anything public using
  781. these techniques please mention me in your greets or where ever you se fit.
  782. I DO love to see my name in a greeting :=)
  783.  
  784. Now, this done you should all be able to code some pretty stunning SVGA games/
  785. demos. We can no longer say anything else : SVGA is the future of all graphic
  786. programming.
  787. A few things to take note of : All the routines presented here in this text are
  788. very general. The ClearScreen will do any resolution - same thing with the
  789. putpixel routine. But I have sacrificed speed to achieve this! If you use the
  790. routines in games/demos where you KNOW what resolution it will run at you
  791. should modify the routines and optimize them to meet those specific resolutions!
  792. Fx. I use a normal * to calculate the offset in the putpixel. This should off
  793. cause be changed to shl's when dealing with a predefined gfx-mode.
  794.  
  795.  
  796. But what now ??
  797. If you have any good ideas for a subject you wish to see a tutorial on please
  798. mail me. If I like the idea (and know anything about it :)  ) I'll write a
  799. tut on it.
  800. I have spoken of a tutorial on interrupts for quite a while now....
  801. maybe it'll come out soon - but I also plan on doing some graphical effects.
  802. MAIL ME!!
  803.  
  804.  
  805. Keep on coding...
  806.  
  807.   Telemachos - August '97.
  808.