'=========================================================================== ' Subject: 15-BIT & 16-BIT SVGA ROUTINES Date: 10-02-99 (21:10) ' Author: Aaron Severn Code: QB, PDS ' Origin: rlsevern@idirect.com Packet: GRAPHICS.ABC '=========================================================================== '**************************************************************************** ' SVGA.BAS ' Programmed by Aaron Severn (Laeden) ' rlsevern@idirect.com ' www.geocities.com/SiliconValley/Peaks/9572/ ' July 18-29, 1998 ' ' This is a bit of a revamp of my previous SVGA functions. A few bugs have ' been fixed, the 256 colour modes now have a much faster put pixel routine ' and a much faster put routine both done in assembly, also 15 and 16 bit ' colour modes have been added. ' ' The 15 and 16 bit stuff is still in the early stages, I might redo both ' routines in assembly some time, but I'm kinda sick of this stuff for now. ' I'll see if I can add support for 24 bit modes too. ' ' Since this is an early version of the routines I'd appreciate bug reports. ' If something doesn't work on your computer let me know either by e-mail or ' by leaving a message on the message board at my website. Try to give me ' as much info as you can about the problem and about your graphics card. ' ' As for the legal aspects. This code is public domain. If you use it, ' give me credit. If it does any damage I'm not liable. It shouldn't ' cause any damage, and as of writing this it hasn't, but if it does you ' can't sue me. Okay. ' ' A few IMPORTANT instructions. ' 1. This code requires QuickBasic with the qb.qlb library loaded, otherwise ' it won't run. ' 2. There are three put pixel routines, one for 256 colour modes (PutPixel), ' one for 15 bit colour modes (PutPixel15), and one for 16 bit colour ' modes (PutPixel16). DO NOT use them with the wrong modes (ie. don't ' use PutPixel in mode 111h, use PutPixel16). You could do some serious ' damage to your monitor if you do. The demo code is set up to avoid ' this little problem, read it, learn it, live it. ' 3. The put routine (Put256) was designed specifically for 256 colour modes, ' use with any other mode could cause some serious problems. Don't say ' I didn't warn you. ' 4. If you use DEF SEG, you must change it back before running a put pixel ' routine. In order to make this easy, a variable is set up that holds ' the segment address required by the various routines. Just put the ' line DEF SEG = ppSeg to point to the right place. Of course, if you're ' not using a put pixel routine, you should restructure the code so that ' the default segment points somewhere else, but that's up to you. ' ' The following is a list of SVGA video modes that are currently supported ' if they are available. Exactly which modes are available depends on the ' graphics card. ' ' Mode Number Resolution Colours Graphics Functions '================================================================== ' &H100 640x400 256 PutPixel, Put256 ' &H101 640x480 256 PutPixel, Put256 ' &H103 800x600 256 PutPixel, Put256 ' &H105 1024x768 256 PutPixel, Put256 ' &H107 1280x1024 256 PutPixel, Put256 ' &H10D 320x200 32k PutPixel15 ' &H10E 320x200 64k PutPixel16 ' &H110 640x480 32k PutPixel15 ' &H111 640x480 64k PutPixel16 ' &H113 800x600 32k PutPixel15 ' &H114 800x600 64k PutPixel16 ' &H116 1024x768 32k PutPixel15 ' &H117 1024x768 64k PutPixel16 ' &H119 1280x1024 32k PutPixel15 ' &H11A 1280x1024 64k PutPixel16 ' ' And now a brief description of how to use this little package. You can ' look at the demo code below for some help too. ' 1. Include all TYPE definitions, SUB and FUNCTION declarations, COMMON ' SHARED and DIM SHARED variables in your code, a header file might be a ' good idea. ' 2. Run the LoadAsm function to set up the assembly routines if you are ' using a 256 colour mode. ' 3. Call the DetectVESA function. If it returns 1 then the computer has ' VESA capabilities, if it returns 0, it doesn't so this code won't work. ' 4. Call the SetSVGAMode function with a mode from the list above as a ' parameter. If the mode isn't available it returns 0, if the mode is ' available it returns the number of video memory pages available. ' Last. Call SetOldMode to restore the previous video mode before the program ' ends. ' ' And then the other functions. ' GetVideoMode - Returns the current video mode, this routine is used by the ' SetSVGAMode function before changing modes so that the ' SetOldMode routine can work. ' Put256 - Very fast put routine that is compatible with mode 13h ' sprites. As the demo code shows, get the sprite in QB screen ' 13 for use in 256 colour SVGA modes. A sprite with data in ' array() is put on the screen at top left corner (x, y). ' StartIndex refers to the element in the array at which the ' sprite data begins. Thus more than one sprite can be stored ' in a single array. Use only in 256 colour modes. ' PutPixel - Puts a pixel on the screen at (x, y) of colour clr in any ' 256 colour screen mode. ' PutPixel15 - Puts a pixel on the screen at (x, y). The colour is made up ' of the red, green, and blue (rgb) components that are passed ' to the routine. The red, green, and blue components can have ' any value from 0 to 31. Works in 15 bit modes (32k colours). ' PutPixel16 - Same as PutPixel15 except works in 16 bit modes (64k ' colours). The red and blue components can have any value ' from 0 to 31. The green component can have any value from 0 ' to 63. ' SetActPage - Sets the video memory page that will be written to. Note ' this routine does not check to make sure multiple pages are ' available, that's up to you using the value returned from ' the SetSVGAMode function. ' ViewPage - Sets the visible video memory page. Like SetActPage it does ' not check to make sure multiple pages are available. ' ' Finally, a list of important variables. These variables either give you ' or the routines important info about the screen mode. Variables marked ' with an asterisk (*) are needed by the routines and should not be changed ' unless you know what you're doing. ' ' xRes, yRes - Holds the screen resolution, filled by SetSVGAMode. ' yOffset * - Adjusts y coordinates for different video memory pages, ' changed by SetActPage. ' curBank * - Holds the current bank being written to, needed by all put ' pixel routines. ' winGran * - Holds the window granularity of the graphics card adjusted ' for use by the put pixel routines. ' oldMode - Stores the screen mode that was in use before setting an ' SVGA mode. ' ppSeg * - Holds either the segment address of the assembly put pixel ' routine or the segment address of the graphics buffer. ' ppOfs * - Holds the offset address of the assembly put pixel routine, ' not used in 15 and 16 bit modes. ' bpp - Holds the number of bits per pixel for the screen mode. ' This can be used to find out how many colours a mode offers ' with the formula numColours = 2 ^ bpp. ' Regs * - A variable used as the CPU registers, used by most routines. ' pp256 * - Holds the machine code for the 256 colour assembly pset. ' sPut256 * - Holds the machine code for the 256 colour assembly put. '**************************************************************************** DEFINT A-Z DECLARE FUNCTION DetectVESA () DECLARE FUNCTION GetVideoMode () DECLARE SUB LoadAsm () DECLARE SUB Put256 (x, y, array(), startIndex) DECLARE SUB PutPixel (x, y, clr) DECLARE SUB PutPixel15 (x, y, r, g, b) DECLARE SUB PutPixel16 (x, y, r, g, b) DECLARE SUB SetActPage (page) DECLARE FUNCTION SetSVGAMode (mode) DECLARE SUB SetOldMode () DECLARE SUB ViewPage (page) COMMON SHARED xRes, yRes, yOffset, curBank, winGran, oldMode, ppSeg, ppOfs, bpp ' CPU registers used for BIOS calls. These are also defined in QB.BI. TYPE RegType AX AS INTEGER BX AS INTEGER CX AS INTEGER DX AS INTEGER BP AS INTEGER SI AS INTEGER DI AS INTEGER FLAGS AS INTEGER DS AS INTEGER ES AS INTEGER END TYPE ' Type used by VESA function 00h, filled with info on the VESA. TYPE VGAInfoBlock VESASignature AS STRING * 4 VESAVersion AS INTEGER OEMStringPtr AS LONG Capabilities AS STRING * 4 VideoModePtr AS LONG TotalMemory AS INTEGER Reserved AS STRING * 236 END TYPE ' Type used by VESA function 02h, filled with info on a screen mode. TYPE ModeInfoBlock ModeAttributes AS INTEGER WinAAttributes AS STRING * 1 WinBAttributes AS STRING * 1 WinGranularity AS INTEGER WinSize AS INTEGER WinASegment AS INTEGER WinBSegment AS INTEGER WinFuncPtr AS LONG BytesPerScanLine AS INTEGER XResolution AS INTEGER YResolution AS INTEGER XCharSize AS STRING * 1 YCharSize AS STRING * 1 NumberOfPlanes AS STRING * 1 BitsPerPixel AS STRING * 1 NumberOfBanks AS STRING * 1 MemoryModel AS STRING * 1 BankSize AS STRING * 1 NumberOfImagePages AS STRING * 1 Rsvd AS STRING * 1 RedMaskSize AS STRING * 1 RedFieldPosition AS STRING * 1 GreenMaskSize AS STRING * 1 GreenFieldPosition AS STRING * 1 BlueMaskSize AS STRING * 1 BlueFieldPosition AS STRING * 1 RsvdMaskSize AS STRING * 1 DirectColorModeInfo AS STRING * 1 Reserved AS STRING * 216 END TYPE DIM SHARED Regs AS RegType DIM SHARED pp256 AS STRING DIM SHARED sPut256 AS STRING LoadAsm '-=-=-=-=-=-=-=-=-=-=-=-=-=-DEMO CODE STARTS HERE-=-=-=-=-=-=-=-=-=-=-=-=-=- DIM spr(201) 'Set up a sprite for use SCREEN 13 'in 256 colour modes with CLS 'the Put256 routine. CIRCLE (9, 9), 9, 27 PSET (6, 6), 11: PSET (12, 6), 11: PSET (9, 9), 14 LINE (6, 12)-(12, 12), 100 GET (0, 0)-(19, 19), spr ' To test the various screen modes simply change the value in the SetSVGAMode ' function to the mode of your choice. IF DetectVESA THEN 'Check for VESA pagesAvailable = SetSVGAMode(&H101) 'Check for/set SVGA mode and IF pagesAvailable = 0 THEN SYSTEM 'get number of memory pages. ELSE SYSTEM 'No VESA so shut down END IF FOR y = 0 TO yRes - 1 'Fill the screen with pixels FOR x = 0 TO xRes - 1 IF bpp = 8 THEN 'Execute a different function PutPixel x, y, x MOD 256 'depending on the mode type. ELSEIF bpp = 15 THEN PutPixel15 x, y, x \ 40 + y \ 30, ABS(x - (xRes \ 2)) \ 20 + ABS(y - (yRes - 1)) \ 30, ABS(x - (xRes - 1)) \ 40 + y \ 30 ELSEIF bpp = 16 THEN PutPixel16 x, y, x \ 40 + y \ 30, ABS(x - (xRes \ 2)) \ 10 + ABS(y - (yRes - 1)) \ 15, ABS(x - (xRes - 1)) \ 40 + y \ 30 END IF NEXT x NEXT y SLEEP IF bpp = 8 THEN 'In 256 colour modes FOR y = 0 TO yRes - 1 STEP 20 'demonstrate the put routine. FOR x = 0 TO xRes - 1 STEP 20 IF bpp = 8 THEN Put256 x, y, spr(), 0 NEXT x NEXT y SLEEP END IF SetOldMode 'Back to last mode DEF SEG 'Reset default segment SYSTEM 'Shut down ' Machine code for put pixel 256. DATA 73 ' 0 1 2 3 4 5 6 7 8 9 DATA &H06,&H55,&H89,&HE5,&H8B,&H46,&H10,&H8B,&H5E,&H0C : '0 DATA &HF7,&HE3,&H8B,&H5E,&H12,&H01,&HD8,&H72,&H34,&H89 : '1 DATA &HC1,&H89,&HD0,&H8B,&H56,&H0A,&H39,&HD0,&H75,&H10 : '2 DATA &H89,&HCF,&HB8,&H00,&HA0,&H8E,&HC0,&H8B,&H46,&H0E : '3 DATA &HAA,&H5D,&H07,&HCA,&H0C,&H00,&HBF,&H00,&H00,&HBB : '4 DATA &H00,&H00,&H8E,&HC3,&HAB,&H8B,&H5E,&H08,&HF7,&HE3 : '5 DATA &H89,&HC2,&H31,&HDB,&HB8,&H05,&H4F,&HCD,&H10,&HEB : '6 DATA &HD7,&H42,&HEB,&HC9 : '7 'Machine code for put 256. DATA 215 ' 0 1 2 3 4 5 6 7 8 9 DATA &H06,&H1E,&H55,&H50,&H50,&H50,&H50,&H89,&HE5,&H8B : ' 0 DATA &H46,&H18,&H89,&H46,&H06,&H8B,&H46,&H20,&H89,&H46 : ' 1 DATA &H04,&H8B,&H46,&H1E,&H89,&H46,&H02,&H8B,&H5E,&H1A : ' 2 DATA &H31,&HD2,&HF7,&HF3,&H89,&H56,&H1E,&H8B,&H46,&H14 : ' 3 DATA &H8E,&HD8,&H8B,&H76,&H12,&HB8,&H00,&HA0,&H8E,&HC0 : ' 4 DATA &HFC,&HAD,&H89,&HC1,&HC1,&HE9,&H03,&H89,&H4E,&H00 : ' 5 DATA &HAD,&H89,&HC3,&H8B,&H46,&H1E,&H8B,&H56,&H1A,&H39 : ' 6 DATA &HD0,&H73,&H3B,&H8B,&H46,&H02,&H8B,&H56,&H1C,&HF7 : ' 7 DATA &HE2,&H89,&HC7,&H8B,&H46,&H20,&H01,&HC7,&H72,&H49 : ' 8 DATA &H8B,&H46,&H06,&H39,&HD0,&H75,&H47,&H8B,&H46,&H04 : ' 9 DATA &H8B,&H56,&H1C,&H39,&HD0,&H73,&H08,&HAC,&H47,&H3C : '10 DATA &H00,&H74,&H02,&H4F,&HAA,&H8B,&H46,&H04,&H40,&H89 : '11 DATA &H46,&H04,&H8B,&H56,&H06,&H83,&HFF,&H00,&H74,&H24 : '12 DATA &HE2,&HDD,&H4B,&H83,&HFB,&H00,&H74,&H38,&H8B,&H4E : '13 DATA &H00,&H8B,&H46,&H20,&H89,&H46,&H04,&H8B,&H46,&H02 : '14 DATA &H40,&H89,&H46,&H02,&H8B,&H46,&H1E,&H40,&H89,&H46 : '15 DATA &H1E,&HEB,&H9C,&H42,&HEB,&HB4,&H42,&H49,&H89,&H56 : '16 DATA &H06,&H8B,&H46,&H16,&H53,&HF7,&HE2,&H89,&HC2,&H31 : '17 DATA &HDB,&HB8,&H05,&H4F,&HCD,&H10,&H5B,&H83,&HF9,&H00 : '18 DATA &H74,&HC4,&HEB,&H9F,&HB8,&H00,&H00,&H8E,&HC0,&HBF : '19 DATA &H00,&H00,&H8B,&H46,&H06,&HAB,&H58,&H58,&H58,&H58 : '20 DATA &H5D,&H1F,&H07,&HCA,&H10,&H00 : '21 ' Detect to see if a VESA compatible graphics card is present. FUNCTION DetectVESA DIM VGAInfo AS VGAInfoBlock Regs.AX = &H4F00 Regs.ES = VARSEG(VGAInfo) Regs.DI = VARPTR(VGAInfo) CALL INTERRUPTX(&H10, Regs, Regs) IF Regs.AX = &H4F THEN DetectVESA = 1 PRINT VGAInfo.VESASignature; RTRIM$(STR$(VGAInfo.VESAVersion \ 256)); "."; LTRIM$(STR$(VGAInfo.VESAVersion AND 255)) ELSE DetectVESA = 0 PRINT "Error - cannot detect VESA." END IF END FUNCTION ' Returns the current video mode. FUNCTION GetVideoMode Regs.AX = &H4F03 CALL INTERRUPT(&H10, Regs, Regs) GetVideoMode = Regs.BX END FUNCTION SUB LoadAsm RESTORE DEF SEG = VARSEG(pp256) pp256 = "" READ codeLen FOR i = 0 TO codeLen READ code$ chrNo = VAL(code$) pp256 = pp256 + CHR$(chrNo) NEXT i DEF SEG = VARSEG(sPut256) sPut256 = "" READ codeLen FOR i = 0 TO codeLen READ code$ chrNo = VAL(code$) sPut256 = sPut256 + CHR$(chrNo) NEXT i DEF SEG END SUB SUB Put256 (x, y, array(), startIndex) DEF SEG = VARSEG(sPut256) yVal = y + yOffset CALL ABSOLUTE(BYVAL x, BYVAL yVal, BYVAL xRes, BYVAL yRes, BYVAL curBank, BYVAL winGran, BYVAL VARSEG(array(startIndex)), BYVAL VARPTR(array(startIndex)), SADD(sPut256)) DEF SEG = ppSeg END SUB ' Sets a pixel. SUB PutPixel (x, y, clr) yVal = y + yOffset CALL ABSOLUTE(BYVAL x, BYVAL yVal, BYVAL clr, BYVAL xRes, BYVAL curBank, BYVAL winGran, ppOfs) END SUB SUB PutPixel15 (x, y, r, g, b) r = r AND 31: g = g AND 31: b = b AND 31 yA& = (y + yOffset) * 2 offset& = yA& * xRes + (x * 2) bank = offset& \ &H10000 offset& = offset& - &H10000 * bank IF bank <> curBank THEN curBank = bank Regs.AX = &H4F05 Regs.BX = 0 Regs.DX = winGran * curBank CALL INTERRUPT(&H10, Regs, Regs) END IF hiClr = r * 4 + g \ 8: loClr = (g AND 7) * 32 + b POKE offset&, loClr: POKE offset& + 1, hiClr END SUB SUB PutPixel16 (x, y, r, g, b) r = r AND 31: g = g AND 63: b = b AND 31 yA& = (y + yOffset) * 2 offset& = yA& * xRes + (x * 2) bank = offset& \ &H10000 offset& = offset& - &H10000 * bank IF bank <> curBank THEN curBank = bank Regs.AX = &H4F05 Regs.BX = 0 Regs.DX = winGran * curBank CALL INTERRUPT(&H10, Regs, Regs) END IF hiClr = r * 8 + g \ 8: loClr = (g AND 7) * 32 + b POKE offset&, loClr: POKE offset& + 1, hiClr END SUB ' Just changes the pointer to the video memory but it's easier to use this ' way. SUB SetActPage (page) yOffset = yRes * page END SUB ' Sets the video mode that was being used before the SVGA mode. The SCREEN ' command doesn't always work so this is used instead. SUB SetOldMode IF oldMode < &H100 THEN 'SVGA modes cannot be reset by this Regs.AX = oldMode 'routine. CALL INTERRUPT(&H10, Regs, Regs) ELSE 'If it was SVGA, set text. Regs.AX = &H3 CALL INTERRUPT(&H10, Regs, Regs) END IF END SUB ' Sets an SVGA mode. FUNCTION SetSVGAMode (mode) oldMode = GetVideoMode 'Get the current mode. DIM ModeInfo AS ModeInfoBlock 'Get info on the desired Regs.AX = &H4F01 'SVGA mode. Regs.CX = mode Regs.ES = VARSEG(ModeInfo) Regs.DI = VARPTR(ModeInfo) CALL INTERRUPTX(&H10, Regs, Regs) IF (ModeInfo.ModeAttributes AND 1) = 0 THEN 'Bit 1 = 0 then mode not PRINT "Error - screen mode not available." 'available. SetSVGAMode = 0 EXIT FUNCTION END IF winGran = 64 \ ModeInfo.WinGranularity 'Window granularity adjusted. xRes = ModeInfo.XResolution 'Get screen resolution. yRes = ModeInfo.YResolution IF ModeInfo.WinSize < 64 THEN PRINT "Error - this program requires at least a 64k memory window." SetSVGAMode = 0 'Window must be > 64k for EXIT FUNCTION 'these routines. END IF bpp = ASC(ModeInfo.BitsPerPixel) IF bpp = 8 THEN IF ASC(ModeInfo.MemoryModel) <> 4 THEN PRINT "Error - screen mode not available." SetSVGAMode = 0 EXIT FUNCTION END IF ppSeg = VARSEG(pp256): ppOfs = SADD(pp256) lB1 = ModeInfo.WinASegment AND 255: hB1 = ModeInfo.WinASegment \ 256 lB2 = VARPTR(curBank) AND 255: hB2 = VARPTR(curBank) \ 256 lB3 = VARSEG(curBank) AND 255: hB3 = VARSEG(curBank) \ 256 tempOfs = SADD(sPut256) DEF SEG = VARSEG(sPut256) POKE 46 + tempOfs, lB1: POKE 47 + tempOfs, hB1 POKE 200 + tempOfs, lB2: POKE 201 + tempOfs, hB2 POKE 195 + tempOfs, lB3: POKE 196 + tempOfs, hB3 DEF SEG = ppSeg POKE 33 + ppOfs, lB1: POKE 34 + ppOfs, hB1 POKE 47 + ppOfs, lB2: POKE 48 + ppOfs, hB2 POKE 50 + ppOfs, lB3: POKE 51 + ppOfs, hB3 ELSEIF bpp = 15 THEN IF ASC(ModeInfo.MemoryModel) <> 6 THEN PRINT "Error - screen mode not available." SetSVGAMode = 0 EXIT FUNCTION END IF ppSeg = ModeInfo.WinASegment DEF SEG = ppSeg ELSEIF bpp = 16 THEN IF ASC(ModeInfo.MemoryModel) <> 6 THEN PRINT "Error - screen mode not available." SetSVGAMode = 0 EXIT FUNCTION END IF ppSeg = ModeInfo.WinASegment DEF SEG = ppSeg ELSE PRINT "Error - screen mode not available." SetSVGAMode = 0 EXIT FUNCTION END IF Regs.AX = &H4F02 'Set the mode. Regs.BX = mode CALL INTERRUPT(&H10, Regs, Regs) IF Regs.AX <> &H4F THEN 'Make sure it worked. PRINT "Error - cannot initialize screen mode." SetSVGAMode = 0 EXIT FUNCTION END IF curBank = 0 'Initialize bank and page. yOffset = 0 SetSVGAMode = (ASC(ModeInfo.NumberOfImagePages) + 1) END FUNCTION ' Set the visible video memory page. SUB ViewPage (page) firstLine = page * yRes Regs.AX = &H4F07 Regs.BX = 0 Regs.CX = 0 Regs.DX = firstLine CALL INTERRUPT(&H10, Regs, Regs) END SUB