Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Offsets, segments, and buffering 1

Status
Not open for further replies.

rowmath

Instructor
Jun 3, 2003
1
US
Man, what a topic. First some background. I am a high school programming teacher. I have some students who have taken QB to new levels (at least in my mind). They are trying to write a game that is graphics intensive and have stumbled across the idea of buffering/double-buffering. I have been trying to help them and get this stuff done, but try as I may I can't get a handle on it. I am familar with pointers in c++ and there seems to be some similarities to buffering. Beyond that I feel like a newbie. Can any one point me to, or send me a tutorial that makes sense of writing to memory in QB?
 
The only way to directly access memory in QB is via the POKE and PEEK commands.

Most QB programs that use QB double buffering use memcopy routines written in ASM or machine code.

One method I've seen used is to GET a portion of the screen, and write to the memory of the array used to store the GET data, and then PUT it onto the screen.

I assume the reason for double buffering is to help prevent flicker. One way to do help prevent flicker is call WAIT &H3DA, 8 right before drawing the graphics.

I was able to do this and have decent scrolling on a 486 25mhz with a game called Spinball that I wrote about 6 years ago.

You can find the source to this game (and a review) at :


I wish I had some actual double buffering source to give you but it was so long ago and I've lost it...
 
double buffering in qbasic is basically creating an array and using the array as a memory block with which you can PEEK and POKE data to and then flip it onto the screen. In screen 13 it would be something like this:

Screen 13
'set up my first page
dim page1%(32000)
'set up my second page
dim page2%(32000)

'fill the two arrays
for x=1 to 319
for y=1 to 199
bufferPixel varseg(page1%(0)),x,y,(x mod 256)
bufferPixel varseg(page2%(0)),x,y,(x mod 256)
next y
next x

'now just put it onto the screen

put (1,1),page1%(0)

do:loop until(inp(96)=1)

put (1,1),page2%(0)

ok that should work. please note there is a faster and much better way to flip the screen buffer onto the screen that is in assembler, but I can only give you the asm code for it and not the machine code that you need for qbasic to use...if you want I could give you the asm code and you could figure it out, or I'm sure someone else could help you
 
Oh and if you use virtual pages in c++ then it is easier to allocate memory using pointers and such, but you can't really do any of that in qbasic
 
This is an area where many people have done a lot of work, but it requires an intimate knowledge of a number of things. First of all, a knowledge of pointers in C++ only partially helps, because memory addresses in QuickBASIC are segmented (read this FAQ for more information: faq314-290 "What are segments and offsets, PEEK(), POKE and DEF SEG, and how does QB store strings?"). As for allocating memory for a buffer, [tt]DIM[/tt] works as shown above, but has some hidden caveats. In source code, [tt]DIM[/tt] will always produce segment-aligned buffers, but in compiled programs, it will not. This can lead to confusing errors if you don't take [tt]VARPTR(buf%(0))[/tt] into account.

Also shown above is the use of [tt]PUT[/tt] to place the buffer onto the screen. This is generally a good approach, as it is fairly fast and avoids shearing by synchronizing with the vertical retrace. However, more is required than simply placing pixels into the buffer. The [tt]PUT[/tt] routine requires a specific header to be present prior to the pixel data in the buffer. It has the following format:
[tt]
Offset Size Description
-----------------------------------------------------------
0 WORD Number of bits per scan line (in SCREEN 13,
this means 8 times the number of pixels per
scan line).
2 WORD Number of scan lines (in other words, the
pixel height of the region).
[/tt]
So before you can [tt]PUT[/tt] the array, you need to place these values into it.

The header is 4 bytes, and an entire buffer in [tt]SCREEN 13[/tt] is 320 * 200 = 64000 bytes, so the buffer needs to be 64004 bytes long. If the buffer is made out of QB [tt]INTEGER[/tt]s, then it will need to contain 32002 elements. As the first element is 0 (barring [tt]OPTION BASE 1[/tt]), the last element (the value specified in the [tt]DIM[/tt] statement) must be 32001. Here is an example of actual working code that uses an offscreen buffer to draw to the screen. It animates bars scrolling upwards.
[tt]
DIM buf%(32001)

bufseg% = VARSEG(buf%(0))
bufptr% = VARPTR(buf%(0))

SCREEN 13

DEF SEG = bufseg%

DO
animationIndex% = (animationIndex% + 1) AND 255

offset& = bufptr% + 4 ' allow for PUT header
FOR y% = 0 TO 199
thisRowColour% = (y% + animationIndex%) AND 255
FOR x% = 0 TO 319
POKE offset&, thisRowColour%
offset& = offset& + 1&
NEXT x%
NEXT y%

buf%(0) = 320 * 8 ' set up PUT header
buf%(1) = 200

PUT (0, 0), buf%, PSET
LOOP UNTIL INKEY$
<> &quot;&quot;

SCREEN 0: WIDTH 80, 25
[/tt]
This example doesn't actually calculate the pixel offset. Instead, it draws the pixels strictly in ascending order of offset. The subroutine demonstrates calculating the offset:
[tt]
SUB setPixel(segment%, offset%, x%, y%, colour%)
DEF SEG = segment%
bufferOffset& = offset% + 4 + x% + 320& * y%
POKE bufferOffset&, colour%
END SUB
[/tt]
The parameters for this function would be passed as follows:
[tt]
setPixel VARSEG(buf%(0)), VARPTR(buf%(0)), x%, y%, colour%
[/tt]
Obviously, this could be optimized to not [tt]DEF SEG[/tt] for every pixel, and to avoid making a function call (in other words, it could be inlined into the code where it is needed).

Good luck with your class, and encourage your students to visit online sources of programming information themselves! As well as this site, there is a huge repository of BASIC code that they can read and learn from called &quot;All Basic Code&quot;, or ABC :) The URL for ABC is:

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top