home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Hack-Phreak Scene Programs
/
cleanhpvac.zip
/
cleanhpvac
/
ANIVGA.ZIP
/
ANIVGA.DOC
< prev
next >
Wrap
Text File
|
1992-08-28
|
173KB
|
3,558 lines
░░░░░░▄ ░░░▄ ░░▄ ░░░░░░▄ ░░▄ ░░▄ ░░░░▄ ░░░░░░▄
░░█▀░░█ ░░░░▄░░█ ░░█▀▀ ░░█ ░░█ ░░█▀▀▀ ░░█▀░░█
░░░░░░█ ░░█░░░░█ ░░█ ░░░░░░▄ ░░█ ░░█ ░░█░░░▄ ░░░░░░█
░░█▀░░█ ░░█ ░░░█ ░░█ ▀▀▀▀▀▀ ░█ ░█▀ ░░█ ░░█ ░░█▀░░█
░░█ ░░█ ░░█ ░░█ ░░░░░░▄ ░░█▀ ░░░░█▀ ░░█ ░░█
▀▀ ▀▀ ▀▀ ▀▀ ▀▀▀▀▀▀ ▀▀ ▀▀▀▀ ▀▀ ▀▀
░░░░░▄ ░░░░░░▄ ░░░░▄
░░█▀░░▄ ░░█▀░░█ ░░█▀░░▄
░░█ ░░█ ░░█ ░░█ ░░█ ▀▀
░░█ ░░█ ░░█ ░░█ ░░█ ░░▄
░░▄ ░░░░░█▀ ░░░░░░█ ░░░░█▀
▀▀ ▀▀▀▀▀ ▀▀▀▀▀▀ ▀▀▀▀
(English documentation)
┌─────────────────────────────────────────────┐
│ ANIVGA │
│ a sprite-unit for TurboPascal V6.0 │
│ by Kai Rohrbacher │
│ Version 1.1 │
└─────────────────────────────────────────────┘
Purpose : Animation of sprites on a VGA's 320x200x256 mode and
TurboPascal V6.0
Author : Kai Rohrbacher
Germany
Internet: S_ROHRBACHER@IRAVCL.IRA.UKA.DE
Bitnet : UKB8@DKAUNI2.BITNET
FIDO : 2:241/7521.7
Language: TurboPascal V6.0
Date : September 1992
---------------------------------------------------------------------
Always remember: "I know my English spelling is bad, but if I used my
own language you probably couldn't read it at all."
-- Nico de Vries
---------------------------------------------------------------------
0. Table of contents
────────────────────
1. Prélude: Legal Notices
2. What is ANIVGA?
3. Features and Restrictions of ANIVGA
4. "HELLO WORLD" - A First Example
5. How ANIVGA works
6. Tips, tricks and techniques
7. Credits
8. ANIVGA Reference Manual
1. Prélude: Legal Notices
─────────────────────────
Okay, the boring stuff first...
The author hereby disclaims all warranties relating to this software,
whether expressed or implied, including without limitation any implied
warranties of merchantability or fitness for a particular purpose.
I will not be liable for any special, incidental, consequential, indirect
or similar damages due to loss of data/damage to hardware or any other
reason, even if I have been advised of the possibility of such damages.
This programming toolkit is released as "freeware" by the author.
It is however copyrighted and all rights and ownership are kept with the
author. You may use it, copy it and give it to everybody as long as no
modifications are made -- but don't try to sell it (or part of it)!
Nevertheless, all programs you realize with this software package may be
distributed/sold freely - the only thing I ask you for is to mention the use
of this toolkit in your program and to send me a copy of your program, al-
though a small donation would be *much* appreciated, for the reasons told in
the file README.2ND (which I hope, you have read thoroughly!).
2. What is ANIVGA?
──────────────────
ANIVGA is a powerful toolkit for the animation of sprites on any IBM (or com-
patible) with a VGA card installed.
It consists of one (big) TurboPascal V6.0-unit to be used by your applications
and some utilities to simplify its use:
README.1ST - as it tells you: a text file you should read first
README.2ND - yes, *exactly* what you are thinking right now...
ANIVGA.DOC - the manual, you are reading it!
FAQ.TXT - some frequently asked questions
ANIVGA.PAS - the source code of the animation unit
MAKES.EXE - a spritemaker program (requires a mouse and a Super-VGA-card!)
GRAB.EXE - a TSR-program to grab sprites from other graphics (req. mouse)
UNLIB.EXE - a utility to break apart a library of sprites back into
its individual sprite files
DUMP_SPR.EXE - a "sprite dumper" which disassembles a (binary) sprite file
into a (recompilable) ASCII-text
EXAMPLE?.PAS - a few _simple_ demo programs
*.COD, *.PAL - some sprites and palettes, which belong to the demo programs
SVGA256.BGI - a BGI driver, only used for MAKES.EXE
TRANSLAT.EXE - a utility to generate a version of ANIVGA.PAS with English
comments
ANIVGA.DIC - dictionary needed for the translation
*.* - documentation, sources, ...
-> Copy these files into your TurboPascal-directory and compile ANIVGA.PAS to
implement ANIVGA on your system - that's all.
3. Features and Restrictions of ANIVGA
──────────────────────────────────────
Some of ANIVGA's features are:
- flickerfree animation by a "page-flipping" algorithm and using the
display enable signal
- sprite movement in any increments you want
- arbitrary background image for the animation
- full use of the VGA's 256-color mode
- several sprite display methods available:
- sprites can be written normally (covering underlying figures)
- sprites can be declared to be transparent with regard to the background
or other sprites pixel by pixel
- sprites can change their color depending on the underlying background
image (-> shadow function)
- display methods can be different for each sprite
- pixel precise hit-detection routine built in
- correct clipping of sprites at the screen boundaries
- up to 32767 different sprites
- up to 500 sprites may be simultaneously active
- maximal size of each sprite = 64k
- maximal size of all loaded sprites only restricted by available memory
- works with virtual coordinates in the range -16000..+16000
- thus simple creation of horizontal/vertical "scrolling" games
- scrolling background image, too
- several supporting routines to: drawing lines (with built in clipping-
algorithm), points and graphic-text (incl. clipping), automatic heap
management for loading of sprites, sprite libraries, background images,
processor-speed adjustment, palette handling,...
What ANIVGA does _not_ support:
- EMS or XMS memory (to slow)
- resolutions other than 320x200x256 (compatibility question)
4. "HELLO WORLD" - A First Example
──────────────────────────────────
ANIVGA uses a non-standard 320x200x256 graphic mode, different from the BIOS-
mode $13, but there should be no problems with all truly compatible VGA cards.
To see if ANIVGA is compatible with your system and to get a first impression
of its ease of use, compile the following _simple_ program (you can find it on
disk as file "EXAMPLE1.PAS"):
(Remember to copy and compile ANIVGA.PAS in your TurboPascal-Unit-directory
first!)
PROGRAM Example1;
USES ANIVGA,CRT;
CONST LoadNumber=42; {why not 42? - A hello to all Douglas Adam fans!}
SpriteName='FLOWER.COD'; {Path and name of the sprite to load}
Sprite1=0;
Sprite2=5;
ch:CHAR=#0; {sets ch to that value everytime the program starts}
VAR collide:BOOLEAN;
BEGIN
IF loadSprite(SpriteName,LoadNumber)=0
THEN BEGIN
CloseRoutines;
WRITELN('Error: '+GetErrorMessage); halt(1)
END;
InitGraph;
Color:=66;
BackgroundLine(0,0,XMAX,0); BackgroundLine(XMAX,0,XMAX,YMAX);
BackgroundLine(XMAX,YMAX,0,YMAX); BackgroundLine(0,YMAX,0,0);
BackgroundOutTextXY(100,70,'Hello world!');
SpriteN[Sprite1]:=LoadNumber;
SpriteX[Sprite1]:=0; SpriteY[Sprite1]:=0;
SpriteN[Sprite2]:=LoadNumber;
SpriteX[Sprite2]:=XMAX SHR 1; SpriteY[Sprite2]:=YMAX SHR 1;
Animate;
REPEAT
collide:=Hitdetect(Sprite1,Sprite2);
if collide THEN BEGIN Sound(1000); Delay(5); NoSound END;
if KeyPressed
THEN BEGIN
WHILE KeyPressed do ch:=UpCase(ReadKey);
CASE ch OF
'I':DEC(SpriteY[0]);
'J':DEC(SpriteX[0]);
'K':INC(SpriteX[0]);
'M':INC(SpriteY[0]);
'E':dec(StartVirtualY,10); {change position of whole scene with}
'S':dec(StartVirtualX,10); {E,S,D,X}
'D':inc(StartVirtualX,10);
'X':inc(StartVirtualY,10);
END;
IF POS(ch,'IJKMESDX')>0 THEN Animate;
END;
UNTIL (ch='Q') OR (ch=#27);
CloseRoutines;
END.
(Don't worry if you do not understand the whole program at once - it should
only give you a first impression of ANIVGA's capabilities)
If you run this program (make sure that the sprite file FLOWER.COD can be
found by the program!) you should see a graphic consisting of two flowers, a
rectangle showing the screen boundaries and the words "Hello world" near the
middle of the screen.
You can move the top left flower by using the keys "I","J","K","M".
If you hit the other flower with the first one, the program will beep.
Try out what happens if you move across the two words in the middle:
obviously, the two leafs of the sprite behave somehow different: the black
parts of left leaf are "transparent" in that the writing shines through it,
while the black parts of the right leaf are "covering black".
But the writing (which is written in the background image) won't be destroyed.
As soon as you leave them, the words will be alright again.
Move the sprite to the very left screen boundary - and move it even more to
the left: you'll get the impression that it moves off the screen until it is
totally offscreen.
Hmmmm - how do we get it back? Sure, "K" will do, but press "S" instead: this
will "pan" the whole screen 10 pixels to the left (think of that as if you
could control an imaginary camera to slide to the left), "X" pans into the
other direction (note the restriction of the program to non-scrolling back-
ground at this point: the big rectangle and the words "Hello world" won't
move because they are part of the so-called "static" background image).
("E" and "X" will behave similarily, but for the y-direction.)
Now -using the "I","J","K" and "M" keys- bring back your sprite to the 2nd one
and let them collide. Press "A" a few times to scroll them both offscreen.
As you'll notice, the program will not stop beeping: it indicates that the two
sprites collide, even if they are not visible to you!
Okay, that should be enough for a first impression, so hit "Q" (or ESC) to
quit the program, if you've finished wondering... :-)
There are a few more EXAMPLE programs included. They share a common thing:
they are as small and simple as possible, because they shall only show you
some basic techniques!
Run EXAMPLE2.PAS for a demonstration of "scrolling" background; the program is
much the same as EXAMPLE1, but uses four different "tiles" to build the back-
ground image. As before, you can use "I,J,K,M" to move your sprite along, but
this time, you may scroll the whole scene (incl. the background!) with the
"E,S,D,X" keys, too ("Q" quits, as before).
EXAMPLE3.PAS shows (an extremely) simple use of the "Display_SHADOW" mode to
display a graphical object and demonstrates the difference to mode
"Display_SHADOWEXACT": first, a sprite is used for its own shadow zone, simply
by redrawing it with a little horizontal and vertical offset, using mode
"Display_SHADOW".
Although this is a nice trick with many sprites (you don't have to design
extra shadow sprites this way), it doesn't always work: note that there is one
area in the flower which differs from what we would expect as shadow: this is
because ANIVGA assumes that everything between the left- and rightmost point
of a sprite belongs to the sprite's interior and will be drawn accordingly.
To circumvent this, one would have to draw one (or even several) especially
designed "shadow zone" sprites for the flower, or use Display_SHADOWEXACT
instead: just press the space bar to toggle to that mode.
Pressing "P" draws 1000 randomly distributed points so you can better see the
shadowing effect for single points.
Finally, "C" copies part of the screen into memory (with GetImage() ) and
pastes it somewhere else (with PutImage() ) while clipping off at the screen
boundaries and is merely there to give a short demonstration of how to use
these routines.
EXAMPLE4.PAS is an example how to use "sprite cycles": there are six images in
the sprite (library) file HANTEL.LIB which become "glued" together to form one
sprite cycle.
App. one hundred copies of this sprite are then animated on the screen with
maximum animation speed and again, you can scroll the whole screen area with
the keys "E","S","D","X". When you do, you will note that as more and more of
the sprites gets scrolled offscreen, the remaining sprites will rotate faster.
Pressing the space bar will toggle between fastest animation (no time limit)
and an animation rate of 200ms per frame.
You can play around with this value to find out an "optimal" time for your PC
and this program:
very small: program will show the same symptoms as mentioned above (being
faster for every sprite offscreen)
.
.
.
very big : program will slow down even when all sprites are onscreen
Somewhere between lies a value where the animation doesn't get slowed down
when all sprites are onscreen (=max. work for ANIVGA), but stays at the same
speed for all other cases (=less work for ANIVGA).
EXAMPLE5.PAS and EXAMPLE6.PAS are two programs to demonstrate how you can
build a background image by using tiles: a 2x2 (8x4 respectively) COD-file
will be loaded and pasted repetively into the virtual screen.
EXAMPLE6.PAS also shows how you may tie sprites and text output to an absolute
screen position in scrolling background modes!
EXAMPLE7.PAS shows you the same old demo image of the former examples, but
this time using another palette, loaded from disk.
EXAMPLE8.PAS shows you all opening sequences available by the routine
"FadeIn()". Press a key A..Y (without Q) to view a method, ESC will quit.
5. How ANIVGA works
───────────────────
(It would be _impossible_ trying to cope every detail of ANIVGA, but I'm sure
you will get the basic ideas of ANIVGA very soon.)
As already mentioned, the program uses a "tweaked" VGA-graphic mode: the VGA
is programmed in a way to give 4 graphic pages at a resolution of 320x200
pixels in 256 colors numbered 0..3.
Page 0 and 1 are used for the display, page 2 holds the "normal" background
image and page 3 can contain so-called "tiles" which can be used to build a
huge background image in "scrolling" background mode.
The basic idea of the "page flipping" scheme used is that: do everything (era-
sing the old graphic page, draw sprites/lines/pixels/text) on a graphic page
invisible to the user while showing him a completed page on the screen.
Then, if finished, "flip" the page, thus making the new, completed page
visible and the old page to the invisible one. Now start creating the next
image on this new invisible page - and so on.
"Erasing" the old image means: overdraw it completely with the background
image stored in page 2 (or 3), so one could write in pseudo code:
...
REPEAT
show page 0 to user;
fill (invisible) page 1 with contents of page 2;
draw new sprites and all other stuff on page 1;
show page 1 to user;
fill (invisible) page 0 with contents of page 2;
draw new sprites and all other stuff on page 0;
UNTIL DOOMSDAY
...
You as the programmer doesn't have to think much about this mechanism, the
routines keep track of the page flipping automatically: the global variable
"PAGE" always holds the number of the page which is invisible (and thus:
the page to be drawn on). Therefore, we say that PAGE holds the "actual page"
number and 1-PAGE is the page visible to the user.
Most of the procedures and functions of the animation package adjust them-
selves to the appropriate page; there are only a few situations where you have
to be aware of this mechanism, mostly when drawing pixels or to create special
effects.
The whole package is "table driven". That means, the interface to the user
consists of some tables in which you specify your sprites to be drawn:
You store into this tables which sprites to draw ("SpriteN[]") and their
coordinates (in "SpriteX[]" and "SpriteY[]").
After this, a call of the main routine "Animate()" gives back control to the
animation routines, which update the graphic screen accordingly:
...
REPEAT
update SpriteN[]-table:
deactivate sprite i by storing a "0" into SpriteN[i] or
activate a sprite k by storing k in an unused SpriteN[]-entry or
let all the other SpriteN[]-entries as they were last cycle
FOR ALL SpriteN[i]<>0 DO
IF SpriteN[i] should change its coordinates
THEN update (SpriteX[i],SpriteY[i]) accordingly
call Animate() to draw image and display it
UNTIL end-of-computer-life
...
You should notice that there are two kinds of "sprite numbers" which should
not be mixed up: one is a spriteLOAD number and represents a handle to the
(physical) sprite data, while the other (normally termed "sprite number") is
a logical number to address this sprite data.
In the pseudo code given above, "k" is the spriteLOAD number (it is a number
given at load time) and the index "i" in SpriteN[i] is the sprite number.
Note that "k" is a unique value: you can think of it as a NAME of the sprite
data loaded (e.g. you could name the FLOWER.COD - data as "123" when loading
it: there can't be another sprite with the same LOAD-number). On the other
hand, there could be a hundred flowers on the screen: just choose hundred
different sprite-table entries (=sprite numbers), e.g. SpriteN[100]..
SpriteN[199] and store "123" in each of them!
Whenever you are unsure if you (or I) are speaking of a "sprite number" or a
"spriteLOAD number", remember that:
■ A sprite number can hold values in the range 0..NMAX and is an index of
the tables SpriteX[], SpriteY[] and SpriteN[].
■ A spriteLOAD number can hold values between 0..LoadMax and is assigned
as a "name" to the sprites' physical loaded data; a "0" as load number is
reserved for "inactivate sprite" (in other words, it is the *content* of
an entry in SpriteN[])
Example: SpriteN[42]:=0
│ └ spriteLOAD number
└ sprite number
The world ANIVGA knows is 32000 pixels wide and high, numbered -16000..+16000
on each axis. Because your graphic screen consists of only 320 by 200 points,
(ranging from 0..XMAX and 0..YMAX in the x- and y-axis, respectively; (0,0) is
the upper left corner, (XMAX,YMAX) the lower right one) you can only see a
small part of this world, but ANIVGA does not distinguish between the visible
and invisible parts of the world. If, for example, two sprites collide, the
routine "HitDetect()" will find out, even if this collision occurs offscreen.
Thus you can think of your graphic display being a "camera" to the real world:
your actions can take place everythere in this virtual world, but you see only
the part displayed by your camera; if you wish to see another part of your
world, you have to move this imaginary camera to that place.
In ANIVGA, you can do this by changing the values "StartVirtualX" and
"StartVirtualY" which hold the upper left corner of the visual window. As an
example, let (StartVirtualX,StartVirtualY) be (1000,500): then on your screen
you will see the part of the world which ranges from coordinates (1000..1319)
and (500..699) in X- and Y-directions, respectively.
6. Tips, tricks and techniques
──────────────────────────────
There would be a lot of things to say and most of them will be mentioned in
the following "Reference Manual". Nevertheless, it seems reasonable to repeat
them in a more concentrated form here, although this happens to make this
chapter a real topsyturvydom...
a) The ERROR-concept: if an error occurs in one of ANIVGA's routines, the
global variable ERROR will be set accordingly. This gives you the freedom
either to check this variable each time you called a routine - or ignore it
for improved speed.
As a rule of thumb, you should always check this variable while your pro-
gram is still in the testing phase - and "comment out" these sections when
you are through with debugging. (Conditional defines are great for that
job!)
Note that there are some routines that do not set ERROR at all (like
Screen, GetPixel, PageGetPixel, PagePutPixel), either because in some
special cases, "nice" tricks can be played with "faulty" parameters or
because of severe speed improvements! For example, if you are going to read
a 5000 pixel area from the screen with PageGetPixel(), it would be crazy to
check 5000 times whether the "page" given to read from is valid or not.
b) Pixel-drawing routines: basically spoken, there are three sorts of graphic
data objects in ANIVGA: sprites, pixels and background images.
Because of ANIVGA's working scheme, all routines handling pixels (PutPixel,
PagePutPixel, Line, PutImage,...) must be used in a special form:
- If you use them to "draw" into the background page, this can only be done
when using background mode STATIC (because in mode SCROLLING, the back-
ground is stored in a compressed "tiling" format one can't access
directly).
- Drawing into the background page in mode STATIC is fine (that's the main
advantage of this mode compared with mode SCROLLING), and the best time
to do it is _before_ calling Animate(), because changes to the background
image will then be visible with the call to this routine.
- Drawing "on the monitor screen" will be visible exactly for one animation
cycle, that is: until the next call to Animate(). For this reason, you
must do this changes _after_ calling Animate() and at the _visible_ page
1-PAGE (not the _actual_ page PAGE itself).
It is not that difficult as it may sound at first glance; for example:
...
REPEAT
read_user_inputs; compute_necessary_actions;
do_all_changes_to_the_background_image;
do_all_changes_to_the_sprites;
Animate();
do_all_changes_to_the_visible_screen;{e.g.: Line(0,0,XMAX,YMAX,1-PAGE)}
UNTIL user_wants_to_end_application
...
This way, after having called Animate(), the changes to the background
(and your sprites) will be visible (because Animate() has generated an
appropriate picture) and your changes to this image with the pixel-
drawing routines will be visible "at once".
That image will then stay visible until the next call to Animate().
(Simply spoken, you let Animate() generate and display a picture and then
do some changes to the picture while it is diplayed)
- Because of unavoidable memory restrictions, ANIVGA can't store pixels
drawn offscreen: if ANIVGA sees that points/lines lie outside the visible
screen, it just does nothing at all; in other words, you can't draw a
line outside the screen and "scroll it in" five minutes later! (You would
have to define the line as a sprite instead, because sprites are the only
objects stored independently).
c) Coordinates: Throughout all routines, ANIVGA works with _virtual_ coordi-
nates (that is values in the range xε[-16000..+16000], yε[-16000..+16000]),
but sometimes you will have to address _absolute_ coordinates (in the range
xε[0..XMAX], yε[0..YMAX]), so you have to transform virtual coordinates
into absolute coordinates (or vice versa), which is _very_ easy:
virtual coordinates -> absolute coordinates:
Xabsolute := Xvirtual - StartVirtualX
Yabsolute := Yvirtual - StartVirtualY
absolute coordinates -> virtual coordinates:
Xvirtual := Xabsolute + StartVirtualX
Yvirtual := Yabsolute + StartVirtualY
d) Background / valid pages: Many routines expect a graphic page number as
parameter. As mentioned under b), BACKGNDPAGE is valid only when you use
background mode STATIC. Nevertheless, you could draw to this page even when
you are using background mode SCROLLING without getting an error
"Err_InvalidPageNumber" (although you are _strongly_ discouraged to do
so)!
That's because you can play some tricks on ANIVGA this way, provided that
you do know _exactly_ what you (and ANIVGA) are doing, but this "feature"
will probably be cut off in future versions of this program.
(Note that this doesn't mean that you can't switch between STATIC and
SCROLLING backgrounds during runtime! - It only says that you can't use
the two background pages _in parallel_ (=at the same time)!)
e) Display objects at the same abolute screen position:
Let us assume you want to display a score at the upper right corner of the
screen; that's not hard when using STATIC background: just define your
score as a sprite and choose an appropriate coordinate pair.
In SCROLLING mode, your score would scroll away, too, so you must tie it to
absolute screen coordinates, as said in c), but there is a simple rule
which can be derived from the equation
absolute_coordinate := virtual_coordinate - StartVirtual_value
To ensure that the absolute (=screen) coordinate stays the same, you have
to balance out changes done to the StartVirtual-variables like this: when-
ever you increase/decrease StartVirtualX|Y by some amount delta, increase/
decrease your score-coordinates by the same amount delta!
(This results in: new_coord := virtual_coord±delta - (StartVirtual±delta)
= virtual_coord - StartVirtual = old_coord as wanted)
f) Displaying scores: another way to display a score without defining it as a
sprite would be to simply draw it to the screen with the pixeldrawing rou-
tines or OutTextXY():
■ draw it to the visible page (1-PAGE) each time after having called
ANIMATE()
■ draw it to the background page BACKGNDPAGE
The last method is applicable only in background mode STATIC and you have
to restore the background image in the used area manually, but has the ad-
vantage that you must redraw your score only when it really changed (in-
stead of every animation cycle as with the first method). One way to
accomplish that would be to use the GetImage() and PutImage() routines:
...
build background image;
use GetImage() to get a copy of the background area which will be overdrawn
by the score;
...
main_loop:
IF new score has to be displayed
THEN BEGIN
use PutImage() to restore old background area underneath the score
use OutTextXY() to write new score into the background image
END
...
g) Speed: It is hard to predict the speed of animations, because that is
merely determined by the speed of your VGA card, not your computer's CPU
clock rate! E.g., a program runs faster on my old AT (8MHz) than on a fast
(25 MHz) 80386 machine - only because of a better VGA card installed in
the AT!
Stated otherwise, if you use a computer with "enough" CPU-power, you won't
have to think much about "should I use STATIC background instead of SCROL-
LING for improved speed?", because it won't matter much anyway!
The break even point, where the VGA-card's bottle neck becomes the limiting
factor depends largely on your application (and your VGA-card, of course),
but as a rule of thumb, clock speeds faster than 12MHz won't improve your
program speeds *linearly* any further:
animation ^ ______
speed │ ___----
│ /
│ /
│/
┼─────┬───────────> clock rate
break-
even point
Note that your programs will still profit from faster CPU's, but that is
due to faster computation of all routines not limited by accessing the
video RAM; even on the fastest clones, the IBM-bus-clock-rate is not faster
than 10MHz -- and this limits accessing the VGA card: sad, but true...
h) DMA access: Quite a long time, I tried to speed up animation rates by using
the DMA-chip in parallel to the CPU: while the CPU is running your program,
the DMA should move around memory.
Unfortunately, I had to find out that most computers don't like DMA memory-
to-memory transfers at all and those who do don't work when addresses used
reference the video RAM area. One of you (TNX Mike!) meant that's due to
the fact that most VGA cards do not decode the necessary DMA signals.
[comment: @!%*!@$ ]
i) Speedup things: Naturally, STATIC background is faster than SCROLLING
backgrounds, but you can speed up SCROLLING backgrounds, too: make sure
that StartVirtualX always is a multiple of 4 (that is, StartVirtualX
MOD 4 = 0), because then, ANIVGA can (and will) use the VGA's write mode 1
which is a lot faster than normal write mode 0.
Another idea is to shrink NMAX: if you don't need more than 100 sprites
(say), then change that constant and recompile ANIVGA!
j) GRAB: If GRAB won't pop up, then save the picture to disk (it's wise to do
that anyway), run a graphic viewer to merely display the picture and
capture then.
7. Credits
──────────
Honour to whom honour is due! I would like to thank some people on this way:
- Ken Pottebaum for his TSR-unit TSRUNIT.ZIP, providing the routines necessary
to write the Grabsprite-Utility
- John Bridges for his SVGA256.BGI driver (out of his SuperVGA-driver package
SVGABGI3.ZIP) used in the sprite maker
(The above mentioned programs are available at the SIMTEL20-servers)
- Bernd Klawonn (?) for his principle of using table-driven graphics in the
first graphics toolkit I ever saw - long, long ago in the "good'ol-AppleII-
days" (~1985)
8. ANIVGA Reference Manual
──────────────────────────
This reference manual lists all routines, variables, constants and a lot of
informational stuff concerning ANIVGA in alphabetic order.
Don't get frightened about the amount of informations given; in normal appli-
cations you will need only a few of them!
(Start with looking at the example *.PAS files and play around with them
- you'll learn a whole lot more by first using them as templates than by
reading manuals!)
ABSOLUTE COORDINATES - information
──────────────────────────────────
See : coordinates
ActualColors - variable
───────────────────────
Function : Supplies the actually used palette
Declaration: VAR ActualColors:Palette;
Description: This variable holds the values of the actual graphic colors.
You can use it to change the palette, but must issue a call to
SetPalette() to make your changes visible.
E.g., to make color 5 to "mere green", you would code:
ActualColors[5].red :=0;
ActualColors[5].green:=63;
ActualColors[5].blue :=0;
SetPalette(ActualColors,TRUE); {or ...,FALSE}
Note : -Whenever you change palette values by using the routine
SetPalette(), ANIVGA reflects the changes in ActualColors, that
is, as long as you don't work around ANIVGA's SetPalette()-
routine by directly tempering with the VGA's palette registers,
ActualColors always holds the actual palette (so you won't need
GetPalette() )
See also : Palette, SetPalette, GetPalette
Animate - procedure
───────────────────
Function : Performs a complete animation cycle
Declaration: PROCEDURE Animate FAR;
Description: A call to Animate() clears the invisible graphic page by copying
the contents of the background image into the actual drawing
page (specified by variable PAGE).
Then all active sprites (SpriteN[i]<>0) in the visible window
(determined by StartVirtualX and StartVirtualY) are drawn in the
style and at the coordinates given by the user.
After that, the routine waits for the display enable signal to
reprogram the VGA adapter to flip the display pages, making the
completed image visible and changes PAGE to point to the new,
invisible graphic page.
Finally, the procedure looks how much time passed since the last
animation cycle and if this time is less than that set by
SetCycleTime(), the program waits accordingly.
Note : This procedure is the kernel routine which has to be called
everytime when you have set all data for a new animation frame.
See also : PAGE, SetCycleTime, StartVirtualX, StartVirtualY
ANIVGAVersion - constant
────────────────────────
Function : Holds version number of ANIVGA-unit
Declaration: CONST ANIVGAVersion=11;
Description: Starting with V1.1, all versions of ANIVGA will define this
constant, holding the version number of the unit.
Note : This constant is new with version 1.1; if for some case you need
a homogenous scheme for version 1.0, too, then you must add the
definition "ANIVGAVersion=10" to somewhere in the constant decla-
ration part in the interface section of ANIVGA V1.0 and recompile
that unit!
See also : -
BackGndPage - constant
──────────────────────
Function : Holds the page number of the backround page
Declaration: CONST BACKGNDPAGE=2;
Description: When using background mode STATIC, BackGndPage specifies the page
number of the background image for the animations to be used.
Note (!) : Use of this constant only makes sense when using background mode
STATIC!
See also : ScrollPage, Background
Background - information
────────────────────────
The term "background" specifies a graphic image in front of which all anima-
tions take place.
There are two sorts of background in ANIVGA: SCROLLING background and STATIC
background, which you choose with SetBackgroundMode().
As its name states, a STATIC background cannot be scrolled: it consists of a
320x200 pixels picture.
This background picture is stored in the graphic page numbered BACKGNDPAGE.
At the very start of every animation cycle, the routine Animate copies that
picture into the actual drawing page, thus erasing old stuff on that page and
building the basis for the new image.
As a normal bitmap picture, it is 320x200=64000 bytes in size. If you use the
GRAB-Utility or the WritePage()-Routine to save an image, a three byte header
is put ahead of the information, thus extending the size to 64003 bytes.
The second background sort is called SCROLLING: like ANIVGA's virtual coor-
dinates, you can define a huge background image and scroll over it.
Unfortunately, it is impossible to hold a complete background picture in
memory: you would need 32000*32000=1024000000 bytes RAM (!) to do that.
Instead, ANIVGA uses a "tiling" mechanism: tiles are small pictures (16x16
pixels) which can be combined freely to build the background image.
You can use up to 256 different tiles and "pin" them on an background area of
up to MaxTiles (=10000) tiles; everything outside of this background area will
be assigned to tile no. 0 automatically.
For example, let us assume that you use only scrolling in the y-coordinate
axis, 16 screens in total: thus, your x-coordinates reach from 0 to 319 and
your y-coordinates from 0..(16*200-1)=5119, which gives an area of 320*5120
=1638400 pixels.
This is equivalent to (320/16)*(5120/16)=20*320=6400 tiles (remember: each
tile consists of 16x16 pixels!).
So you would define the scroll range for the background area needed with
SetBackgroundScrollRange(0,0,319,5119) and start "painting" your background:
You could design up to 256 different tiles and use them to assemble your
background image (=those 6400 tiles).
Most often, only a few are needed, because the background image isn't that
dramatically different all over the place. For simplicity, let's assume that
you need only 20 different tiles, numbered 0..19 respectively in the following
order to build your background image:
(0,0) (319,0)
┌────────┬────────┬────────┐ ┌────────┬────────┬────────┐
│ │ │ │ │ │ │ │
│ 0 │ 1 │ 2 │ ... │ 13 │ 14 │ 15 │
│ │ │ │ │ │ │ │
├────────┼────────┼────────┤ ├────────┼────────┼────────┤
. . . . . .
. . . . . .
. . . . . .
├────────┼────────┼────────┤ ├────────┼────────┼────────┤
│ │ │ │ │ │ │ │
│ 0 │ 1 │ 2 │ ... │ 13 │ 14 │ 15 │
│ │ │ │ │ │ │ │
└────────┴────────┴────────┘ └────────┴────────┴────────┘
(0,5119) (319,5119)
Now all you have to do is to tell ANIVGA that layout with the PutTile command:
{assuming SetBackgroundScrollRange(0,0,319,5119) has been set}
number:=0;
y:=0; {better: y:=BackY1}
REPEAT (things would become easier if Pascal would know a STEP-command...)
x:=0; {better: x:=BackX1}
REPEAT
PutTile(x,y,number);
number:=(number+1) MOD 16;
inc(x,16);
UNTIL x>319; {better: x>BackX2}
inc(y,16);
UNTIL y>5119; {better: y>BackY2}
That's it! (It is better to use the (global defined) "Back..."-variables, set
by the former SetBackgroundScrollRange()-call, because ANIVGA has to adjust
values on multiples of 16, see SetBackgroundScrollRange()/Back?? for more
details).
So then, why should one use STATIC backgrounds after all when there is such a
powerful instrument like SCROLLING backgrounds?
There are two simple answers: speed and simplicity! - First, SCROLLING back-
grounds take a lot of work to compute, which slows down animations (unless you
have a fast machine, because then the VGA's memory access time becomes the
limiting factor). Second, it is easy to do some "tricks" on static back-
grounds:
draw a line in the static background page and >zap!< starting with the next
animation cycle, it will be visible for all times. Stated otherwise, when
using scrolling background, you cannot use drawings to the background image,
because it simply doesn't exist explicitly, you are restricted solely to
"tiles" and "sprites"! (On the other hand, you can play nice tricks on scrol-
ling background by changing single tiles...)
So consider carefully what mode you are going to use for your application!
See also : BACKGNDPAGE, BACKGNDADR, WritePage, LoadPage,
WriteBackgroundPage, LoadBackgroundPage, SetBackgroundMode,
LoadTile, Tile
BackgroundGetPixel - function
─────────────────────────────
Function : Reads a background pixel's color
Declaration: FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE; FAR;
Description: This routine will return the color value of the specified point
with virtual coordinates (x,y) in the background image.
If the corresponding absolute coordinates lie outside the screen,
zero (= black) will be returned.
Note : Use of this routine works only when using background mode STATIC!
It might look strange to use virtual coordinates then, although
the background is said to be static (= non-scrollable) and hence
restricted to absolute coordinates anyway, but it is often con-
venient to use an uniform notation and it is easy to convert co-
ordinates accordingly (see "coordinates" for more about that).
See also : coordinates, GetPixel, PageGetPixel
BackgroundLine - procedure
──────────────────────────
Function : Draws a line on the background page
Declaration: PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER); FAR;
Description: To draw a line on the background page (thus alterating the back-
ground), you can use this procedure. Like the similiar Line()-
routine, it uses virtual coordinates, too.
If necessary, the line will be clipped down to its visible part
(using a special Sutherland-Cohen algorithm).
Note : Use of this routine only makes sense when using background mode
STATIC!
See also : Line, coordinates
BackGroundMode - variable
─────────────────────────
Function : Holds the actual choosen background mode
Declaration: VAR BackgroundMode:BYTE;
Description: Using SetBackgroundMode(), you can select one of the possible
background modes STATIC or SCROLLING. BackGroundMode stores this
value.
Note (!) : Only read this value, never change it directly!
See also : Background, SetBackgroundMode
BackgroundOutTextXY - procedure
───────────────────────────────
Function : Writes a textstring to the background page BACKGNDPAGE
Declaration: PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING); FAR;
Description: This routine is exactly the same like OutTextXY() (see there), but
it writes the string into the background page (so it will be visi-
ble permanently).
Note : Use of the routine only makes sense if STATIC is used as
background mode. With SCROLLING backgrounds, use OutTextXY()
instead.
See also : GraphtextColor, GraphtextOrientation, GraphtextBackground,
OutTextXY, background
BackgroundPutPixel - procedure
──────────────────────────────
Function : Plots a point into the background page
Declaration: PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:BYTE); FAR;
Description: (x,y) specify the virtual coordinates of the point to be drawn in
color "color". If this point lies onscreen (i.e.: its _absolute_
coordinates are between (0,0)..(319,199)), it will be drawn on the
background page BACKGNDPAGE (and become visible starting with the
next animation cycle).
Note (!) : - Use of this routine makes sense only when using background mode
STATIC!
- This routine works with virtual coordinates! - Although this
seems silly at first glance (because in STATIC mode, background
coordinates are always restricted to (0,0)..(319,199)), it
appears to be handy in many situations. If you actually want to
address points absolute coordinates (a,b), you can call this
routine with coordinates (a+StartVirtualX,b+StartVirtualY)
instead.
- Because of ANIVGA's working scheme, you probably want to call
this routine _before_ calling Animate(), so that changes of the
point will be visible as soon as possible.
See also : PutPixel, PagePutPixel, background, coordinates, How ANIVGA works
BACKX1, BACKX2, BACKY1, BACKY2 - variables
──────────────────────────────────────────
Function : Hold the background image boundaries in background mode SCROLLING
Declaration: BackX1,BackY1,BackX2,BackY2:INTEGER;
Description: When background mode SCROLLING is to be used, you have to define
a scrolling area (with SetBackgroundScrollRange()). Due to inter-
nal management restrictions of ANIVGA, the boundaries of this area
must fall on coordinates which are multiples of 16 ("on a grid
with mesh 16").
If the values you supply don't fulfill this restriction, ANIVGA
adjusts them automatically to do so and stores them to these
variables for further use.
Note : The only reason these variables are visible to you are that it
could be necessary for you to notice adjustments ANIVGA did;
so: only read this values, never change them directly!
(Look at "background" for an example).
See also : background
CloseRoutines - procedure
─────────────────────────
Function : Terminates ANIVGA
Declaration: PROCEDURE CloseRoutines; FAR;
Description: Calling this routine switches back from ANIVGA's special graphic
mode into the graphic or text mode previously set.
Note : This should always be the last call to a routine of ANIVGA in your
programs.
See also : InitGraph
COLLISION-DETECTION, CONCAVE, CONVEX - information
──────────────────────────────────────────────────
A graphical figure can be classified by its outline into one of two groups,
called "concave" or "convex" figures.
To motivate this mathematical notion >eh, don't get frustrated...<, regard
your sprite only given by its "outmost" points, which connected together shape
the figures boundaries.
The figure is called "convex" :<=> every pair of arbitrarily choosen points
on this boundary build a line which is totally inside (or at least on the
boundary of) the figure:
┌──────┐ This rectangle is "convex", because whenever you choose two points
│ │ on its boundaries and connect them, the resulting line lies com-
└──────┘ pletely inside (or on the boundary) of the rectangle itself.
┌──────┐ On the other hand, this figure would be "concave", because if you
└─┐ ┌─┘ choose the top-right and bottom-right corner (say) and connect them,
┌─┘ └─┐ then the middle part of the resulting vertical line lies outside the
└──────┘ figure.
That is (in a very lax form) the _mathematical_ definition of these terms, but
ANIVGA completely deals with either horizontal or vertical lines, so that an
extension of these terms can be made:
A sprite is called "horizontal concave" ("vertical concave"), if a horizontal
(vertical) line connecting two points of the sprite's boundary can be found
so that parts of this line lies outside the sprite; if the sprite is not hori-
zontal (vertical concave), it is "horizontal convex" ("vertical convex").
In that sense, the second of the figures above is "vertical concave", but
"horizontal convex"!
(Notice that figures which are concave in the pure _mathematical_ sense are
sometimes treated as convex by this definition, as this cross:)
┌─┐ (If you use either a horizontal or vertical "scan line" sweeping
┌─┘ └─┐ throughout the cross, there will be never more than one part of
└─┐ ┌─┘ the "scan line" which belongs to the figure; you can use this
└─┘ principle as a second definition for horizontal/vertical convex)
This terminology comes in handy when describing some mechanisms of ANIVGA: a
sprite is drawn LINEwise. For this, every point between the leftmost and right-
most point of a sprite's line is considered to be an _inner_ point of the
sprite, thus ANIVGA assumes a horizontal convexity! If your sprite isn't, like
this one...
┌─────┐ ...and the points between the two "legs" of this sprite shall still
│ ┌─┐ │ be treated as "transparent" (assuming they have been defined with
│ │ │ │ color "black" (=0)), you must use display mode "Display_NORMAL",
│ │ │ │ because the "Display_FAST" mode would treat them as belonging to the
└─┘ └─┘ sprite itself and draw them as "covering" black.
(To state it otherwise: whenever your sprite is (at least) horizontal convex
and you don't need the feature of transparent parts inside the sprite, you
can use the "Display_FAST" mode without any loss of accuracy in the sprite
display)
Tip: the spritemaker program MAKES allows to display a sprite's horizontal
boundaries, which makes it easier for the beginner to decide about that
figure's convexity. But whenever you are unsure, you still can use mode
"Display_NORMAL" for drawing it.
---
Things get a bit more tough when deciding if two sprites collide or not (which
is an important task): in difference to many sprite toolkits, ANIVGA doesn't
use a "mask" approach, which makes sprites big and collision detection slow.
Instead, ANIVGA uses a sprite's outline to decide whether two sprites collide.
For that, it computes for every line (column) of the overlap region of the
sprites' surrounding rectangles, whether the sprites overlap horizontally
(vertically) and says "collision!" only if there are intersections in both
directions. In pseudo code:
IF smallest_box_around(sprite1) doesn't intersect smallest_box_around(sprite2)
THEN no_collision
ELSE BEGIN
compute the lines and columns for which the 2 sprite rectangles overlap
FOR every such line compare -with the help of the sprite boundaries- if
the corresponding lines overlap
FOR every such column do the same check
ONLY_IF there is an intersection in at least one line AND one column
THEN collision!
ELSE no_collision
END
If you think a byte (=8 bits...) about this algorithm, you'll see that it can
lead to misdetection, in that the algorithm says "collision!", although there
is none (but it still guarantees that if there _is_ a collision, the alg. will
detect it) as in the following example:
┌─────┐
└───┐ │
┌────────┐ │ │
│ ┌────┐ │ │ │
│ │ ┌─┐│ │ │ │ <─ In this line there is a "horizontal collision" (that is,
└─┘ │ │└─┘ │ │ the two sprites overlap in their horizontal dimension)
│ └────┘ │
└────────┘ ┌─ In this column there is a "vertical collision"
^───────┘
To state things without a proof here, such an (unavoidable) misdetection is
only possible, if at least one of the two sprites is neither horizontal nor
vertical convex!!!
Even then, it takes special constellations (as the one above) to produce such
an error, so that in praxis, it is very unlikely for such an error to occur.
Color - variable
────────────────
Function : Determines the actual drawing color
Declaration: VAR Color:BYTE;
Description: Various drawing routines use this global variable to determine
which color should be used.
Note : ANIVGA uses the standard color table of the 256-color mode $13.
See also : -
ColorTable - type
─────────────────
Function : Supply a data type for self-defined "Shadow Tables"
Declaration: TYPE ColorTable=ARRAY[0..255] OF BYTE;
Description: If you want to use a different color look-up-table for your
sprites in display mode Display_SHADOW or Display_SHADOWEXACT
than can be achieved with SetShadowTab(), you must build a table
like this.
Each entry gives the color which should be used to replace the
original color with that index, i.e.: if c is of type ColorTable
and c[5]=9, this means that every point of your sprite which is to
be drawn over a pixel with color 5 should replace that pixel with
color 9.
You can find an example how to activate such a "home-brew" table
at "ShadowTab".
Note : -
See also : ShadowTab, SetShadowTab, Display modes, Palette
COORDINATES - information
─────────────────────────
ANIVGA has to deal with two kinds of coordinates: "virtual" and "absolute" ones.
An absolute coordinate lies in the range 0..319, 0..199 for the x and y values,
respectively. It names a unique point on your graphic screen.
However, ANIVGA doesn't restrict animations to take place on the visible
graphic screen: its routines deal with coordinates in the range -16000..+16000
in each direction, called "virtual coordinates".
The picture you view while ANIVGA's routines are running is a window of that
virtual screen, 320 points wide and 200 points high.
Naturally, the graphic hardware only knows absolute coordinates and thus,
ANIVGA has to transform virtual in absolute coordinates. It does this with the
help of the two variables StartVirtualX and StartVirtualY which together speci-
fy the starting point of the upper left corner of your actual screen window;
e.g. if (StartVirtualX,StartVirtualY) was (1000,2000) then you would look at
the part of ANIVGA's world which consists of the 320x200 region with the coor-
dinates xε(1000..1319) and yε(2000..2199).
Note that there is one severe restriction, though: because it is absolutely
impossible to hold a complete "virtual" screen bitmap for ANIVGA's world in
memory (it would need app. 1GB RAM!), all drawing commands only take place on
the visible screen.
This means that you can't draw lines, points or any other objects which are
_not_ sprites outside the visible window that become visible, when you scroll
your window over to that part of the virtual screen. For example, if you draw
a point somewhere outside your visible window (say at (-10000,1234) while your
visible window starts at (500,900)) and pan to that region afterwards (by set-
ting (StartVirtualX,StartVirtualY)=(-10100,1200) or something like that), you
won't see that point: it is stored nowhere.
(The only way to circumvent this is to define the point as a sprite and set its
coordinates (SpriteX[],SpriteY[]) to (-10000,1234), because sprites are the
only objects which the system stores!).
More general:
Because there is _no_ complete virtual screen, all information drawn outside
the coordinate range visible at the moment will be lost and all information
read in from these "offscreen" pixel positions will be zero (= black).
For that reason it may seem strange for some routines that were restricted in
their use to the "real" (= absolute coordinate) screen region to use virtual
coordinates inspite (e.g.: GetImage, BackGroundGetPixel,...), but this was done
intentionally, because it leaves room for further improvements: if it should be
possible some day to store a complete virtual screen image, there will be no
changes necessary in ANIVGA's syntax.
Meanwhile, it is simple to transform absolute and virtual coordinates into each
other whenever necessary, using the following equivalence:
virtual X-coordinates - StartVirtualX = absolute X-coordinates
virtual Y-coordinates - StartVirtualY = absolute Y-coordinates
As a result: virtual coordinates lie in the range -16000..+16000, the start of
the visible part is defined in StartVirtualX and StartVirtualY and only sprites
can be "scrolled in" into the visible screen, while all other objects are
"lost".
DefaultColors - constant
────────────────────────
Function : Supplies the default RGB-colors of mode $13 to the user
Declaration: CONST DefaultColors:Palette=
(
(red: 0; green: 0; blue: 0),
[...stuff deleted...]
(red: 63; green: 63; blue: 63)
);
Description: ANIVGA and its accompanying utility programs are based on the
Bios' default color palette. That ain't necessary, though (and
you *can* set different palettes), but it makes things a bit
easier!
DefaultColors is a listing of these default colors.
Note : Consider the table as *read only*! When you use SetPalette(),
ANIVGA will not temper this table (thus you can use it to restore
the original palette values again).
See also : Palette, SetPalette, GetPalette
Display modes - information
───────────────────────────
ANIVGA is able to display a sprite in several "modes". This describes how the
sprite's data should be handled when drawing the sprite to the screen. Up to
now, there are four modes:
- Display_NORMAL
- Display_FAST
- Display_SHADOW
- Display_SHADOWEXACT
This mode is linked to a sprite's physical data by creation of the sprite with
the spritemaker program (and defaults to Display_NORMAL), but can be altered
once the sprite is loaded into memory with the procedure SetModeByte().
Note that the display mode information is part of the _physical_ sprites (that
is, the memory image of the bytes loaded at the beginning), not the _logical_
sprites (the "handles" in the SpriteN-array to this physical data). For that
reason, a change of the display mode of a sprite with spriteLOAD number 123
(say) will affect _all_ sprites of type 123 (= all entries in SpriteN[] with
value 123). This is intended, because the display mode is a piece of informa-
tion reflecting the sprite's physical structure!
(For the case that you disagree: of course you are free to load the same sprite
with a different load number into memory a second time and assign another
display mode to this copy!)
In mode "Display_NORMAL" you can think of a sprite as a picture with holes at
the places where its pixels have color 0: when displayed, all the parts of the
sprite with color<>0 will cover (paint over) the screens original pixels, but
the pieces with color=0 will act like "window panes": the original contents of
the screen remain visible there.
This mode is useful for all kinds of sprites which have such opaque holes in-
side themselves: cars/planes/houses or other objects with window panes, but
also all "concave" sprites. Note that black, COVERING parts must be realized
with a dark color<>0, for example color 16.
"Display_FAST" is a bit (but not that dramtically) faster than the last method,
because it doesn't know of a special color: all sprite data is treated equally
and stored to the screen at once. For that, all parts of the sprite are
covering. (But note that a sprite consists only of the points "inside" and on
its boundaries: all the points "outside" the sprite doesn't matter).
You will use this mode whenever you have sprites which meet the following re-
quirements: they are "convex" and don't have any transparent parts inside them-
selves.
"Display_SHADOW" is a tribute to the fact that one often needs some kind of
shadowing to give the impression of an freefloating object or other pseudo
3D-effects. In this mode, the sprite's real colors are insignificant, only its
boundaries and the actual contents of the screen where the sprite shall be
drawn are important. The color of every sprite point is determined by the color
of the appropriate screen point. The color of these points are translated by
the lookup table ShadowTab into darker ones.
If you want to give a sprite a shadow zone, then you must divide your sprite
into two ones: one building the sprite itself and a second one to realize only
that shadow area, and compose them with appropriate coordinates.
"Display_SHADOWEXACT" behaves quite similiar to "Display_SHADOW", but shadowing
will only take place at the sprite's pixels with color <>0, that is: color 0
is again used as "transparent", this time even for shadows! To state it other-
wise: Display_SHADOWEXACT is for displaying shadows what Display_NORMAL is for
displaying sprites (and Display_SHADOW relates to Display_FAST in that sense):
exactly for the same reason, Display_SHADOWEXACT is slower than Display_SHADOW!
Normally, you will use Display_SHADOW when you are using Display_FAST, too: If
your sprites are "convex" and don't have any transparent parts inside them-
selves.
(If you are still not sure about the difference between these two combinations
a) Display_FAST & Display_SHADOW
b) Display_NORMAL & Display_SHADOWEXACT
then EXAMPLE3.PAS is a good place to try out!)
Technically spoken, there are short code areas in ANIVGA's routines reserved in
which the right piece of code to transfer/interpret the sprite's data become
copied, when not already there. For optimal performance it is wise to group the
entries in SpriteN[] such that adjacent sprite entries share the same display
method.
See also : convex, concave
DUMP_SPR - utility
──────────────────
(This is surely a tool for all those hackers among us...)
If you want to take a closer look at a sprite's data, you don't have to fiddle
around with DEBUG or the like, just use this sprite dumper: it takes a (binary)
sprite file (*.COD or *.LIB) and disassembles it into readable ASCII-text.
You can redirect the output to a file or printer, e.g.:
DUMP_SPR mysprite.cod >mysprite.txt
would dump the sprite file "mysprite.cod" to the ASCII-text file "mysprite.txt"
for further usage.
Note that DUMP_SPR creates a format which will be understood by assemblers like
MASM or TASM so that you can reassemble the files to get a binary sprite file
once again!
To do so, you would have to enter the following commands (replace MASM by TASM
if you use Borland's assembler):
MASM mysprite.TXT; -> gives you mysprite.OBJ
LINK mysprite.OBJ; -> gives you mysprite.EXE
EXE2BIN mysprite.EXE mysprite.COD -> gives you mysprite.COD
ERROR - variable
────────────────
Function : Holds the code of the last error which occured
Declaration: VAR ERROR:BYTE
Description: If an error occurs while executing one of its routines, ANIVGA
terminates that routine and sets ERROR accordingly to reflect that
error.
You can use GetErrorMessage() anytime to get more information,
which error occured.
It is your responsibility to check if such an error occured and
react in an appropriate way.
For the possible values and their descriptions returned by
GetErrorMessage, see there.
Note (!) : - After processing an error, you have to reset the variable back
to Err_None yourself
- In respect of future extensions, you should treat every value
<> Err_None as an error
- The most frequented routine Animate() doesn't produce any
errors, neither do several other procedures. As a basic rule,
all routines which have to do with file I/O have to be checked.
- ERROR is initialized with Err_None
See also : GetErrorMessage, InitRoutines
FadeIn - procedure
──────────────────
Function : Fade in a graphic page onto the actually visible page.
Declaration: PROCEDURE FadeIn(pa,ti,style:WORD); FAR;
Description: If you need an interesting opening sequence for your program, then
FadeIn() is what you need: there are a lot of different routines
available to copy one image to the actually displayed graphic page
(1-PAGE): supply the page which shall be displayed "pa" (most
often, this will be BACKGNDPAGE), "ti" is the time (in millise-
conds) the fade should last (approximately), "style" defines the
algorithm to be used and must be one of:
Fade_Squares,
Fade_Circles,
Fade_Moiree1 .. Fade_Moiree14,
Fade_SweepInFromTop, Fade_SweepInFromBottom,
Fade_SweepInFromLeft, Fade_SweepInFromRight,
Fade_ScrollInFromTop, Fade_ScrollInFromBottom,
Fade_ScrollInFromLeft, Fade_ScrollInFromRight
Note : - The easiest way to use this routine is the following:
a) initialize the graphic mode via InitGraph(),
b) load the background page BACKGNDPAGE with your normal
animation background,
c) (if you want:) fill the visible page 1-PAGE with whatever
you want (initially, it is completely black)
d) call FadeIn(BACKGNDPAGE,2000,Fade_???);
(about 2000..4000 milliseconds are good values)
e) continue with your normal program
- Naturally, ANIVGA can't make your PC faster than it is: the
time value you supply is a _lower bound_!
- FadeIn() will use the "normal" MSDos-timer values for its
operation; as this timer has resolution of about 55msec, it
is quite inaccurate (..for a computer, I mean..), but as we
are talking about thousands of milliseconds here, that won't
matter! (Besides that, this timer won't interfere with the
one used for the animation rate, set by SetCycleTime()!)
See also : -
FillBackground - procedure
──────────────────────────
Function : Fills the background page with the specified color.
Declaration: PROCEDURE FillBackground(color:BYTE); FAR;
Description: The given value is written into the whole graphic page BACKGNDPAGE
and thus defines the picture before all animations take place to
have one color.
Note : Use of this routine only makes sense when using background mode
STATIC!
See also : Background, BACKGNDPAGE, BACKGNDADR, GetBackgroundFromPage,
LoadBackgroundPage
FillPage - procedure
────────────────────
Function : Fills a graphic page completely with a given color
Declaration: PROCEDURE FillPage(pa,color:Byte); FAR;
Description: If you want to paint a complete page uniformly with one color,
then this will be the fastest method to do it: specify the graphic
page (0,1 or BACKGNDPAGE (=2)) in "pa" and the color to be used in
"color".
Note : - Although possible, you are strongly discouraged to use this pro-
cedure in background mode SCROLLING (i.e.: pa=SCROLLPAGE (=3) as
page number), because the background is treated completely dif-
ferent!
- Remember also that changes to one of the drawing pages (0 or 1)
have to be applied _after_ calling Animate and will be visible
for exactly one animation cycle, whereas changes to the back-
ground page remain permanent (and are best done _before_ calling
Animate, although that's not peremptory).
- This routine is great to produce "flashing" screens: apply it to
1-PAGE (the visible page).
- Possible ERROR-values returned are Err_InvalidPageNumber
See also : background, How ANIVGA works, LoadPage, LoadBackgroundPage,
GetBackgroundFromPage
FontOrient, FontHeight, FontWidth - type/constants
──────────────────────────────────────────────────
Function : Supply some additional data about the internal font
Declaration: TYPE FontOrient=(horizontal,vertical);
CONST FontHeight=6;
FontWidth=6;
Description: The internal font used for displaying graphic text (OutTextXY(),
BackgroundOutTextXY()) can be displayed either horizontally or
vertically; use of the TYPE FontOrient simplifies that.
To compute the width/height of a text, the constants FontHeight
and FontWidth can be used, which specify the size of one letter.
Note : -
See also : OutTextXY, BackgroundOutTextXY
FreeImageMem - procedure
────────────────────────
Function : Releases the memory allocated by a GetImage()-call
Declaration: PROCEDURE FreeImageMem(p:POINTER); FAR;
Description: If you use GetImage(), ANIVGA allocates the memory needed and
returns a pointer to that area, which you can use with PutImage()
as often as you desire. If you don't need that clipped image any
longer, you should release its memory so that it can be used by
other routines again. To do that, just call FreeImageMem() with
the pointer GetImage() returned to you.
Note : It is this reason -releasing memory- why you shouldn't make an
"anonymous" GetImage() / PutImage() combination like
PutImage(x,y,GetImage(x1,y1,x2,y2,1-PAGE),1-PAGE): you don't get
a handle which could be used to free the occupied memory!
Of course, you could use "Mark()" and "Release()", but a simple
additional pointer variable ("p") is better style:
p:=GetImage(x1,y1,x2,y2,1-PAGE);
PutImage(x,y,p,1-PAGE);
FreeImageMem(p)
See also : GetImage, PutImage
GetBackgroundFromPage - procedure
─────────────────────────────────
Function : Take over one of the drawing pages as background image
Declaration: PROCEDURE GetBackgroundFromPage(pa:Byte); FAR;
Description: Specify the graphic page (0 or 1) from which the image should be
"captured" and the routine will copy its contents into the back-
ground page BACKGNDPAGE (=2) as new background image.
Note : - Use of the routine only makes sense if STATIC is used as
background mode.
- Possible ERROR-values returned are Err_InvalidPageNumber
See also : LoadBackgroundPage
GetErrorMessage - function
──────────────────────────
Function : Returns a description of the last error occured
Declaration: FUNCTION GetErrorMessage:STRING; FAR;
Description: Although you can use the ERROR variable directly to evaluate any
error and inform the user about it, it is often more comfortable
to let ANIVGA do that: GetErrorMessage will give you a string
describing the last error which occured in words.
The possible string contents and the corresponding ERROR values
are:
Err_None: 'No Error'
No error occured during the routine; this is the variable's
initial value
Err_NotEnoughMemory: 'Not enough memory available on heap'
The program couldn't load sprites or other data to the heap
Err_FileIO: 'I/O-error with file'
There was an error reading the file; either the file doesn't
exist at the path given or it is damaged
Err_InvalidSpriteNumber: 'Invalid sprite number used'
This error occurs if you try to load a sprite with a sprite
loadnumber not in the valid range 1..LoadMAX
Err_NoSprite: 'No (or corrupted) sprite file'
While attempting to interpret the data just read in, ANIVGA
found the data not to be in the expected format; either because
you used a wrong data file or it is damaged
Err_InvalidPageNumber: 'Invalid page number used'
There are four graphic pages, numbered 0..3. Page 0 & 1 are
used for the animation itself, page 2 ("BACKGNDPAGE") holds the
static background image and page 3 ("SCROLLPAGE") is reserved
for the scrollable background information
Err_NoVGA: 'No VGA-card found'
The animation package needs a VGA (or compatible) graphic card
but couldn't find one
Err_NoPicture: 'No (or corrupted) picture file'
The background picture file ANIVGA should load has not the ex-
pected size/format or a DOS-error occured while attempting to
access the data
Err_InvalidPercentage: 'Percentage value must be 0..100'
If you set the colortable for the shadowing effects of sprite
display mode Display_SHADOW or Display_SHADOWEXACT, you must use
a percentage value giving the remaining brightness of the colors
in the shadow areas, which must be in the range 0..100%, of
course
Err_NoTile: 'No (or corrupted) tile/sprite file'
There was an error loading the specified sprite file(s) and
interpreting them as background tiles. Most often this occurs
because the sprite doesn't meet the requirement to be a multiple
of 16 points in its x- and y-directions!
Err_InvalidTileNumber: 'Invalid tile number used'
There may be only 256 background tiles, numbered 0..255
Err_InvalidCoordinates: 'Invalid coordinates used'
The virtual background coordinates you use must lie in the range
(BackX1,BackY1)..(BackX2,BackY2), which has been specified with
SetBackgroundScrollRange()
Err_BackgroundToBig: 'Background to big for tile-buffer'
ANIVGA's tile buffer can hold no more than MaxTiles (=10000)
tiles, that is an area of 10000*16*16 pixels². Check the area
you specified in your SetBackgroundScrollRange()-call!
Err_InvalidMode: 'Only STATIC or SCROLLING allowed here'
The only background modes ANIVGA knows are STATIC and SCROLLING
Err_InvalidSpriteLoadNumber: 'Invalid spriteload number used'
spriteLOADNumbers must lie in the range 0..LoadMAX; when you
get this error, you probably confounded a spriteLOADnumber with
a spritenumber
Err_NoPalette: 'No (or corrupted) palette file'
You tried to load a palette file which didn't meet the require-
ments: a palette file must be of size 3..768 bytes and a
multiple of 3
Err_PaletteWontFit: 'Attempt to write beyond palette end'
While attempting to read in and store the palette file into the
actual color table, ANIVGA noticed that it would have to write
beyond the end of that table; decrease your "number" parameter!
Err_InvalidFade: 'Invalid fade style used'
You tried to use a fade style not supported by the unit: look
at routine "FadeIn()" for allowed styles.
(else): 'Unknown error'
If ERROR has none of the above values, this string will be
returned; this should never happen, though.
Note : Calling GetErrorMessage won't set back the ERROR variable either;
you must do that explicitly!
See also : ERROR
GetImage - function
───────────────────
Function : Makes a copy of the specified screen region
Declaration: FUNCTION GetImage(x1,y1,x2,y2:INTEGER;pa:BYTE):POINTER; FAR;
Description: - This function works much the same as its equivalent in Turbo-
Pascal: (x1,y1) and (x2,y2) define the upper left and lower right
corners of the screen part to save, but now these coordinates are
_virtual coordinates_, the routine reserves the memory needed to
hold the copy itself and you can specify the graphic page, from
which the image is to be taken (pa=0,1 or BACKGNDPAGE (=2) ).
- As result you get a pointer to the start of the saved image,
which can be used with PutImage().
- If there is not enough memory available or the specified part of
the screen lies completely outside the visible screen, NIL is
returned.
- Besides that, there are 5 global variables which are set accor-
dingly:
was_cut:BOOLEAN = TRUE/FALSE, if the image had to be _partially_
clipped (if the specified image is totally offscreen,
was_cut stays at FALSE!)
left_cut, right_cut, top_cut, bottom_cut:WORD hold the size how
much had to be clipped off at the boundaries; these
values are only set when was_cut=TRUE
(If you wonder about this odd definitions: GetImage was intended
to work only with the visible screen (that is: with _absolute_
coordinates): together with its counterpart PutImage(), you can
copy a part of the screen to another part or page. In that case,
you do not have to fiddle around with clipping: just issue a
GetImage() and use PutImage() to paste this block elsewhere.
But there may be some applications, when you cut out part of
the screen and think you got the complete graphic figure you
wanted, although (because of the use of virtual coordinates and
your figure being partially offscreen) you got only part of it.
Checking "was_cut" informs you about such a partial clipping.
If your figure is completely offscreen, that is a special case:
it depends on your application whether this should be treated
as being okay or not; if you need special treatment (as with
partial clipping), you still can check for this with something
like:
...
image_ptr:=GetImage(x1,y1,x2,y2,1-PAGE); {1-PAGE=visible page!}
IF ERROR<>Err_None
THEN ... {probably not enough memory}
ELSE IF (was_cut) OR (image_ptr=NIL)
THEN ... {partial or total clipping occured}
ELSE ... {no clipping at all}
)
- possible ERROR-values returned are: Err_NotEnoughMemory and
Err_InvalidPageNumber
Note : - As already mentioned, GetImage() only works on screen regions in
the _absolute_ coordinate range 0..319, 0..199, but expects
_virtual_ coordinates!
- To release the memory allocated by a GetImage() call, you must
use FreeImageMem(); TurboPascal's "Dispose()" won't work.
See also : PutImage, FreeImageMem, coordinates
GetModeByte - function
──────────────────────
Function : Returns the actual display method set for a sprite
Declaration: FUNCTION GetModeByte(Sp:WORD):BYTE; FAR;
Description: "Sp" specifies the spriteLOADnumber of the sprite from which the
user wants to know the display mode. The function will return one
of the valid modes Display_NORMAL, Display_FAST, Display_SHADOW
or Display_SHADOWEXACT.
Note : - Again, spriteLOADnumbers are used!
- If the LOADnumber given doesn't exist (because no sprite has
been loaded with that number), the routine will return
Display_UNKNOWN instead.
See also : Display modes, SetModeByte
GetPalette - procedure
──────────────────────
Function : Reads out the actually set color palette directly from the VGA
Declaration: PROCEDURE GetPalette(VAR pal:Palette); FAR;
Description: "pal" specifies the variable in which to store the actual palette.
Note (!) : - This procedure has been added for completeness, merely: As long
as you make all palette changes by using SetPalette(), you can
use the variable "ActualColors[]" instead!
- You must be in graphic mode already or you will get rubbish!
To state in otherwise: call this routine _after_ having called
InitGraph() and _before_ calling CloseRoutines()!
See also : SetPalette, Palette, ActualColors
GetPixel - function
───────────────────
Function : Reads a pixel's color
Declaration: FUNCTION GetPixel(x,y:INTEGER):BYTE; FAR;
Description: Returns the color value of the specified pixel with the virtual
coordinates (x,y) on graphic page PAGE. If (x,y) lies offscreen
(to be precise: the computed absolute coordinates lie offscreen),
then zero (= black) is returned.
Note : Be aware that PAGE is the invisible page, not the one you are
looking at!
See also : coordinates, PAGE, PageGetPixel, PutPixel
GRAB - utility
──────────────
GRAB allows you to "steal" graphics from other applications and convert them
into sprite files (*.COD) or background images (*.PIC) for use with ANIVGA.
This program is a terminate-and-stay-resident (TSR) utility that has to be run
before starting those applications from which you want to capture graphic
images.
It requires a mouse to be installed and a VGA card - note that an EGA won't do!
Pressing the hotkey CTRL-ALT-G will popup a frame which you can move and resize
to select the part of the graphic sreen you want to save (if you are not in a
graphic mode or in a graphic mode unknown to GRAB you'll here a beep instead).
Note that if you are in a "MSDos critical" situation, GRAB can't pop up.
Use the mouse to move the box, hold down the left mouse button and drag the
mouse to resize the box (in "sprite mode" only). The space bar will toggle
between "sprite mode" and "background mode", pressing the right button will
store the framed graphic to disk (either as sprite or background image, what-
ever program mode you are actually in).
Press ESC (or both mouse buttons simultaneously) anytime to escape from GRAB
back to your application.
By default, GRAB starts in sprite capture mode, thus generating sprite files
(starting with the file name GRAB_000.COD with increasing numbers for the next
sprites). To get a background image, toggle into screen capture mode by pres-
sing the space bar (a second press will switch back to sprite capture mode
again), select the screen region wanted and press the right mouse button to
get that part of the screen in the file GRAB_000.PIC (or whatever number is
actual then).
In both modes, GRAB also dumps the actually set palette to disk, having the
same number as the COD/PIC file, but with the ending ".PAL" and a (P)icture
or (S)prite replacing the underscore, e.g. "GRABS000.PAL" for the first
sprite saved.
Naturally, you can't resize your frame in the screen capture mode: it stays at
its initial size of 320x200 points.
Note that there is the a restriction for a sprite's size: a sprite may be
152x152 points in max., if you need bigger sprites then just save the sprite
as a PIC file and convert it afterwards, using MAKES.
There is only one possible command line parameter when installing GRAB:
"BIOS": Supplying "BIOS" tells GRAB to use the video bios interrupt INT10h to
access all video data. This should work on almost every VGA, but is extremely
slow.
Otherwise, GRAB defaults to its internal, fast access routines. Note that some
applications directly reprogram the VGA hardware so that GRAB must fail on
them (both in default and BIOS mode)!
Notes :
o It may happen that you can't popup GRAB in some applications; if you have
some commercial screen capture utility, you can use that (most often, they
are more "radical" in their behaviour, using undocumented Dos-funtions and
the like).
Then, use an appropriate viewer program and capture the graphic from their
display!
(Sorry, I know there are much situations where GRAB _should_ popup, but
does not - I'm not content with that, either, but I didn't write the TSR-
unit, but only use it; _if_ I should find the time, I'll write a more
suitable TSR-unit on my own)
o Especially if you save a screen as a PIC file, it will take quite a long
time until GRAB finishes its operation - be patient!
See also : MAKES, Palette
GraphTextBackground, GraphTextColor, GraphTextOrientation - variables
─────────────────────────────────────────────────────────────────────
Function : Determine how the OutTextXY()-procedures work
Declaration: TYPE FontChar=ARRAY[0..5] OF BYTE;
Font=ARRAY[0..255] OF Fontchar;
FontOrient=(horizontal,vertical);
CONST GraphTextOrientation:FontOrient=horizontal;
GraphTextColor:BYTE=white;
GraphTextBackground:BYTE=white;
FontHeight=6;
FontWidth=6;
Description: Whenever text is to be written to the graphic screen, ANIVGA
consults some global variables. GraphTextColor is simply the color
in which the text should be drawn, GraphTextBackground specifies
the color for the pixels in between the letters with one special
value: if GraphTextBackground=GraphTextcolor, then only the pixels
belonging to the letters will be drawn with all others remaining
unchanged.
Finally, GraphTextOrientation tells ANIVGA in which direction the
text should be written with two values being possible: HORIZONTAL
(default) for left-to-right text and VERTICAL for top-to-bottom
style text.
Note : Default color for the text is "white/white" = "white and don't
change pixel values between letters".
See also : OutTextXY, BackgroundOutTextXY
HitDetect - function
────────────────────
Function : Checks whether two sprites collide or not
Declaration: FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN; FAR;
Description: Call this routine with the sprite numbers of the two sprites to be
checked for collision; the function will return TRUE/FALSE when
the sprites collide/do not collide, respectively.
Note (!) : - Collision detection is independent of whether the sprites are
visible or offscreen: ANIVGA uses the corrdinates of the two
sprites given (in SpriteX/Y) and internal data to check.
- For this it is possible to check for collisions _before_ drawing
an image (with Animate) and thus make necessary sprite updates
at once!
- Inactive sprites cannot collide:
(SpriteN[s1] or SpriteN[s2]=0) -> FALSE
- A sprite can't collide with itself: (s1=s2 -> FALSE)
See also : Collision-detection
InitGraph - procedure
─────────────────────
Function : Initialises the VGA card for the use with ANIVGA
Declaration: PROCEDURE InitGraph; FAR;
Description: ANIVGA uses a special graphic mode, which supports 4 graphic pages
in the resoultion 320x200 pixels and 256 colors. Because this mode
is not known by the VGA's BIOS, ANIVGA has to reprogram the VGA.
You should use this command only once to switch into graphic mode.
Note : InitGraph automatically switches to the invisible graphic page
1-PAGE.
See also : Screen, CloseRoutines
InitRoutines - procedure
────────────────────────
Function : Resets all necessary internal variables of ANIVGA to initial values
Declaration: PROCEDURE InitRoutines FAR;
Description: At program start, some variables have to be set and a few system
checks are necessary.
Among these are:
- SpriteN[] and SpriteAd[] become cleared (= set to 0)
- Page (the actual drwaing page) is set to 0
- PageAdr is set to the segment address of the drawing page PAGE
- BackgroundMode is set to STATIC, i.e.: non-scrollable background
- BackGndAdr is set to the segment address of the background image
- StartVirtualX/Y are set to (0,0), making the normal screen coor-
dinates identical to the virtual screen coordinates
- the old graphic/text mode which was active at program start is
stored for restoring it at the program end
- the system is checked if a VGA card is present and the global
variable ERROR is set accordingly
- CycleTime is set to 0, which says that there should be no time-
control mechanism for the animation rate
- if the machine is not at least an AT, the time mechanism is
switched off completely
- COLOR is set to 15 (= white)
The first thing you should do in your programs is to look at the
ERROR variable: if it was set to something different from Err_None
(by the implicit, automatical call of InitRoutines) then your pro-
gram should not proceed further.
Note : - This routine is called automatically at the very beginning of
every program which uses ANIVGA. For that, there is normally no
need to call this routine explicitly.
- Possible ERROR-values returned are: Err_None and Err_NoVGA
- Note that this is the _only_ routine that definitely sets the
variable ERROR, either to Err_None or Err_NoVGA. Because it is
called at the beginning of every program, it is thus assured
that your application always has a defined value for ERROR!
See also : ERROR
Line - procedure
────────────────
Function : Draw a line between the two points specified
Declaration: PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE); FAR;
Description: Calling this routine will draw a line between the two points
(x1,y1) and (x2,y2) on graphic page "pa" and in the color COLOR.
The routine uses virtual coordinates and clips the line down to
its visible part.
"pa" must be one of the values 0, 1 or BACKGNDPAGE (=2).
Note : - As with all point-setting procedures of ANIVGA, you have to re-
member ANIVGA's working scheme: the first thing ANIVGA does when
Animate becomes executed is to copy the background image to the
actual drawing page PAGE, erasing everything on that image.
For this reason, a line drawn on the visible page 1-PAGE will be
visible exactly one animation cycle.
- Possible ERROR-values returned are: Err_InvalidPageNumber
See also : PutPixel, BackGroundLine, coordinates
LoadBackgroundPage - procedure
──────────────────────────────
Function : Loads a background image from disk
Declaration: PROCEDURE LoadBackgroundpage(name:String) FAR;
Description: This routine loads a bitmap image stored in file "name" into the
graphic page used for the background image (BACKGNDPAGE).
Note (!) : - This routine must be called *after* the graphic mode has been
initialized (with InitGraph())!
- You can create such images either with the WritePage()- and
WriteBackgroundPage()-routines of ANIVGA or the GRAB-Utility.
- Calling this routine is equivalent to use the routine LoadPage()
with BACKGNDPAGE as second argument.
- Possible ERROR-values returned are: Err_FileIO and Err_NoPicture
See also : Background, LoadPage, FillBackground, GetBackgroundFromPage,
InitGraph
LoadMAX - constant
──────────────────
Function : Specifies the maximum number of different sprites
Declaration: CONST LoadMAX=1000;
Description: For each physical sprite, ANIVGA uses an internal pointer to its
data. There are LoadMAX pointers, thus there may be up to LoadMAX
different spriteLOADnumbers (= different sprites).
Note : Don't mix this constant up with NMAX!
See also : NMAX, SPRITE, SpriteLOADnumbers, Spritenumbers
LoadPage - procedure
────────────────────
Function : Loads a graphic page from disk
Declaration: PROCEDURE LoadPage(name:STRING; pa:BYTE); FAR;
Description: "name" is the MSDOS-path to the graphic image to load, pa the
destination page (0,1 or BACKGNDPAGE (=2)).
Note : - The graphic mode must have been initialized (vià InitGraph)
already!
- You can generate disk files of graphic pages with the help of
the WritePage()-routine or with the GRAB-utility program.
- Don't use this routine to load an image into the SCROLLPAGE,
i.e.: in background mode SCROLLING!
- Possible ERROR-values returned are: Err_InvalidPageNumber,
Err_FileIO and Err_NoPicture
See also : GRAB, WritePage, background, InitGraph
LoadPalette - function
──────────────────────
Function : Loads a palette into memory
Declaration: FUNCTION LoadPalette(name:String; number:BYTE;
VAR pal:Palette):WORD;
Description: "name" is the MSDOS-name of the palette file (*.PAL) to load,
"number" is the index of the first loaded color in the desti-
nation array "pal". For example,
LoadPalette('C:\ANIVGA\TEST.PAL',0,my_pal)
would load the named palette file into my_pal and the first color
of this file would be stored in my_pal[0], the second in
my_pal[1] and so on. (This call - "number" set to 0 - will be
the form you'll need in 99% of all cases!)
The routine will read in the complete file and return the number
of colors read as result.
All other colors in "pal" before "number" or after the end of the
specified pal-file will stay untouched!
Note : - As the routine reads in the complete file, you must take care
not to write beyond the end of "pal"! Especially, if you load
a complete 256-color palette (size: 3*256=768 bytes), you must
start at color index 0 (that is: number=0) or you'll get an
"Err_PaletteWontFit"-Error! Most often however, you will use
this routine as in the example above.
- Other possible errors are: Err_FileIO and Err_NoPalette
- You can call this routine only after having called InitGraph()!
- You can directly load into ActualColors, that is the sequence:
Dummy:=LoadPalette(pal_name,0,ActualColors);
SetPalette(ActualColors);
is valid!
See also : palettes, SetPalette, GetPalette
LoadSprite - function
─────────────────────
Function : Loads one (or more) sprites into memory
Declaration: FUNCTION LoadSprite(name:String; number:WORD):WORD; FAR;
Description: "name" is the MSDOS-name of the sprite file to load, which can be
either a single sprite file (*.COD) or a complete sprite library
(*.LIB): the function will detect automatically, which format is
used while loading the data.
"number" is the spriteLOADnumber, the first loaded sprite will be
assigned to. If the file contains more than one sprite, they will
get consecutive LOADnumbers.
The value returned by the function is the numbers of sprites read
in (i.e.: 0 means "no sprite read", so you should check ERROR in
that case).
Note : - Unlike LoadTile(), LoadSprite() loads data into conventional
memory. For that, you don't have to be in graphic mode to load
data from disk!
- Possible ERROR-values returned are: Err_FileIO, Err_NoSprite,
Err_NotEnoughMemory and Err_InvalidSpriteNumber
See also : sprite format, MAKES
LoadTile - function
───────────────────
Function : Loads one or more tiles from disk
Declaration: FUNCTION LoadTile(name:STRING; number:BYTE):WORD; FAR;
Description: This routine loads the background tile file "name" into the
graphic memory area reserved for tiles (the SCROLLPAGE).
The starting number for the first tile of the file is "number",
if there are more than one tile in the named file, they will be
loaded to (with increasing numbers).
The function returns the number of tiles read in.
Note (!) : - This routine must be called *after* the graphic mode has been
initialized (with InitGraph)!
What the function actually does is reading in a sprite and con-
verting it into an internal tile format: if the sprite read in
doesn't have the proper size of a tile (16x16 pixels), you nor-
mally will get an appropriate error (Err_NoTile), with one (use-
ful) exception: if the sprite can be "cut" into tiles (that is,
its width and height are multiples of 16 pixels each), then
LoadTile() will do so with the following numbering scheme: from
left to right and from top to bottom.
For example, a sprite with (width,height)=(3*16,2*16) points
would be numbered as: (assuming that "number" = 0)
┌────────┬────────┬────────┐
│ │ │ │
│ 0 │ 1 │ 2 │
│ │ │ │
├────────┼────────┼────────┤
│ │ │ │
│ 3 │ 4 │ 5 │
│ │ │ │
└────────┴────────┴────────┘
Besides, LOADTILE can load a sprite library, too (they will be
loaded in the sequence in which they appear in the library).
- Possible ERROR-values returned are: Err_NotEnoughMemory,
Err_FileIO, Err_NoTile and Err_InvalidTileNumber
See also : Background, LOADSPRITE, TILE
MAKES - utility
───────────────
The design of sprites, background pictures and tiles is much to tedious to be
carried out manually. For this reason, there are two utility programs to
simplify that task. The first one is a resident program named "GRAB" to
capture graphics from other applications and convert them into sprites, the
second is MAKES, a spritemaker program.
To use it, you must have a mouse installed and a Super-VGA card.
-> MAKES uses a "tweaked" 640x400x256 graphic mode, only available at Super-
VGA-cards! If you don't have one (or one which chip-set isn't supported by
the supplied BGI-driver), you won't be able to run MAKES!
Let me cite from Jordan Hargrave's docs:
>Card types supported: (SuperVGA drivers)
>Ahead, ATI, Chips & Tech, Everex, Genoa, Paradise, Oak, Trident (both 8800
>and 8900), Tseng (both 3000 and 4000 chipsets) and Video7.
>These drivers will also work on video cards with VESA capability.
>
>I have not tested these drivers on all these card types, so I can not
>guarantee perfect operation with your card. I have tested them extensively
>on Trident, Tseng and ATI cards, and have had no problems. (Trident 8800
>cards occasionally have problems, especially older models)
If you can't run MAKES, then please drop me a note specifying which brand of
VGA card you have and which chip-set it uses!
There are no parameters or such things, just start it!
The screen is divided in several areas:
- the so-called "work area" in the upper left region, in which you paint your
sprite
- the palette area to the right of it, where you choose colors for painting
or define new colors
- the info bar right beneath the work area, which informs you about the
cursor position and some other actually set data
- the icon field, supplying 18 different functions: 8 "tools" and 10 pure
functions
- 10 function boxes at the very screen bottom, which can also be accessed by
pressing the appropriate function key (ever seen the Norton Commander?)
(Note that a lot of the icons/function boxes have two functions, where the
second one can be reached by holding down the shift-key while pressing/
clicking at the icon - this will be described later on, but you can always
press F1 in MAKES for a short summary.)
Now let's take a small tout through MAKES!
-> I propose that you print out this part of the documentation and then start
MAKES.EXE for the following description!!!
Huh - where to begin? Okay, look at the work area's boundary: it has small
marks on it, indicating 8 pixel intervals. Move the mouse cursor somewhere into
the workarea: right beneath the work area, your PC will display the mouse
cursor's position and what color is currently set at that point. Now move around
and convince yourself about the marks' values. Press the left mouse button a
few times: each time, a white pixel will be drawn at the cursor position,
because "pixel" is the selected tool and "white" the actually set drawing color.
Nothing whopping, eh? - Now press "+" a few times: wow! You zoom into the work
area as much as you wish (well, I limited it to a factor 30, but if _that_ is
not enough you should consider selling your PC for a seeing-eye dog, anyway!).
Use "-" to zoom out, down to value 1: for easier pointing, the cursor will
change to a small crosshair pointer when zooming is at factor 1.
-> Note that as the screen you look at has resolution 640x400, while ANIVGA's
has 320x200, zoom=2 (the default value) will give you normal 1:1 aspect
ratio!
You don't like monochrome pictures? Ok, then click (with the left mouse button)
at another color in the palette area: this changes the drawing color to the
color you clicked at.
Repeat choosing a color, but this time press the _right_ mouse button: a menu
will pop up and let you change the RGB-values of that color; this way, you may
alter the palette for your sprites!
-> Note that RGB-values reach from 0 to 63. If you want to copy another color's
values, then just click at this color; e.g. if you want to have color 222
hold the same color as 111 (for example as a template), then click with the
_right_ button at color 222 and then with the _left_ button at color 111
Now choose another drawing tool, let's say lines: click at this icon and move
back into the work area. Choose a starting point and click at it (release the
mouse button!): now you started a line: move around the mouse to route your
line; if you are content with it, then press the left button again. If you
decide to cancel the line drawing instead, then press the right button instead.
-> This "philosophy" will be used for all tools: press the left button to
start/advance/complete an action, press the right button any time to cancel
what you are doing - so get used to it!
Now repeat the process of drawing a line, but hold down "shift" while you are
clicking at the starting point: this tells the object "to be aligned" which
in the context of lines means that you are drawing a horizontal, vertical or
diagonal line! In the same way, you can align rectangles to become squares and
ellipses to circles. Try it! Choose these icons and draw the according objects,
aligned and not aligned (if you choose the lower rectangle/ellipse icon, your
objects will be filled out with the actual drawing color).
-> You may select another color even if you are in midst of drawing an object;
move out of the work area, click at the color you wish - as soon as you
move back into the work area, your object will change!
Let's try the filling tool (the left, bottommost one): it will fill all points
it can reach from the pixel you clicked at having the same color, e.g. if you
click at a white pixel, it will color all white pixels neighboured to that
pixel and so on. Note that as long as you don't press the left button a second
time, this coloring doesn't rest, that is if you move around the mouse after
having clicked the first time, MAKES will restart its fill algorithm starting
at the new pixel your mouse points at! This behaviour is a bit confusing in
the beginning but comes in very handy when you get used to it.
-> If you really get stuck - especially on slow machines - then just press the
right mouse button for two or three seconds to cancel the action and start
over again.
The last tool to be mentioned is the copy tool (the icon with the scissors):
you can span a (dotted) rectangular area which you want to copy the same way
you would draw a rectangle, but after pressing the mouse button a second time,
a copy of this area will be visible at your cursor which you can place where-
ever you want to. (Note that color 0 inside this copy will be treated as trans-
parent, which makes it easier to overlay objects at the screen!)
These 8 icons (the 4 leftmost in the upper and lower row) make up the available
_tools_, the resting 10 icons are "function buttons", that is: their linked
action will take place at once (respectively: after asking you necessary para-
meters).
I'll first name them, starting in the upper row at the 5th icon, in clockwise
order:
a) change color
b) rotate work area left
c) rotate work area right
d) mirror work area horizontally
e) go/move to the upper-left
f) display boundaries
g) mirror work area vertically
h) rotate work area down
i) rotate work area up
j) blink color
a)
You can replace pixels of a specific color by another color with this tool:
the program will ask you for the colors, which you can select by either
clicking in the palette area or by clicking at pixels in the work area itself.
b), c), h), i)
Clicking at one of these buttons will move the contents of the work area in
the according direction, but what "falls out" at one side of the work area
will show up on the opposite side again. If you hold down "shift" while
clicking, the image will rotate by one pixel, without shift, it will rotate
by 1/4 of the actual screen width.
d), g)
I guess these two mirror options should be quite clear; note that as
they mirror a small image in the upper left corner to the "far away" right/
bottom region of the work area, you'll often need a tool to "pull back" the
graphic contents to the upper left corner: that is exactly the task of the
e) icon: it will move the graphic contents to the top and left as much as
possible.
e)
As mentioned above, this tool will move the work area contents to the left
(and top), until column 0 (row 0) holds a non-zero colored pixel.
If you hold down "shift" while clicking at this icon, there is another
functionality: then, MAKES scrolls back the visible part of the workarea
back to the upper left region of the picture (0,0), that is: this is a short-
cut for pressing the left- and up-arrow keys a few times (see below for more
about this).
f)
If you want to know/see the boundaries of your sprite, then click at this
icon: the leftmost and rightmost (upmost & bottommost) pixel of each row
(column) will blink and a popup window will inform you about the sprite's
size numerically.
If you hold down "shift" while clicking this icon, MAKES will also blink all
transparent areas inside the sprite, which may be useful if you don't know
whether you must use display mode Display_SHADOW <-> Display_SHADOWEXACT and
Display_FAST <-> Display_NORMAL; in all other cases you can forget about this
option.
-> Note that sprites are always stored as the smallest rectangle which
surrounds them and starts at the upper left corner (0,0): if you don't have
special reasons to do otherwise, your sprites should start in the upper left
corner.
If for example you realize a sprite consisting of one single point at
coordinates (a,b), the smallest surrounding box with (0,0) as upper left
corner would be
(0,0) (a,0) of size (a+1)*(b+1) pixels (=bytes)!!!
┌──────────┐
│ │
│ │
│ │
└──────────▀ <─ this is your 1 point
(0,b) (a,b)
(In addition to that, the right edge of this box will be rounded up so that
the width of the sprite will be a multiple of 4)
To determine what areas belong to your sprite and which don't, the program
assumes color 0 to specify no-sprite-areas and all other colors to be part
of your sprite (roughly spoken).
j)
If for some reason you must know of all pixels of a specific color (e.g. to
distinguish two very similiar colors), you can use this function: the program
will ask you to select the color, what you can do by either clicking at a
work area pixel with that color or at a color in the palette area.
Okay, now that we are through with the icons, let's have a look at the keys:
you already know that "+" and "-" zoom in and out the workarea. But if zoom>1
then only a part of the complete workarea (320x200 pixels) will be visible!
To work on the "offscreen" regions, you can scroll the work area by using the
cursor keys: pressing one of the arrow keys will scroll by 1/4 screen into the
corresponding direction; if you hold down "shift" while pressing an arrow key,
it will scroll by one pixel instead. The absolute coordinate value of the
upper left corner you are looking at will be displayed by the two "offset:"
messages, e.g. "offset X: 40" means that there are 40 columns (0..39) to the
left of the visible window of the work area, which you may scroll in by
pressing the left arrow key. (Consider the work area as a view-finder of an
imaginary camera which you may slide into each direction).
A short-cut to return to the work area's origin (0,0) is available, too: press
shift and click at the "go/move to upper left" icon.
The function keys do what they tell you:
F1 = a short summary of the functionality not visible at first sight
F2 = save the work area's contents to disk as a sprite file
F3 = load a previously saved sprite into the work area; if you press "shift"
while activating this icon (or Shift-F3), then the work area won't be
erased before loading the sprite: this way, you may overlay several
sprites on the screen
F4 = save the actually set palette to disk. Note that if you are using the
BIOS' default palette, the program won't store it to disk (as you don't
need)
F5 = load a previously saved palette. This function is especially necessary
when you used GRAB to capture a sprite from an application using a
different palette. (See below for more about palette handling)
F6 = save the work area's contents to disk, this time as a background picture
F7 = load a previously saved background picture; the same notes apply as said
to loading sprites (F3)
F8 = clear screen. This will erase the work area and let you start all over
again. Note that it won't reset the palette to the BIOS' default! If you
want that, you have to press Shift-F9, too!
F9 = map the workarea colors onto another palette. This feature asks you for
a palette, loads that and then uses a minimum square algorithm to exchange
each's pixel color by the one from the specified palette which comes as
close as possible to the original color. (See below for more about that)
Shift-F9 works the same, but maps to the BIOS' default palette instead
of asking you for a palette file.
F10= quit the program
Note :
o Palettes:
Note that if you load/save a sprite or picture file, MAKES won't load/save
the according palette automatically, you have to do that manually. This has
been done intentionally, however: never forget that you may design a hundred
sprites with a hundred different palettes, but when it all comes down to
display these sprites simultaneously in your programs, only *one* palette may
be active! For that reason, you must mix all those palettes to the one you are
going to use.
Normally, that won't be that dramatic, as 240 free color shades (it is *very*
wise not to change the first 16 EGA-compatible colors) seem enough to me, but
perhaps you want to include a formerly designed sprite A, using palette B,
into a new program where you use palette C! Before you start mixing a new
palette D for this old and your new sprites together, you should try mapping
old sprite A's colors to palette C: To accomplish that, load sprite A (using
F3), then load its old palette B (using F5); now press "map palette to
palette" (F9) and tell the program to map onto palette C: if the result looks
good enough, then save sprite A (perhaps using a different name) and use
palette C for all items in your program, else you have to find a compromise
between palettes B and C (I'm actually working on a program which will auto-
matize that job, but for now, you are on your own!).
To state it clear: there is a conceptional difference between EXCHANGING a
color (using the "change color" icon) and CHANGING a color itself (by altering
the RGB values of one or multiple colors):
- exchanging colors doesn't change the palette, it merely uses another color
of that palette
- changing palette colors doesn't change the pixels' color number, but the
color's RGB value
In other words: if you exchange colors, then you don't have to save the color
palette again, as it didn't change, but the sprite, because its data changed.
On the other hand, if you changed palette colors, then you'll have to save the
palette, but not the sprite, as the pixel data didn't change.
(If you didn't get that: just always save both and forget about it...)
o Mouse problems:
I noticed that sometimes, the program hangs when initializing the mouse driver
(when it calls "INT 33h" with AX=0), what you see in that the starting count-
down doesn't get below 7. I don't have _any_ idea why this happens and hope
it won't show up on other systems. Note that this is (at least what I noticed)
a spurious error: cancel the program, restart it once more and it will work!
Besides that, when quitting the program, MAKES sometimes reports a senseless
runtime error - it is a spurious, not reproducable error I couldn't track
down, either (perhaps TP doesn't like my TSR / QEMM installation, I dunno)!?
o Memory:
You should have at least 256K free RAM if you start MAKES, or it won't work.
o Sprite size:
If MAKES tells you that it can't save the workarea as a sprite, because it
is "to big" - well, then you'll have to shrink your sprite! Sorry, but I
wanted MAKES to handle CODs and PICs at the same time, but 320x200 pixels
(the size of a picture) is to much for a COD, as the additional data stored
along with the sprite would make it larger than 64K! (Cut off a few rows or
columns until it works.)
Note also that MAKES has to store sprites with widths being a multiple of 4!
That is: it doesn't matter, whether the max. used x-coordinate is for example
316, 317, 318 or 319, because for all those 4 widths (0..316=317 pixels,
0..317=318, 0..318=319, 0..319=320), MAKES would have to store them with
the "rounded up" width of 320 pixels!
(In other words: although ANIVGA itself can handle sprites up to 32000 pixels
in each axis and 64K max. size, MAKES restricts you to sprites of x-size at
most 320 pixels and y-sizes of at most 200 pixels)
o COD <-> PIC:
Yes, you read right: MAKES doesn't care whether you are working on a sprite
or a picture graphic: just paint it and store it into the format you want
(subject to what I said above concerning the 64K limit)! Oh yes, that way
you may convert a sprite into a background picture (and vice versa) if you
have reason to do so!
o Tips:
The best way to design a sprite is to start in midst of a cleared work area.
If you need more room, rotate your sprite in the appropriate direction.
If you think you're done, use the rotate boxes again (or the "move to upper-
left" icon) to align your sprite with the upper left corner. Then click on
the "display boundaries" box to compare the sprite's size with what you
expected. To wide (high)? Then there is a pixel with color <> 0 to the right
(beneath) your sprite! Look at the max. column (row) MAKES told you and kill
that pixel! (To see it more clearly, just hold down "shift" while clicking
at the "display boundaries" icon).
If you are unsure whether you can use display mode Display_FAST or need
Display_NORMAL (same applies for Display_SHADOWEXACT and Display_SHADOW),
then hold down "shift", click at the "display boundaries" icon and look at
the picture: if the blinking parts "spread" out of the parts you think your
sprite should be made of, then you should use Display_NORMAL
(Display_SHADOWEXACT, respectively), if all the blinking areas are inside your
sprite, you can (and should) use Display_FAST (Display_SHADOW).
See also : sprite format, GRAB, Display modes
MaxTiles - constant
───────────────────
Function : Holds the maximum number of tiles to build the background image
Declaration: CONST MaxTiles=10000;
Description: In background mode SCROLLING, you may use up to MaxTiles tiles
to build your graphic image.
Note : -
See also : Background
NextSprite - variables
──────────────────────
Function : Holds the "successors" of sprites for sprite cycles
Declaration: VAR NextSprite: ARRAY [0..LoadMAX] OF WORD
Description: To realize a sprite cycle, you must tell ANIVGA which sprites
should be drawn one after another. It is this information
NextSprite holds! For example, let us assume that you wanted to
make the sprite(loadnumber)s 43, 177 and 111 a sprite cycle, i.e.:
whenever you set a sprite (to be precise: a SpriteN[]-entry) to
one of these three numbers, ANIVGA should cycle between the three
sprite-images in the sequence 43->177->111->43->177->111->...
You would then set NextSprite[43]:=177; NextSprite[177]:=111 and
NextSprite[111]:=43 (don't forget this final value!) to do so.
Note (!) : - Most often, you will have the situation that some sprite(load)-
numbers with consecutive numbers should make up a cycle. In that
case it is more convenient to use the SetSpriteCycle()-procedure
to do the job for you
- Again, note that the routine deals with spriteLOADnumbers! That
is intentionally, because a sprite cycle is related to the
_physical_ existent sprite data, or simply spoken: if you make
5 pictures to form a flickering torch and you are going to use
10 torches in your animation then each of them should loop
through this 5-picture-cycle, shouldn't it?
- NextSprite[] is initially set "to point to itself", that is:
NextSprite[i]=i for all possible i's. If you had to break off
a sprite cycle (though I can't think what this should be good
for...), you must restore this data, e.g.: if you wanted to
break the sprite cycle above, you would have to set
NextSprite[43]:=43; NextSprite[177]:=177; NextSprite[111]:=43;
- As this is a global variable, ANIVGA can't check whether your
settings make sense or not; thus, it remains your responsibi-
lity to use proper values!
See also : SetSpriteCycle, Sprite cycles
NMAX - constant
───────────────
Function : Determines the maximum of sprites to be active at the same time
(minus 1)
Declaration: CONST NMAX=499
Description: This constant sets the size of the internal tables - and thus the
valid sprite numbers: the indices of the tables SpriteX, SpriteY
and SpriteN must lie in the range 0..NMAX.
To state it otherwise, there may be up to NMAX+1 sprites creeping
around your screen at the same time...
Note : Don't confound that constant with LoadMAX
See also : LoadMAX
OutTextXY - procedure
─────────────────────
Function : Writes a textstring to the graphic screen
Declaration: PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING); FAR;
Description: ANIVGA has a built-in font, each character consisting of 6x6
pixels: very ugly, but hey, we want to make animations, not text!
To write the string "s" to the graphic screen, you must specify
the upper left starting corner of the text in (x,y):
(x,y) -> ▄──────────┐ , where (x,y) are virtual coordinates!
│ │
│ │
│ │
└──────────┘
The text will be drawn in color GRAPHTEXTCOLOR and with the orien-
tation GRAPHTEXTORIENTATION ("VERTICAL" or "HORIZONTAL").
A third global variable, GRAPHTEXTBACKGROUND, specifies the color
which will be used for the background area "beneath" the text
letters; if GRAPHTEXTCOLOR=GRAPHTEXTBACKGROUND then the text will
be drawn like TurboPascal's routine does: only the pixels be-
longing to the letters will be drawn, all others remain unchanged.
"pa" specifies the graphic page to be drawn on and must be one of
the drawing pages (0 or 1) or the BACKGNDPAGE (=2) for background
mode STATIC.
Note : - In 99% of all cases, you will output text to the visible
screen, that is: "OutTextXY(someX,someY,1-PAGE,'foobar')"
- Any text drawn to the working pages 0 or 1 will stay onscreen
only for one animation cycle. If you want it permanent, then
use BackGroundOutTextXY() in mode STATIC or replace any call
to Animate() by the sequence
Animate();
OutTextXY(someX,someY,1-PAGE,my_text)
which works in both modes STATIC & SCROLLING. (As always, if
you are in mode SCROLLING and use absolute coordinates, the
text will scroll with your graphic image, while if you use
relative coordinates (relative to StartVirtualX|Y of course),
then the text will stay at a definite physical monitor position.
For example,
OutTextXY(StartVirtualX,StartVirtualY,1-PAGE,'Hi!')
will tie the text to the upper left screen position)
- Better fonts could have been developped, but they would all
depend on special assumptions about the text- and/or background
color(s).
This font was intented for short and simple text strings and to
be as small as possible.
Nevertheless, using a bigger cell (say: 10x10) and several
colors (for antialiasing effects) can result in very impressive
fonts - and work, too...
- Possible ERROR-values returned are: Err_InvalidPageNumber
See also : GraphtextColor, GraphtextOrientation, GraphtextBackground,
BackgroundOutTextXY
PAGE - variable
───────────────
Function : Holds the number of the actual drawing page
Declaration: VAR PAGE:WORD
Description: ANIVGA uses a page flipping approach. Basically this means that it
alternates between using page 0 and page 1 for its display.
Although this mechanism should be transparent for the user, ANIVGA
provides you with the page number of the actual drawing page in
"PAGE". Note that this number specifies always the invisible page:
when PAGE=0, then the actual _displayed_ page is page 1 and vice
versa (ANIVGA always works on the invisible page!).
Note (!) : Only _read_ this value, never assign a new value to it!
PAGEADR - variable
──────────────────
Function : Holds the segment address of the actual drawing page PAGE
Declaration: VAR PAGEADR:WORD
Description: As already mentioned, there are four graphic pages, numbered from
0 to 3. The start addresses of these four pages are used by ANIVGA
and normally the user should not need to reference them, but with
PAGEADR at least the address of the actual (invisble) graphic page
PAGE is available in PAGEADR.
Note (!) : Only use this variable to _read_ its value, never change it!
Although this 16-bit-value represents only the segment part of the
complete address, it is the whole address: the address is norma-
lized in such a way that the offset part is always zero.
See also : PAGE
PageGetPixel - function
───────────────────────
Function : Returns the color value of the specified point
Declaration: FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE; FAR;
Description: If the point at the virtual coordinates (x,y) and graphic page
"pa" lies on the screen (i.e.: in the range (0,0)..(319,199) in
absolute coordinates), this routine will return its color, if it
is offscreen, the function returns zero.
"pa" should be one of the values 0, 1 or BACKGNDPAGE (=2).
Note : - If you want to read a pixels' color from the _visible_ page, you
have to remember that it is the opposite of the _actual_ page
(that is, you have to use "1-PAGE" as page number).
- Although only values of 0,1 and BACKGNDPAGE (=2) make sense as
"pa" values, the routine doesn't check that (for improved speed)
- For that, the routine _doesn't_ return Err_InvalidPagenumber or
something similiar in ERROR!
See also : Background, Coordinates, GetPixel
PagePutPixel - procedure
────────────────────────
Function : Plots a point at a specified page
Declaration: PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:BYTE); FAR;
Description: This routine is very similiar to PutPixel(), but it lets you
specify explicitly on which graphic page the point shall be drawn.
(x,y) specify the virtual coordinates of the point to be drawn in
color "color". If this point lies onscreen (i.e.: its absolute
coordinates are between (0,0)..(319,199)), it will be drawn on the
specified page "pa", which must have one of the values 0, 1 or
BACKGNDPAGE (=2). The latter only makes sense if STATIC is used as
background mode.
Note : - Don't forget that this routine works with virtual coordinates.
- Note also that the point is _not_ drawn automatically on the
background page if pa=0 or pa=1, thus it will be visible exactly
one animation cycle (and be overdrawn by the background image
then).
- Because of ANIVGA's working scheme, you probably want to use
this routine AFTER calling Animate() (else, your point would be
overdrawn by the background image immediately) if pa=1-PAGE.
If you want to draw the point at the _visible_ page, remember
that it is the "opposite" of the _actual_ drawing page, i.e.:
you have to use "1-PAGE" for "pa".
- For improved speed, the routine _doesn't_ check the "pa"
variable to have a valid value, so there will be no report to
ERROR (Err_InvalidPageNumber or the like) available!
It remains your responsibility to assure a proper value for pa!
See also : BackgroundPutPixel, PutPixel, coordinates, How ANIVGA works
Palette, PaletteEntry, PalettePtr - type
────────────────────────────────────────
Function : Supplies user with proper internal data types
Declaration: TYPE PaletteEntry=RECORD red,green,blue:BYTE END;
Palette=ARRAY[0..255] OF PaletteEntry;
PalettePtr=^Palette;
Description: Drawing colors with the EGA/VGA is quite an interesting thing!
You probably heard that "mode $13 gives you 256 out of 262144
colors". The key to this is the palette (or, to be precise:
the color-look-up-table "CLUT").
Every color (in the range 0..255) is used as a pointer into the
CLUT; the corresponding entry consists of three bytes, which
stand for the red/green/blue intensity of that color (in that
order!). These three "bytes" (only the values 0..63 are valid for
each of them) together form an "PaletteEntry". Because we have
256 colors, a complete CLUT is made of 256 such entries: such a
table will be called a "Palette" in ANIVGA!
Note : ANIVGA initially assumes the default colors of mode $13.
When you change the palette and you are using one of the display
modes Display_SHADOW or Display_SHADOWEXACT, ANIVGA must know
this, as it must recompute its ShadowTab. "SetPalette()" takes
care of this, so you shouldn't change palettes by other means
than "SetPalette()" until you are absolutely sure what you are
doing!
FYI: Note also that the 256 color modes are something special:
in all other graphic modes (the EGA's 640x350x16 for example),
there is a second, intermediate indirection level.
There, the color value is used as an index into a table, giving
a value between 0..63. This value is used again as an index into
a second table which holds the triples ("PaletteEntries")
mentioned above. The first table is called the palette, the second
is the CLUT. In the 256 color modes, only the CLUT is used, but
few of us ever heard of CLUTs! Because there is no way to confuse
things in ANIVGA, I decided to use the term "palette"!
See also : SetShadowTab, ShadowTab, DefaultColors, SetPalette, GetPalette
Palette (*.PAL) files - information
───────────────────────────────────
Palette files generated by GRAB and MAKES make it possible to use different
colors than the BIOS default values, just by issuing a LoadPalette()-call.
Their internal format is the simplest possible: each color consists of three
bytes, specifying the RGB-values (in that order), where each value can reach
from 0 (darkest) to 63 (brightest), e.g.: a bright red would be coded as
(63,0,0).
LoadPalette() reads in a complete palette - equally, if it is 3*16 bytes in
size or the max. 3*256 bytes for a complete 256 color palette, but it is wise
to use complete 256 color palettes, because otherwise you soon get confused,
- don't say I didn't warn you!
See also : LoadPalette(), Palette
PutImage - procedure
────────────────────
Function : Pastes a formerly copied image to the screen
Declaration: PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:WORD); FAR;
Description: PutImage() is the counterpart of GetImage(): use GetImage() to
copy part of the screen and PutImage to paste it somewhere. (x,y)
is the upper left corner of the destination (in _virtual_ coordi-
nates), "p" is the pointer given by GetImage() and "pa" is the
number of the graphic page (0, 1 or BACKGNDPAGE (=2)) of the des-
tination.
If p equals NIL, the routine does nothing at all; this is useful
because you can PutImage() directly on the result of a GetImage()
call without further checking for clippings, although you should
be careful by doing so: you don't get a "handle" this way which
you could use to free up the occupied memory again!
(See FreeImageMem() for more about that)
Note : - Like GetImage(), this routine also works only when the _virtual_
coordinates translate into _absolute_ coordinates in the range
of 0..319, 0..199, that is: they must lie on the visible part of
the screen, everything else is clipped off.
- Possible ERROR-values returned are: Err_InvaliPageNumber
See also : GetImage, FreeImageMem, coordinates
PutPixel - procedure
────────────────────
Function : Plots a point
Declaration: PROCEDURE PutPixel(x,y:INTEGER; color:BYTE); FAR;
Description: (x,y) specify the virtual coordinates of the point to be drawn in
color "color". If this point lies onscreen (i.e.: its absolute
coordinates are between (0,0)..(319,199)), it will be drawn on the
visible page 1-PAGE.
Note : This routine is not the same as TurboPascal's one: it works with
virtual coordinates! Note also that the point is _not_ drawn on
the background page, thus it will be visible for exactly one ani-
mation cycle (and be overdrawn by the background image then).
Because of ANIVGA's working scheme, you probably want to use this
routine AFTER calling Animate() (your point will then be visible
until the next call to Animate()).
See also : BackgroundPutPixel, PagePutPixel, coordinates, How ANIVGA works
PutTile - procedute
───────────────────
Function : "Pastes" a tile into the background image
Declaration: PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE); FAR;
Description: After you have defined a background scrolling area, you can use to
PutTile() to arrange them as wanted to build your background image.
(x,y) is the virtual coordinate where you want the tile "TileNr"
to be placed.
(x,y) will be changed to be a multiple on 16 in each direction
and must then lie in the range (BackX1,BackY1)..(BackX2,BackY2).
Note : - Of course, this routine only makes sense when you use background
mode SCROLLING!
- (x,y) will be drawn to the upper left to fall on the grid.
- Possible ERROR-values returned are: Err_InvalidCoordinates
See also : background, tile, SetBackgroundScrollRange, coordinate, BackX1,
BackX2, BackY1, BackY2
Screen - procedure
──────────────────
Function : Chooses the display page.
Declaration: PROCEDURE Screen(pa:BYTE) FAR;
Description: Call Screen() with a value between 0 and 3 which tells the routine
to which graphic page it should switch. This is done by repro-
gramming the VGA start address registers. For a flickerfree dis-
play, this switching is synchronized to the display enable signal.
Note (!) : - You should not use this routine if you are not absolutely sure
what you are doing! Be aware that ANIVGA relies on the fact that
the actual drawing page is PAGE and its segment address is in
PAGEADR while the actually visible page is 1-PAGE!
- Although it makes little sense to apply this routine to graphic
pages other than 0 or 1, it is possible to set "pa" to 2 (=BACK-
GNDPAGE) or 3 (=SCROLLPAGE).
See also : PAGE, PAGEADR, InitGraph
ScrollPage - constant
─────────────────────
Function : Holds the page number of the backround page
Declaration: CONST SCROLLPAGE=3;
Description: When using background mode SCROLLING, BackGndPage specifies the
page number of the tile buffer used to build up the background
image for animations.
Note (!) : Use of this constant only makes sense when using background mode
SCROLLING!
See also : BackGndPage, Background
SetBackgroundMode - procedure
─────────────────────────────
Function : Chooses one of the possible background modes of ANIVGA
Declaration: PROCEDURE SetBackgroundMode(mode:BYTE); FAR;
Description: ANIVGA has two possible ways of handling background you can choose
of: "STATIC" or "SCROLLING" backgrounds with several advantages
and disadvantages, each (see background). Specify the mode you
want to use in the "mode" variable.
Note : - Default value set by ANIVGA is STATIC.
- Possible ERROR-values returned are: Err_InvalidMode
See also : background
SetBackgroundScrollRange - procedure
────────────────────────────────────
Function : Specifies the scrollable background area in mode SCROLLING
Declaration: PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER) FAR;
Description: (x1,y1) is the upper left corner of the background scroll area,
(x2,y2) the lower right corner (all virtual coordinates).
ANIVGA will round the points given to fit on a grid with mesh 16,
that is, x1,y1,x2,y2 will be changed to be all multiples of 16.
These new values will be stored in the (global) variables BackX1,
BackY1, BackX2, BackY2 for further use.
Besides that, XTiles and YTiles will hold the width and height of
the choosen background area in tiles.
Note : - You can read the Back??-variables for your information, but
don't change them!
- Of course, this routine only makes sense when you are going to
use SCROLLING as background mode.
- The upper left corner (x1,y1) will be drawn to the upper left,
the lower right corner (x2,y2) to the lower right to fall on the
grid.
- Don't forget that the tile memory is limited; you can't select
an area bigger than MaxTiles (=10000) tiles, that is more than
2560000 pixels².
- Possible ERROR-values returned are: Err_InvalidCoordinates and
Err_BackgroundToBig
See also : background, tiles, PutTile
SetCycleTime - procedure
────────────────────────
Function : Defines the maximum animation speed
Declaration: PROCEDURE SetCycleTime(milliseconds:WORD); FAR;
Description: There are lots of PC-compatible machines with a broad range of
clock rates, wait states and different speeds of their graphic
cards. With this routine you can set the time an animation cycle
has to last at least: at the very end of Animate, the routine
checks whether at least "milliseconds" milliseconds have been past
since the last call to this routine and waits if necessary.
If you give 0 milliseconds as an argument or your machine is not
(at least) an AT class machine, there will be no such time control
mechanism and the animation will always take part at the maximal
speed on the specific machine (this is also the default value).
For example: "SetCycleTime(100);" would restrict the animation
rate even on the fastest 80586 machines to at most 1sec/100msec
= ten frames per second.
Note (!) : - Because there is no such high precision timer on PC/XT computers
as required, SetCycleTime() is ignored on these machines.
Anyway, this should be not to hard because these computers are
normally that slow that they would not have been slowed down
either.
- The accuracy of this timing mechanism is better than 1 milli-
second.
SetModeByte - procedure
───────────────────────
Function : Specifies the way a sprite will be displayed
Declaration: PROCEDURE SetModeByte(Sp:WORD; M:BYTE); FAR;
Description: This routine assigns one of the possible display methods "M"
(Display_NORMAL, Display_FAST, Display_SHADOW,
Display_SHADOWEXACT)
to the specified spriteLOADnumber "Sp".
Note : - Because this kind of information is stored directly inside the
sprite data, the sprite must have been loaded already for this
routine to work.
- For the same reason, the routine works on spriteLOADnumbers,
not sprite numbers (>gee, again!<): a display method set for one
spriteLOADnumber will affect all sprites with that LOADnumber!
Most often, that is okay (e.g.: if you use the sprite of a foot-
ball player ten times, it is quite normal to use the same dis-
play mode for all ten players!), if you really must use a sprite
with two different display methods at the same time, you can use
the following trick: load the sprite's data a second time into
memory, using a different spriteLOADnumber. For this new copy,
you can use another display mode.
- Possible ERROR-values returned are: Err_InvalidSpriteNumber and
Err_InvalidMode
See also : SpriteLoadNumber, SpriteNumber, Display methods, GetModeByte
SetOffscreenTile - procedure
────────────────────────────
Function : Defines the tile to be used outside the specified scroll range
Declaration: PROCEDURE SetOffscreenTile(TileNr:BYTE); FAR;
Description: When you use background mode SCROLLING and have set up a scroll
range (via SetBackgroundScrollRange() ), all tiles _within_ that
region are specified by your settings done with PutTile().
However, ANIVGA must know what to draw when it has to display
areas _outside_ that "window": you can choose that tile with
SetOffscreenTile().
Example: You set your scrollable background range by issuing
SetBackgroundScrollRange(-500,-500,1000,1000) and used PutTile()
to define that tiles 0..10 (say) should be used inside that
window (-500,-500,1000,1000) in some specific order. If you want
that everything outside the window should be painted with tile
6 (say), you would tell ANIVGA so by calling SetOffscreenTile(6)
Note : - The default value set by ANIVGA is 0
- Of course, using this procedure only makes sense when using
background mode SCROLLING!
See also : SetBackgroundScrollRange, PutTile, Background
SetPalette - procedure
──────────────────────
Function : Changes the VGA's color values
Declaration: PROCEDURE SetPalette(pal:Palette; update:BOOLEAN); FAR;
Description: You can use this procedure to change the color values of the VGA's
256 colors by supplying an appropriate palette.
"update" tells the procedure whether it should recompute its
internal "ShadowTab" or not; if you use one of the two display
modes Display_SHADOW or Display_SHADOWEXACT you must set this
value to TRUE or the shadow areas will show "wrong" colors
(namely the old ones *before* changing the palette). If you don't
use shadowing (or change colors in a way so that using the old
shadow is okay), you can use FALSE and save some time.
Note : - SetPalette automatically updates "ActualColors" to reflect the
changes made; although you don't have to use the variable
"ActualColors" as first parameter of this procedure, you are
recommended to do so, that is
a) make your color changes to ActualColors[]
b) call SetPalette(ActualColors,TRUE|FALSE)
This way, you will save some time and the memory requirements
for an additional palette
- If you messed up things, use "SetPalette(DefaultColors,TRUE)" to
return to the default values.
- You must be in graphic mode already or strange things may happen
(at least, you won't get the colors you intented...)
To state in otherwise: call this routine _after_ having called
InitGraph() and _before_ calling CloseRoutines()!
See also : GetPalette, Palette, LoadPalette, ActualColors
SetShadowTab - procedure
────────────────────────
Function : Set the amount of shadowing in display modes Display_SHADOW and
or Display_SHADOWEXACT
Declaration: PROCEDURE SetShadowTab(brightness:BYTE); FAR;
Description: Whenever a sprite is drawn in Display_SHADOW / Display_SHADOWEXACT
mode, ANIVGA must know how much darker these shadow areas should
be, compared with the brightness of the original (not-shadowed)
colors.
This data is held in the table ShadowTab and is set by default to
70% of the colors original brightness. However, you can use this
routine to provide more or less darker shadow areas: "brightness"
is the percentage of the colors original brightness which shall
remain, e.g.: brightness=0 would mean every shadow is completely
black, brightness=100 is the original color as shadow (not darken-
ed at all), brightness=40 will darken every color by 100-40=60%,
etc.
Note (!) : - SetShadowTab() bases its computation on the actually displayed
colors, held in the table "ActualColors"
- This routine takes app. 1s on an 8MHz AT. This can be quite a
"long" time when you are in midst of a smooth animation sequence
-or doesn't bother you at all (e.g., in the very beginning of
your program) - this depends on your applications!
- The argument will be only approximated: the algorithm computes
the 256 color values needed precisely and matches them as close
as possible to the 256 colors actually set.
Note that the palette registers of the VGA card *won't* be
changed at all! ANIVGA still works with the default VGA palette
of the BIOS (or whatever values you set); what it does is
solely creating an internal color look-up-table!
- Possible ERROR-values returned are: Err_InvalidPercentage
See also : ShadowTab, ActualColors, Display modes, SetModeByte
SetSpriteCycle - procedure
──────────────────────────
Function : Links spriteLOADnumbers together to form a sprite cycle
Declaration: PROCEDURE SetSpriteCycle(nr,len:WORD); FAR;
Description: "nr" is the first spriteLOADnumber to be included in the sprite
cycle and "len" entries (i.e.: from "nr" to "nr+len-1") should be
tied together.
The routine will then set the according NextSprite[] entries to
build this cycle: nr -> nr+1 -> nr+2 -> ... -> nr+len-1 -> nr
Note : - The routine uses spriteLOADnumbers, _not_ sprite numbers!
- If you want to link sprite(loadnumber)s which do not have conse-
cutive (load)numbers, you must do that by setting NextSprite[]
accordingly.
See also : Sprite cycles, NextSprite
ShadowTab - "procedure"
───────────────────────
Function : Table for translating sprite colors into others
Declaration: PROCEDURE ShadowTab; FAR;
Description: If the display mode "Display_SHADOW" is set for a physical
sprite, its colors will depend not on the values stored in the
sprite itself, but on the values found on the screen at the place
where the sprite shall be drawn: every pixel of the sprite will
become darkened by substituting its corresponding color against
the color stored in this color table. (Mode "Display_SHADOWEXACT"
behaves the same, but shadowing will take place only at points
with sprite color <>0 - that's the whole difference).
At startup, this table is set to make shadows be approximately
70% the brightness of the original colors, but you can adjust
this with the routine SetShadowTab() if this value is not sui-
table for your application.
You can even supply a completely different color table (for
special effects?).
To do so, define an array "[0..255] of byte" (you should use the
predefined TYPE ColorTable for this), containing for each color
of the standard palette its substitute (e.g. setting array
element [8]:=13 would mean: "replace every pixel in the shadow
area with color 8 against a pixel with color 13") and overwrite
the original color table by issuing the command
"MOVE(my_array,@ShadowTab^,256)"
Note : - Although this table is declared as a procedure, it really is
data, not code; so don't call it!
- There can be only _one_ color table and it is only active in
display modes "Display_SHADOW" or "Display_SHADOWEXACT".
See also : SetShadowTab, Display modes, SetModeByte
SPRITE, Spritenumbers, Spriteloadnumbers - information
──────────────────────────────────────────────────────
A sprite is the basic data element used in ANIVGA. Technically spoken, it is
nothing more then a two-dimensional array of bytes which becomes copied to the
screen positions needed, but it is far more comprehensive to think about it as
a photograph of a figure which can be pasted to the screen whereever you want.
To distinguish between different sprites, we use natural numbers, but whenever
we talk about "sprites", we are somehow inaccurate:
You should notice that there are two kinds of "sprite numbers" which should
not be mixed up: one is a spriteLOAD number and represents a handle to the
(physical) sprite data, while the other (normally termed "sprite number") is
a logical number to address the sprite data.
Yet, most often it is clear from the context, which meaning is intended:
For a simple example: if you are going to animate a soccer team, you would
need 11 sprites for the player - but they all have the same shape. This means,
you only have to load one sprite (-> you need 1 spriteLOAD number), but need
11 copies of that image to move around the screen (-> you need 11 sprite
numbers).
(See section "How ANIVGA works" for more about that)
You can design sprites with the help of the spritemaker-tool MAKES, by using
GRAB to capture and convert graphic screens from other graphic applications
or write your own tools for that (it's really not that difficult you think
it is...).
See also : sprite format, How ANIVGA works
SPRITE CYCLES - information
───────────────────────────
Often, you don't want to have a single picture as sprite, but a sequence of
them which should loop forever. For example, let's assume that you use a torch
as an animation object in your application and you want it to have a flicker-
ing flame.
You would start to draw 5 (say) pictures, which -repeatedly displayed one
after another- would make the impression of your flickering torch. But within
your application, you still want to handle these five different images as one
single object - namely the sprite "torch".
To do so, you can use a capability of ANIVGA, called a "sprite cycle": load
the five images as (physical) sprites and tie their loadnumbers together to
form that sequence!
The easiest way to do that would be to load the images with consecutive
numbers and use the SetSpriteCycle() procedure to form the sprite cycle (see
there).
Note that we are talking about linking spriteLOADnumbers here: when you have
built such a cycle for your torch and you want to use 10 torches in your
program, you surely want that each of them behaves the same, that is: they all
should show a flickering flame by using that sprite cycle.
For this reason, ANIVGA uses spriteLOADnumbers, so that every instantiation of
a spriteLOADnumber (i.e.: a SpriteN[]-entry) belonging to a cycle will lead to
a sprite cycle for this sprite! (Tip: in out torches example, it would be wise
to use different starting values for the 10 torches, so that they do not
flicker "in phase")
A small detail at last: if you defined a sprite cycle to be a->b->c->a->...,
and initialized a SpriteN[]-entry to "a", then the first sprite displayed at
the screen will be "b" instead of "a" - why?
Well, ANIVGA handles sprite cycles in the Animate() routine and thus has two
possibilities to update the SpriteN[]-table (by issuing a "SpriteN[] :=
NextSprite[SpriteN[]]" command): _before_ drawing the sprites or _afterwards_.
But when it does _after_ drawing the sprites, the sprites displayed on your
screen (=the old SpriteN[] values before doing the above command) are incon-
sistent to the according numbers actually held in the SpriteN[]-table!
This could lead to problems (e.g.: when you do a HitDetect() after calling
Animate()). Although this could be circumvented by a special grouping of sub-
routine calls, it is far more convenient to update the SpriteN[]-table
_before_ drawing the sprites.
The only drawback with this method is the one stated in the beginning: not the
SpriteN[]-entry supplied by you will be drawn, but its "successor"
NextSprite[SpriteN[]]!
However, most often that won't be that bad and *if* it would, you still could
compensate for it by using the sprite's predecessor (in the above example, you
would use "c", as it is the predecessor of "a", to display "a").
SPRITE FORMAT - information
───────────────────────────
As already said, a sprite is nothing more then a two-dimensional array of
bytes which becomes copied to the screen positions needed.
For quick animations, the data should be stored in a format which causes few
and simple transformation steps when accessing the data, but it is hard to
keep up with that principle, because the graphic mode used is "planed".
This means that points are _not_ stored sequentially into the graphics memory,
but in a rather strange way: every 4 points use the same address, but lie in
different "bitplanes". To cut it short: clipping and drawing sprites is hell
therefore (and surely one reason why there are so less tools for this mode)
and ANIVGA uses a very special format to store a sprite (= *.COD-files):
0..1 DW offset to Plane_0_Data (points with x-coord. MOD 4=0)
2..3 DW offset to Plane_1_Data (points with x-coord. MOD 4=1)
4..5 DW offset to Plane_2_Data (points with x-coord. MOD 4=2)
6..7 DW offset to Plane_3_Data (points with x-coord. MOD 4=3)
8..9 DW sprite width (DIV 4), rounded up if not dividable by 4
10..11 DW sprite height in lines
12..15 DB 1,2,4,8 ; constants (translate-table)
16..17 DW SpriteLength ; length of this sprite file
18..37 DW 10 dup(?) ; reserved area for future use
38..39 DB 'K','R' ; code for "this is a sprite file"
40 DB 1 ; version
41 DB 0 ; default display mode (0=Display_NORMAL)
42..43 DW offset pointer to left boundary table
44..45 DW offset pointer to right boundary table
46..47 DW offset pointer to top boundary table
48..49 DW offset pointer to bottom boundary table
50..SpriteLength-1: boundary- and plane data tables
(If you should wonder why all pointers are only 16 bit long: the maximal size
of one sprite is 64k, so offset pointers are sufficient.
Another trick is that ANIVGA loads sprites at segment boundaries; for that,
you don't have to distinguish between "relative offsets" and "offset poin-
ters": if normalized segment addresses (=offset part is ε [0..15]) are used
to address sprites, the offset part is always 0, so the two terms are
identical!)
The Plane_?_Data tables consist of the points of the sprite (1 pixel = 1 byte);
if the sprite width is 12 pixels (say), then each table would hold 12/4=3 bytes
for each of the sprite's rows:
Plane_0_Data = color of pixels 0,4,8 of 1. sprite row
color of pixels 0,4,8 of 2. sprite row
...
Plane_1_Data = ditto, for pixels 1,5,9
Plane_2_Data = ditto, for pixels 2,6,10
Plane_3_Data = ditto, for pixels 3,7,11
The boundary tables hold the outermost positions of the sprite:
The left/top/right/bottom boundary table holds the leftmost/topmost/
rightmost/bottomost pixel of each row/column/row/column (or 16000/16000/
-16000/-16000 if none exists), respectively:
left boundary table = leftmost pixel coordinate of 1. sprite row (or 16000)
leftmost pixel coordinate of 2. sprite row (or 16000)
...
Note that each entry in the boundary tables consists of a signed integer!
Note also that sprites are always stored as the smallest, the figure including
box (rounded up in the x-direction to the next multiple of 4), but that the
values of the "superfluous points" stored in the plane tables doesn't matter
at all (no difference which display mode is used for the sprite!), because
ANIVGA uses only the bytes of the areas which belong to the _real_ sprite-
figure (ANIVGA determines these parts by assuming the sprite to be "horizontal
convex" and uses the boundary tables to compute them).
(Don't worry if you do not understand these technical details now --hopefully,
you won't need them at all).
See also : MAKES, Display modes, convex, sprite library
SPRITE LIBRARY - information
────────────────────────────
Sprite files can be combined to sprite libraries. The main advantage of this
is that you can reduce the number of files needed for your programs drama-
tically:
A normal program will use approximately 20..40 different sprites, so that you
would have 20..40 files only for your sprites!
But ANIVGA's routine to load sprites "loadSprite()" is flexible enough to dis-
tinguish whether the file to be loaded contains one or more sprites and loads
them all.
To construct such a "sprite library" (suggested filename extension: .LIB), you
just use MSDos' COPY-command with the binary option "/B" to glue the binaries
together; for example:
COPY /B sprite1.cod+d:\sprites\sprite2.cod+testspr.cod A:\mylib.lib
would concatenate the three sprites "sprite1.cod", "d:\sprites\sprite2.cod"
and "testspr.cod" and build the sprite library "A:\mylib.lib".
Note : You can reverse this process with the UNLIB-utility.
See also : UNLIB, sprite format, loadSprite
SpriteAd - variable
───────────────────
Function : Store the pointers to the sprites' data
Declaration: VAR SPRITEAD:ARRAY[0..LoadMAX] OF WORD;
Description: Whenever you load a (physical) sprite with LOADnumber xxx, ANIVGA
stores the sprite's data somewhere in RAM and maintains a pointer
which points to the beginning of this data as a handle to access
the data: this handle is stored in SpriteAd[xxx] and reflects the
segment part of the starting address of the data.
Note : Don't change that data directly unless you are absolutely sure
what you are doing!
See also : LoadSprite, SPRITE, Sprite Format
SPRITEN, SPRITEX, SPRITEY - tables
──────────────────────────────────
Function : Hold the values of all sprites to be drawn in the next animation
cycle.
Declaration: VAR SpriteN:ARRAY[0..NMAX] of Integer (SpriteX/Y dto.)
Description: ANIVGA is based on tables: in SpriteN[] you must declare, which
sprites shall be drawn in the next animation step. To do that,
store the spriteLOAD number of the sprites into the SpriteN[]-
entries; a zero indicates that the according sprite is inactive
and should not be displayed.
For every active sprite (SpriteN[i]<>0), a pair of virtual coor-
dinates in the range -16000..+16000 must be specified in the
SpriteX[i] and SpriteY[i] entries to determine the sprites' po-
sition on the (virtual) screen.
These coordinates will be transformed internally into real coor-
dinates to decide whether the sprite is onscreen and has to be
displayed or not.
Note : If you have less sprites than are allowed by the system (that is:
less than NMAX+1), your decision what table entries you use are
arbitrary; if for example you have only two sprites, it won't
matter, if you use SpriteN[0] for the first one and SpriteN[1]
for the other or vice versa, or SpriteN[123] and SpriteN[310] or
whatever valid indices you can think of - except in one point:
the sprites are drawn in reverse order, that means SpriteN[NMAX]
is drawn first, then SpriteN[NMAX-1] ... SpriteN[0].
For that, if two (or more) sprites overlap each other, the one
with the smallest index is drawn topmost and covers the other(s).
For performance reasons you should observe another rule: if you
use different display methods for different sprites then try to
group your sprites in such a way, that sprites with the same dis-
play method have continous indices. As an example: if the sprites
with (load)number 1 use one method and the ones with number 2
another, then the sequence SpriteN[]=(...2,2,2,2,2,...,1,1,1...)
would be better than (...2,2,1,2,...,1,2,...,1,2,...).
This is due to the fact that whenever ANIVGA has to draw a sprite
with a display method other than the active one, it must inter-
nally switch from one method to the other which costs some time.
See also : SetModeByte
StartVirtualX, StartVirtualY - variables
────────────────────────────────────────
Function : Specify the upper left corner of the visible world
Declaration: CONST StartVirtualX:INTEGER=0;
StartVirtualY:INTEGER=0;
Description: When working with virtual coordinates, your screen displays only
a very small window (320x200 points) of this "virtual screen"
(32000x32000 points). To tell ANIVGA which part of this virtual
screen is to be displayed, you specify the upper left corner of
the visible part in (StartVirtualX,StartVirtualY).
For example, setting (StartVirtualX,StartVirtualY) to (100,1000)
would define that the part of the virtual screen having x-coordi-
nates ε [100..100+XMAX] and y-coordinates ε [1000..1000+YMAX] to
be displayed.
Note : Setting these variables doesn't affect the HitDetect-function: if
two sprites collide outside the visible area, it will be detec-
ted, still.
See also : coordinates
Table - TYPE
────────────
Function : Supply a data type for the animation variables
Declaration: TYPE Table=ARRAY[0..NMAX] OF INTEGER;
Description: A lot of variables in ANIVGA have to be of type "one entry for
each sprite" and "Table" is the appropriate form for that.
Note : -
See also : SpriteX, SpriteY, SpriteN
Tile - information
──────────────────
"Tiles" are graphic images, 16 pixels wide and high. They are used to define a
scrollable background image when you use SCROLLING as background mode.
Due to memory limitations, it is impossible to hold a complete background
image in memory (because virtual coordinates range 32000 pixels in x/y-direc-
tions, one would need app. 977 MB (!) RAM for that).
Instead, you may define up to 256 different tiles and then combine them to
form the graphic background, which may consist of up to MaxTiles (=10000)
tiles (using the 256 different tiles).
(A simple example for that can be found by "Background").
ANIVGA stores tiles in a slightly different format then sprites internally,
but you don't have to bother your head about that: on disk, tiles have the
same format as sprites, so you can use all the utility programs to create/edit
sprites also to create/edit tiles! The only restriction you have to care about
is, that a tile has the definite size of 16 pixels in each direction (but see
the LoadTile()-function for some simplifications about even that).
See also : Background, LoadTile
TRANSLAT - utility
──────────────────
I hate doing work twice - that's why I have bought a PC! And it is the reason
why... a) I invented TRANSLAT
b) I'll just *cite* a few words from my own docs to TRANSLAT here:
>TRANSLATE is a (quite dumb) translation program. It reads in a Pascal source
>file, filters out all comments and tries to translate them into another
>language by using a database "dictionary". It then writes out a new Pascal
>file with the translated comments in it.
>TRANSLATE is thought for all those programmers among us, whose native tongue
>isn't English but who realized that this is the only universal language to
>publish programs. I think most of us don't have problems to write program
>docs and other accompanying texts in English. The problem lies within the
>program sources: the comments of a program should serve two purposes: help
>YOU, the author, to remember the thoughts you had when writing these lines
>of code and second, help OTHERS to understand your program.
>As being quite close to the thinking process in the human brain, I'm sure
>that most of us are not willing to write down their program comments other
>than in their native language! But when it comes to publish the program
>sources, you'd better have them in English, as this is the only universally
>understood language.
>
>Now you could maintain a second version of the program, identical to your
>original, but with all comments translated to English -- but >uaaah!< if you
>ever had to manage the consistency of two program versions of an evolving
>project, you _surely_ know that this is like putting the plagues back into
>Pandora's box!
>So why not setting up a database for your comments and then run a program
>which translates these comments? Well, TRANSLATE is exactly that program!
Creating such dictionaries doesn't have to concern you (not until you would
like to use it for your own sources; if so then drop me a note) -- just use
it:
TRANSLAT ANIVGA.PAS ANIVGA.NEW ANIVGA.DIC
...will create an English version of ANIVGA, named ANIVGA.NEW!
(It takes quite a long time (~1h) for this, so if you have a multitasking en-
vironment, then run it in the background!)
If everything worked and ANIVGA.NEW compiles ok, then you can use ANIVGA.NEW
to replace the German version ANIVGA.PAS (and delete TRANSLAT.EXE and
ANIVGA.DIC).
Note : - You can use _the same_ dictionary to translate ANIVGA V1.0, too
- I didn't publish the complete TRANSLAT-package til now; con-
sider the version included a "working α-version": it is just
intended for the above command line. You are free to experi-
ment with it, but if you ruin your system, don't say I didn't
warn you! B-p
UNLIB - utility
───────────────
Sometimes, you will want to reverse the process of building a sprite library,
that is: you want to split a sprite library into the sprite files of which it
consists.
To do that, call UNLIB with the name of the sprite library to split. UNLIB
will then create the files UNLIB000.COD, UNLIB001.COD, UNLIB002.COD,... which
represent the sprite files wanted.
Note here that UNLIB cannot restore the original filenames you used (there is
no such entry in a sprite's header). For that, it is a good idea to write down
the names and sequence of the sprite files used in building a sprite library.
(If you didn't, you still can load every extracted sprite with MAKES, look at
it and give it the right name then)
See also : sprite library, MAKES, sprite format
VIRTUAL COORDINATES - information
─────────────────────────────────
See : coordinates
WriteBackgroundPage - procedure
───────────────────────────────
Function : Saves the background image to disk
Declaration: PROCEDURE WriteBackgroundPage(name:STRING); FAR;
Description: This is merely a shortcut of the WritePage()-procedure (see
there), i.e. WritePage(name; BACKGNDPAGE) would do an equivalent
job.
Note : Possible ERROR-values returned are Err_FileIO
See also : WritePage
WritePage - procedure
─────────────────────
Function : Saves a graphic page to disk
Declaration: PROCEDURE WritePage(name:STRING; pa:BYTE); FAR;
Description: To save an image of one of the drawing pages (0 or 1) or the
backgroundpage BACKGNDPAGE (=2), specify the approriate page
number in "pa" and a valid MSDOS-path/name where to store the
data in "name".
Note : - Make sure that your disk has enough space to hold the data: one
page is stored as 64003 bytes!
- You can't use this procedure for saving the background page
"pa"=SCROLLPAGE in background mode SCROLLING!
- Possible ERROR-values returned are: Err_InvalidPageNumber and
Err_FileIO
See also : WriteBackgroundPage, LoadPage
XMAX - constant
───────────────
Function : Specifies the maximal absolute x-coordinate
Declaration: CONST XMAX=319
Description: XMAX is the biggest _absolute_ coordinate in the x-direction
which can be used: all x-coordinates must lie in the range
0..XMAX.
Note : Probably, you will never use this constant at all, because nearly
everything in ANIVGA's user interface works with _virtual_ coor-
dinates, but who can tell...
See also : YMAX, coordinates
XTiles - variable
─────────────────
Function : Holds the width of the scrollable background image in tiles
Declaration: VAR XTiles:INTEGER;
Description: When using background mode SCROLLING, you have to specify the
size of your scrolling background area (with the
SetBackgroundScrollRange()-procedure). ANIVGA adjusts these
values slightly and computes the size of the resulting background
image in tiles.
The width of this area (in tiles) is then stored in XTiles.
Notes : Don't change this variable directly!
See also : YTiles, Background, SetBackgroundScrollRange
YMAX - constant
───────────────
Function : Specifies the maximal absolute y-coordinate
Declaration: CONST YMAX=199
Description: YMAX is the biggest _absolute_ y-coordinate which may be used,
that is, every y-coordinate must lie in the range 0..YMAX.
Note : Probably, you will never use this constant at all, because nearly
everything in ANIVGA's user interface works with _virtual_ coor-
dinates, but who can tell...
See also : XMAX, coordinates
YTiles - variable
─────────────────
Function : Holds the height of the scrollable background image in tiles
Declaration: VAR YTiles:INTEGER;
Description: When using background mode SCROLLING, you have to specify the
size of your scrolling background area (with the
SetBackgroundScrollRange()-procedure). ANIVGA adjusts these
values slightly and computes the size of the resulting background
image in tiles.
The height of this area (in tiles) is then stored in YTiles.
Notes : Don't change this variable directly!
See also : XTiles, Background, SetBackgroundScrollRange