|
QBXL Technical Articles
VGA Boot Camp |
|
Hello there maggot, and welcome to video mode Bootcamp. This will NOT be a walk in the park. This will NOT be fun. You will likely CRY. LIKE A BABY. If you're the sort who can't handle the sight of blood or the thought of low level programming, THIS TUTORIAL IS NOT FOR YOU. Video memory Now, since you are the sorryest bunch of apes I've ever had the misfortune to have to deal with, I'll start with something easy -- video memory. It's so easy that my poor sweet momma in the nursing home can understand it, so LISTEN UP. I'm only going to explain this once, so you'd BETTER pay attention! There are generally THREE ways that video memory can be set up. These are PLANAR, NON-PLANAR, and THAT CREEPY THING REAL-MODE VESA DOES. Those are all SCIENTIFIC terms. REMEMBER THEM. They WILL save your life. Now PLANAR modes are unique to ModeX. These are also known as NON-CHAINED modes. In ModeX, they're generally set up in 4 planes, which are set up like this: 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 In order to write to a pixel on a certain plane, you have to tell the video card which you plan to write to. Luckily for us, you DO NOT need to do this every time you write to memory, just when you switch planes. This means that with care, most ModeX video modes are capable of running nearly as fast as a regular video mode. We'll come back to this later. NON PLANAR MODES, also called CHAINED modes, are set up so all the memory can be seen in one continuous block. Any pixel on the screen can be accessed at any time. Mode 13h, 320x200 uses this scheme. It's phenomally fast to acces because no extra work is needed. However, it's quite memory inefficient, hence the 320x200 limit. THAT CREEPY THING REAL-MODE VESA DOES is creepy. Every 4, 16, 32, or 64k based on the GRANULARITY setting in the video card, you have to tell the video card to head to the next memory segment, so the memory at 0xa000(we'll get to that in a second) becomes the memory from the 1st pixel to the 4 thousandth, from the 4 thousandth to the 8 thousandth, and so on. It's definitely creepy. Something a standard maker would think up. The worst part is that it's horribly complicated trying to optimze a standard pset routine as a result, because you never really know when you're going to have to draw a sprite over an interection of two territories, and incur the ultimate speed penalty of a bunch of segment changes(and trying to detect said segment changes) without careful planning! THIS IS WHY VESA MODES IN REAL-MODE DOS IS SLOW, PEOPLE! Setting up video modes There are THREE ways that you will be able to set up video modes. These are CALLING THROUGH THE INTERRUPT 10h, SETTING THE VGA REGISTERS DIRECTLY, and THAT CREEPY THING REAL-MODE VESA DOES. CALLING THROUGH INTERRUPT 10H is the easiest way. In QB, you just use the SCREEN statement. When you say SCREEN 13, you're saying "Set ax to and call interrupt 10h". I can't explain this any better, because it's too easy. SETTING THE VGA REGISTERS DIRECTLY is how we get MODE X and MODE Q modes. Setting these is quite DANGEROUS. You WILL NOT do this on your own. Only use either sample code from others or technical specs from others. You CAN and likely WILL damage your hardware if you play with this incorrectly! THAT CREEPING THING REAL-MODE VESA DOES isn't really that creepy. It's just calling another interrupt. IT'S STILL CREEPY THOUGH, because IT IS REAL MODE VESA. Remember that. REAL MODE VESA IS CREEPY. Examples Ever since that PANSY LIBERAL PINKO of a judge from LEFT WING TEXAS said that we COULDN'T put troops in the field and ask them to program hardware without showing them HOW, we now have to give four examples of graphics programming. Remember to PAY ATTENTION, because this information IS VITAL. ESPECIALLY if you're a weak little mommas boy who couldn't figure out how to do this from the paragraphs ABOVE. FIRST OFF, we will show you an example of simple Mode 13h, which is 320x200. It uses CALLING THROUGH INTERRUPT 10H to set it's video mode, and is a NON PLANAR MODE. declare sub putd(x%, y%, colr%) def seg = &Ha000 screen 13 FOR a = 0 TO 255 FOR b = 0 TO 255 putd a, b, c NEXT b NEXT a STATIC SUB putd (x, y, colr) POKE (x * 320&) + y, colr END SUB SECOND, we will show you an example of Mode Q. Mode Q is 256x256. It uses SETTING THE VGA REGISTERS DIRECTLY to set up the screen, and is a NON PLANAR MODE. PAY ATTENTION to the setModeQ routine, which sets up the video mode, and the putd routine, which draws pixels to the screen. DEFINT A-Z def seg = &Ha000 DECLARE SUB setModeQ () DECLARE SUB deinit () DECLARE SUB putd (x%, y%, colr%) setModeQ WHILE INKEY$ = "" c = INT(RND(1) * 255) FOR a = 0 TO 255 FOR b = 0 TO 255 putd a, b, c NEXT b NEXT a WEND deinit SUB deinit () CLS SCREEN 13: SCREEN 0: WIDTH 80 END END SUB STATIC SUB putd (x, y, colr) POKE (x * 256&) + y, colr END SUB DEFSNG A-Z SUB setModeQ () DEF SEG = &HA000 'begin with standard 320x200x256 mode SCREEN 13 'to reprogram the CRT controller, 'remove write protect from the registers OUT &H3D4, &H11: OUT &H3D5, INP(&H3D5) AND &H7F OUT &H3D4, &H0: OUT &H3D5, &H5F 'Hor. Total OUT &H3D4, &H1: OUT &H3D5, &H3F 'Hor. Display enable end OUT &H3D4, &H2: OUT &H3D5, &H40 'blank start OUT &H3D4, &H3: OUT &H3D5, &H82 'blank end OUT &H3D4, &H4: OUT &H3D5, &H4E 'retrace start OUT &H3D4, &H5: OUT &H3D5, &H9A 'retrace end OUT &H3D4, &H6: OUT &H3D5, &H23 'vertical total OUT &H3D4, &H7: OUT &H3D5, &HB2 'overflow register OUT &H3D4, &H8: OUT &H3D5, &H0 'preset row scan OUT &H3D4, &H9: OUT &H3D5, &H61 'max scan line/char height OUT &H3D4, &H10: OUT &H3D5, &HA 'vertical retrace start OUT &H3D4, &H11: OUT &H3D5, &HAC 'vertical retrace end OUT &H3D4, &H12: OUT &H3D5, &HFF 'vertical display enable end OUT &H3D4, &H13: OUT &H3D5, &H20 'offset/logical width OUT &H3D4, &H14: OUT &H3D5, &H40 'underlinde location OUT &H3D4, &H15: OUT &H3D5, &H7 'vertical blank start OUT &H3D4, &H16: OUT &H3D5, &H17 'vertical blank end OUT &H3D4, &H17: OUT &H3D5, &HA3 'mode control OUT &H3C4, &H1: OUT &H3C5, &H1 'clock mode register OUT &H3C4, &H4: OUT &H3C5, &HE 'memory mode register OUT &H3CE, &H5: OUT &H3CF, &H40 'mode register OUT &H3CE, &H6: OUT &H3CF, &H5 'misc. register OUT &H3C0, &H10 + 32: OUT &H3C1, &H41 'mode control 'reprotect the registers OUT &H3D4, &H11: OUT &H3D5, INP(&H3D5) OR &H80 END SUB THIRDLY, we have here a FINE EXAMPLE of MODE X, at 320x240. THIS IS A PLANAR MODE. It SETS THE VGA REGISTERS DIRECTLY, and is one of the HARDEST video modes to use correctly. PAY ATTENTION to every part of this complicated routine, and you MAY make it out there, you WORTHLESS PIECE OF DIRT! DECLARE SUB putd (sx%, sy%, colr%) DECLARE SUB pbox (firstx%, lastx%, firsty%, lasty%, colr%) DECLARE SUB pageflip () DECLARE SUB box (firstx%, lastx%, firsty%, lasty%, colr%) DECLARE SUB xcls (page%) DECLARE SUB showpage (page%) DECLARE SUB Set320x240mode () DEFINT A-Z def seg = &Ha000 DIM SHARED page AS INTEGER DIM bitmask%(7) FOR Bit% = 0 TO 7: bitmask%(Bit%) = 2 ^ Bit%: NEXT PRINT "Sj Zeros Optimization demonstration." PRINT "Press any key to start" SLEEP Set320x240mode 'The XCLS is needed or else the program will crash. xcls 0 xcls 1 xcls 2 'Program loop goes here! 'meant to set the video page and keep it there. 'Pageflip defs the seg, and then I show that video page. It looks awful 'if you triple buffer the below demonstrations... pageflip showpage 1 FOR v = 1 TO 5 FOR a = 0 TO 255 box 0 + a, 320 - a, 0 + a, 240 - a, a'This fills the entire screen with new pixels. 'Just meant to demonstrate the speed of this. NEXT a NEXT v SCREEN 13: SCREEN 0: WIDTH 80 PRINT "That was the fast algorithm in action. Press space to see the slow" PRINT "algorithm do the same thing to see the speed difference." SLEEP Set320x240mode 'The XCLS is needed or else the program will crash. xcls 0 xcls 1 xcls 2 'Program loop goes here! 'This is meant to set the video page and keep it there. pageflip showpage 2 FOR v = 1 TO 5 FOR a = 0 TO 255 pbox 0 + a, 320 - a, 0 + a, 240 - a, a'This fills the entire screen with new pixels. 'Just meant to demonstrate the speed of this. NEXT a NEXT v PRINT "Quite a difference, eh?" PRINT "Enjoy!" SCREEN 13: SCREEN 0: WIDTH 80 END SUB box (firstx%, lastx%, firsty%, lasty%, colr%) 'This is probably the fastest way to write to a modex screen. 'in my own game I replaced the a%/4 with a function that returned 'the result of that operation. a% is between 0 and 320, but while 'that is a lot of memory, it's worth the speed increase in the end. SHARED bitmask%() startedhere% = firsty% * 80 'this sets the vertical position. FOR a% = (firstx% - 1) TO lastx% OUT &H3C5, bitmask%(a% AND 3) 'Sets the bitplane *once per line* 'very important for speed. sy% = a% \ 4 + startedhere% 'This sets the horizontal position FOR b% = firsty% TO lasty% 'moves vertically sy% = sy% + 80 'adds 80 to the video pointer POKE sy%, colr% 'places that pixel! 'code to read a screen buffer could easily be placed here 'to use this in any kind of game, even a crappy 'pure QB 3d shooter! :) NEXT b%, a% END SUB SUB pageflip 'This is a nice routine I wrote that didn't come with the original. 'This will change the video focus while rendering. important for 'games that take advantage of triple buffering. showpage page IF page = 1 THEN page = 2 ELSE IF page = 2 THEN page = 0 ELSE IF page = 0 THEN page = 1 SELECT CASE page 'This *was* in the putpixel routine. Evil. CASE 0: VidSegment% = &HA000 CASE 1: VidSegment% = &HA4F0 CASE 2: VidSegment% = &HA9E0 CASE ELSE: ERROR 5 END SELECT DEF SEG = VidSegment% END SUB SUB pbox (firstx%, lastx%, firsty%, lasty%, colr%) FOR x% = firstx% TO lastx% FOR y% = firsty% TO lasty% putd x%, y%, colr% NEXT y% NEXT x% END SUB SUB putd (sx%, sy%, colr%) STATIC 'Clipping is done, despite the speed loss. IF colr% <> 0 AND sx% > -1 AND sx% < 320 AND sy% < 240 THEN SHARED bitmask%() OUT &H3C5, bitmask%(sx% AND 3) 'This must set the plane...... POKE sy% * 80 + sx% \ 4, colr% END IF END SUB SUB Set320x240mode 'begin with standard 320x200x256 mode SCREEN 13 'disable "chain4" mode OUT &H3C4, &H4: OUT &H3C5, &H6 'enable writes to all four planes OUT &H3C4, &H2: OUT &H3C5, &HF 'clear video memory 'synchronous reset while switching clocks OUT &H3C4, 0: OUT &H3C5, &H1 'select 25 Mhz dot clock and 60 hz scanning rate OUT &H3C2, &HE3 'restart the sequencer OUT &H3C4, 0: OUT &H3C5, &H3 'to reprogram the CRT controller, 'remove write protect from the registers OUT &H3D4, &H11: OUT &H3D5, INP(&H3D5) AND &H7F OUT &H3D4, &H6: OUT &H3D5, &HD 'total vertical pixels OUT &H3D4, &H7: OUT &H3D5, &H3E 'overflow OUT &H3D4, &H9: OUT &H3D5, &H41 'turn off double double-scan OUT &H3D4, &H10: OUT &H3D5, &HEA 'vertical sync start OUT &H3D4, &H11: OUT &H3D5, &HAC 'vertical sync end, reprotect registers OUT &H3D4, &H12: OUT &H3D5, &HDF 'vertical pixels displayed OUT &H3D4, &H14: OUT &H3D5, 0 'turn off dword mode OUT &H3D4, &H15: OUT &H3D5, &HE7 'vertical blank start OUT &H3D4, &H16: OUT &H3D5, &H6 'vertical blank end OUT &H3D4, &H17: OUT &H3D5, &HE3 'turn on byte mode OUT &H3C4, 2 'I removed this from the main putpixel loop. 'It used to be in the main renderer, but it's slow, and only 'needed once, at execution. END SUB SUB showpage (page%) SELECT CASE page% CASE 0: OUT &H3D4, &HC: OUT &H3D5, 0 CASE 1: OUT &H3D4, &HC: OUT &H3D5, &H4F CASE 2: OUT &H3D4, &HC: OUT &H3D5, &H9E CASE ELSE: ERROR 5 'illegal function call END SELECT END SUB SUB xcls (page%) SELECT CASE page% CASE 0: VidSegment% = &HA000 CASE 1: VidSegment% = &HA4F0 CASE 2: VidSegment% = &HA9E0 CASE ELSE: ERROR 5 END SELECT OUT &H3C4, &H2: OUT &H3C5, &HF DEF SEG = VidSegment% FOR Address% = 0 TO 19199: POKE Address%, 0: NEXT END SUB I HOPE YOU GOT THAT, BOY! This is EXTREMELY COMPLICATED STUFF! You wanna GO HOME? wanna go home and CRY to MOMMA? DO YOU? Tough. This is the fighting mans army, so you gotta stay and fight like the rest of us. FINALLY. We have an example of REAL-MODE VESA. As you recall, this is CREEPY. You'd better learn it fast though, or you'll be GOING DOWN FASTER THAN AN INTERN IN THE WHITEHOUSE. '$INCLUDE: 'QB.BI' DEF SEG = &HA000 set640x480mode FOR x% = firstx% TO lastx% FOR y% = firsty% TO lasty% putd x%, y%, colr% NEXT y% NEXT x% END DEFINT A-Z SUB putd (x, y, clr) offset& = x + xRes * y Bank% = offset& \ 65536 offset& = offset& + Bank% * 65536 IF Bank <> Banknow THEN Banknow = Bank% regs.ax = &H4F05 regs.bx = 0 regs.dx = Bank% CALL INTERRUPT(&H10, regs, regs) END IF POKE offset&, clr END SUB END SUB END SUB SUB set640x480mode xRes = 640 regs.ax = &H4F02 regs.bx = &H101 CALL INTERRUPT(&H10, regs, regs) END SUB THERE. I've done ALL I CAN DO. You'd better PRAY TO GOD that you got that. Good luck, I think I've taught you well. Go out there and make us all proud, You bunch of apes!! MOVE IT! - --SJ Zero
won't be writing many
more QB articles, so eat up! FB does all this stuff on it's own! |
||
|
|||