BSAVING AND BLOADING IN QBASIC
This tutorial is intended for intermediate programmers
who are proficient with standard QBasic commands.
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Table of contents
(1) so what are BSAVE and BLOAD?
(2) making excellent graphics in EGA/VGA
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
So what are BSAVE and BLOAD?
BSAVE and BLOAD are two commands in the QBasic environment to allow
you to save graphics created using the method I explained in GRAPHICS.TXT
in a file. The file can then be loaded instantaneously from a program,
eliminating many of the delays created using the GRAPHICS.TXT method.
Both of these commands save part of memory to a file - they don't
just have to be used for graphics. This tutorial focuses on graphics.
To point BSAVE and BLOAD to the right memory address to start saving
from, you must use the DEF SEG statement in this form:
DEF SEG = VARSEG(arrayname(0))
arrayname is the name of the array you stored the graphic name
in using the GET command. After you are done BSAVEing or BLOADing,
use a solitary DEF SEG command to point memory back to where it should
be.
BSAVE is the next command you will learn in this tutorial. Its
basic syntax is:
BSAVE "graphic.ext", offset, length
"graphic.ext" is the filename of the graphic you want to save. You
can have any filename and any extension - for clarity, in my programs I
use the .GFX extension, though this is totally arbitrary.
length is the size of the array you DIMmed to store the graphic in
using the GET command. Be sure to get the EXACT number. The actual file
will be seven bytes larger than the length you specify here.
offset is the byte address of where to start saving. For the purp-
oses of this tutorial, offset will ALWAYS be zero. You can manipulate
these commands so as to save more than one graphic in a single file,
though I'll probably address this in another tutorial.
Now, on to the BLOAD command. Assuming you've already created and
saved a graphic using BSAVE, it's time to BLOAD the graphic into a
program. It's rather simple, really:
DIM arrayname(length)
SCREEN screenmode
DEF SEG = VARSEG(arrayname(0))
BLOAD "graphic.ext", 0
DEF SEG
PUT (0, 0), arrayname
Of course, you'll need to stick your arrayname and length into this
program along with the name of the file. I have attached with this tut-
orial an example of this, BSAVE.BAS, in which I BSAVE and BLOAD a picture
of a planet successfully. Look at this and experiment before moving on
to the next section.
Be sure to use the same SCREEN mode when you BSAVE and when you
BLOAD a graphic. For instance, if you BSAVEd a graphic in SCREEN 7,
you *must* BLOAD the graphic in SCREEN 7, too. BSAVE files are not
screen-mode interchangeable.
Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-Ä-
Making excellent graphics in EGA/VGA
Your best bet for making good graphics in EGA mode is just to
practice using the technique I explained in GRAPHICS.TXT. VGA mode
graphics can be created using a different method which will yield
better results.
For VGA graphics, it's best to create sprites in a paint program
(for example, CorelDRAW! or Autodesk Animator) and save them in .GIF
mode. Use the .GIF loading code attached to this tutorial to load the
.GIF in QBasic, then GET it into an array and BSAVE it into QBasic
format. An example of this is also attached to the tutorial.
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
The code above can be modified to whatever your needs.
Program Codes:
'GRAPHIC2.TXT example program
'GRAPHIC2.BAS
'
'The SUBroutine BSAVEExample shows how to BSAVE a picture.
'The rest of the program is an animation.
'
'GIF loading author is unknown.
'
'
'
DECLARE SUB BSAVEExample ()
DECLARE SUB GifLoad (a$)
GifLoad "palette.gif": CLOSE
DIM m1(6200)
DIM mallard(8000)
SCREEN 13
speed = 1000
DO
FOR i = 1 TO 8
IF x < 95 THEN x = x + 1: ELSE EXIT DO
'IF y < 50 THEN y = y + 1
DEF SEG = VARSEG(m1(0)): BLOAD "b" + LTRIM$(STR$(i)) + ".gfx", 0: DEF SEG
PUT (x, y), m1, PSET
ERASE m1
FOR j = 1 TO speed: NEXT
NEXT
LOOP
FOR z = 1 TO 3
FOR i = 1 TO 8
DEF SEG = VARSEG(m1(0)): BLOAD "b" + LTRIM$(STR$(i)) + ".gfx", 0: DEF SEG
PUT (x, y), m1, PSET
ERASE m1
FOR j = 1 TO speed: NEXT
NEXT
NEXT z
speed = speed - (speed \ 1.5)
DEF SEG = VARSEG(mallard(0)): BLOAD "mallard.gfx", 0: DEF SEG
x2 = 60
y2 = 119
DO
FOR i = 1 TO 8
IF y2 >= 80 THEN y2 = y2 - 1: ELSE EXIT DO
PUT (x2, y2), mallard, PSET
DEF SEG = VARSEG(m1(0)): BLOAD "b" + LTRIM$(STR$(i)) + ".gfx", 0: DEF SEG
PUT (x, y), m1, PSET
ERASE m1
FOR j = 1 TO speed: NEXT
NEXT
LOOP
speed = speed - (speed \ 2)
a = 101
DO
FOR i = 1 TO 8
DEF SEG = VARSEG(m1(0)): BLOAD "b" + LTRIM$(STR$(i)) + ".gfx", 0: DEF SEG
PUT (x, y), m1, PSET
ERASE m1
FOR j = 1 TO speed: NEXT
IF s < 60 THEN
s = s + 1: PALETTE s + 100, s: s = s + 1: PALETTE s + 100, s: s = s + 1: PALETTE s + 100, s
s = s + 1: PALETTE s + 100, s: s = s + 1: PALETTE s + 100, s: s = s + 1: PALETTE s + 100, s
END IF
IF s = 60 THEN
IF ajsaikj = 0 THEN speed = speed * 2: ajsaikj = 1
a = a + .25
IF a >= 160 THEN EXIT DO
COLOR INT(a)
LOCATE 18, 15
PRINT "presents"
END IF
NEXT
LOOP
i = 0
DO WHILE INKEY$ = ""
i = i + 1: IF i = 9 THEN i = 1
DEF SEG = VARSEG(m1(0)): BLOAD "b" + LTRIM$(STR$(i)) + ".gfx", 0: DEF SEG
PUT (x, y), m1, PSET
ERASE m1
FOR j = 1 TO speed: NEXT
LOOP
DEFINT A-Z
DEFSNG A-Z
SUB BSAVEExample
GifLoad "mallard.gif"
DIM mallard(10000)
GET (0, 0)-(200, 80), mallard
DEF SEG = VARSEG(mallard(0))
BSAVE "mallard.gfx", 0, 10000
DEF SEG
END SUB
SUB GifLoad (a$)
DEFINT A-Z
DIM Prefix(4095), Suffix(4095), OutStack(4095), shiftout%(8)
DIM Ybase AS LONG, powersof2(11) AS LONG, WorkCode AS LONG
FOR a% = 0 TO 7: shiftout%(8 - a%) = 2 ^ a%: NEXT a%
FOR a% = 0 TO 11: powersof2(a%) = 2 ^ a%: NEXT a%
IF a$ = "" THEN INPUT "GIF file"; a$: IF a$ = "" THEN END
IF INSTR(a$, ".") = 0 THEN a$ = a$ + ".gif"
OPEN a$ FOR BINARY AS #1
a$ = " ": GET #1, , a$
IF a$ <> "GIF87a" THEN PRINT "Not a GIF87a file.": END
GET #1, , TotalX: GET #1, , TotalY: GOSUB GetByte
NumColors = 2 ^ ((a% AND 7) + 1): NoPalette = (a% AND 128) = 0
GOSUB GetByte: Background = a%
GOSUB GetByte: IF a% <> 0 THEN PRINT "Bad screen descriptor.": END
IF NoPalette = 0 THEN P$ = SPACE$(NumColors * 3): GET #1, , P$
DO
GOSUB GetByte
IF a% = 44 THEN
EXIT DO
ELSEIF a% <> 33 THEN
PRINT "Unknown extension type.": END
END IF
GOSUB GetByte
DO: GOSUB GetByte: a$ = SPACE$(a%): GET #1, , a$: LOOP UNTIL a% = 0
LOOP
GET #1, , XStart: GET #1, , YStart: GET #1, , XLength: GET #1, , YLength
XEnd = XStart + XLength: YEnd = YStart + YLength: GOSUB GetByte
IF a% AND 128 THEN PRINT "Can't handle local colormaps.": END
Interlaced = a% AND 64: PassNumber = 0: PassStep = 8
GOSUB GetByte
ClearCode = 2 ^ a%
EOSCode = ClearCode + 1
FirstCode = ClearCode + 2: NextCode = FirstCode
StartCodeSize = a% + 1: CodeSize = StartCodeSize
StartMaxCode = 2 ^ (a% + 1) - 1: MaxCode = StartMaxCode
BitsIn = 0: BlockSize = 0: BlockPointer = 1
x% = XStart: y% = YStart: Ybase = y% * 320&
SCREEN 13: DEF SEG = &HA000
IF NoPalette = 0 THEN
OUT &H3C7, 0: OUT &H3C8, 0
FOR a% = 1 TO NumColors * 3: OUT &H3C9, ASC(MID$(P$, a%, 1)) \ 4: NEXT a%
END IF
LINE (0, 0)-(319, 199), Background, BF
DO
GOSUB GetCode
IF Code <> EOSCode THEN
IF Code = ClearCode THEN
NextCode = FirstCode
CodeSize = StartCodeSize
MaxCode = StartMaxCode
GOSUB GetCode
CurCode = Code: LastCode = Code: LastPixel = Code
IF x% < 320 THEN POKE x% + Ybase, LastPixel
x% = x% + 1: IF x% = XEnd THEN GOSUB NextScanLine
ELSE
CurCode = Code: StackPointer = 0
IF Code > NextCode THEN EXIT DO
IF Code = NextCode THEN
CurCode = LastCode
OutStack(StackPointer) = LastPixel
StackPointer = StackPointer + 1
END IF
DO WHILE CurCode >= FirstCode
OutStack(StackPointer) = Suffix(CurCode)
StackPointer = StackPointer + 1
CurCode = Prefix(CurCode)
LOOP
LastPixel = CurCode
IF x% < 320 THEN POKE x% + Ybase, LastPixel
x% = x% + 1: IF x% = XEnd THEN GOSUB NextScanLine
FOR a% = StackPointer - 1 TO 0 STEP -1
IF x% < 320 THEN POKE x% + Ybase, OutStack(a%)
x% = x% + 1: IF x% = XEnd THEN GOSUB NextScanLine
NEXT a%
IF NextCode < 4096 THEN
Prefix(NextCode) = LastCode
Suffix(NextCode) = LastPixel
NextCode = NextCode + 1
IF NextCode > MaxCode AND CodeSize < 12 THEN
CodeSize = CodeSize + 1
MaxCode = MaxCode * 2 + 1
END IF
END IF
LastCode = Code
END IF
END IF
LOOP UNTIL DoneFlag OR Code = EOSCode
'BEEP
'A$ = INPUT$(1)
EXIT SUB
GetByte: a$ = " ": GET #1, , a$: a% = ASC(a$): RETURN
NextScanLine:
IF Interlaced THEN
y% = y% + PassStep
IF y% >= YEnd THEN
PassNumber = PassNumber + 1
SELECT CASE PassNumber
CASE 1: y% = 4: PassStep = 8
CASE 2: y% = 2: PassStep = 4
CASE 3: y% = 1: PassStep = 2
END SELECT
END IF
ELSE
y% = y% + 1
END IF
x% = XStart: Ybase = y% * 320&: DoneFlag = y% > 199
RETURN
GetCode:
IF BitsIn = 0 THEN GOSUB ReadBufferedByte: LastChar = a%: BitsIn = 8
WorkCode = LastChar \ shiftout%(BitsIn)
DO WHILE CodeSize > BitsIn
GOSUB ReadBufferedByte: LastChar = a%
WorkCode = WorkCode OR LastChar * powersof2(BitsIn)
BitsIn = BitsIn + 8
LOOP
BitsIn = BitsIn - CodeSize
Code = WorkCode AND MaxCode
RETURN
ReadBufferedByte:
IF BlockPointer > BlockSize THEN
GOSUB GetByte: BlockSize = a%
a$ = SPACE$(BlockSize): GET #1, , a$
BlockPointer = 1
END IF
a% = ASC(MID$(a$, BlockPointer, 1)): BlockPointer = BlockPointer + 1
RETURN
END SUB