|
RPG's PROGRAMMING TUTORIAL:
FILE 1
Graphics: Creation and usage
Welcome to the new lesson of this tutorial !. Today
we'll learn the usage of graphics in our games. We've the tools (320x200x256),
so let's start painting! ^_^.
First we'll learn how to represent a prite in a
game. Next how can we edit sprites (before using it in the game) and save
them into HDD, and at least how to take the Sprite from HDD to memory.
I'll write routines in Pascal, but i think
that evebody can read them (Pascal is like PseudoCode).
NOTE: When I'll define techniques, the one who has
(STAR) is used in the Freeware game
I develop.
Before start
A.D.T. Sprite( What's a graphic for my program? )
Editing graphics and file formats
Reading graphics from Hard Disc
Source Code
PCX Format.
(Thanks to JASM-BMP, PC-Actual Magazine [Antonio
Ropero] and PCGPE for docs and routines)
PCX Format, developed by ZSoft Corporation, is one
of the easiest graphic formats and has a good compression ratio.
Like all graphic formats, has a Header, a Data Zone
and a Tail. Header has graphic info (128 bytes), Data has the graphic (obvious
^_^) and Tail has the palette.
Of Header, we want these items:
Source Code: In G320x200.PAS stays the procedure
MostrarPCX320x200 (ShowPCX320x200), where you can see everything implemented.
And in URLE.PAS stays the procedures RLE, RLEPCX y RLEOut, that implements
compression/decompression with RLE.
If you want to see the entire PCX header, look
at SWAG or PCGPE v1.0 .
A.D.T. Sprite ( WHAT'S A GRAPHIC FOR MY PROGRAM? )
First, we'll talk about representing sprites/graphics
in our programs.
NOTE: I've put this section here 'cause graphics
has almost the same form in memory and in HDD. (And here the structure
can be understand better).
Graphics like pointers and linked lists
In 320x200x256 mode, one pixel=one byte. So we can imagine a type Sprite that represents one Graphic/Sprite (people, house, scenario):
Type TSprite = Record
TamX,TamY:Word; (* Width and Height of the Sprite *)
PSprite:Pointer; (* PSprite^ = Sprite itself *)
End;
...where TamX and TamY means the Width and Height
of the Sprite, and PSprite is a pointer to a memory region sized (TamX*TamY)
that holds the Sprite itself. (1 pixel =1 byte) .[I. E.: a ball 4x4 pixels
() would be TamX=4, TamY=4,
PSprite^= [0,4,4,0, 4,12,4,4, 4,4,4,4, 0,4,4,0] ].
And a list of graphics will be a linked list with
sprites like elements:
Type PLSprite = ^LSprite;
LSprite = Record
Sprite:TSprite;
Next:PLSprite;
End;
I think Ultima 7: The Black Gate use this format
(looking at its file formats).
And of course this is optimal only when we're in
protected mode or/and in a linear memory O.S. (Unix, W95), 'cause if we
try to do this in real mode, sprites bigger than 64K pixels can't be created,
and we can only save a few sprites (we've the 640K barrier). One solution
is interpret PSprite like a pointer to an EMS bank. Or we can reserve a
big zone of XMS memory for all the sprites, and PSprite is a pointer to
the start of the sprite in XMS.
Sprites like arrays, and saved in group (STAR)
There's other option when all the sprites have the same size:
Type TSprite = Array [1..TAMX,1..TAMY] Of Byte (* Best: Array [1.. TAMX*TAMY] Of Byte *)
...where the sprite itself is in TSprite. [I.E.:
a ball 4x4 pixels ()
with TamX=4 and TamY=4 will be Sprite= [0,4,4,0, 4,12,4,4, 4,4,4,4, 0,4,4,0]
].
Like before, we can store the graphics like a linked
list or a predefined array. And also we can use EMS or XMS if we aren't
in protected mode.
NOTE: XMS is very slow in comparison with EMS. Think
on this.
Paint a sprite into the screen (STAR)
When we have the sprite stored on memory, we would want ^_^ to paint it. It's very easy to make:
(On pseudocode. Parameters: (IX,IY) -> coord.
where we want to put the sprite; Sprite -> self-explanatory)
For X=1 to Width_Sprite
For Y=1 to Height_Sprite
PutPíxel(IX+X,IY+Y,Sprite[X,Y]) (* Sprite[,] is the sprite itself
*)
EndFor
EndFor
NOTE: We can add some things to this put_sprite. One is add transparent checking (there are pixels in the sprite that aren't painted, if we find them don't exe the putpixel code), and the other is border checking (don't paint pixels off of the screen).
EDITING GRAPHICS AND FILE FORMATS
Well, we know now how to manage graphics in our programs. But before we need to edit them and save them in HDD. This is the section you need for these jobs.
Graphics in HDD: Making of
Every game needs graphics (SVGA 800x600 bitmaps or
poligons, modified characters in monochrome text mode,...). But there's
a question: We're those graphics ?. In HDD, of course ^_^.
The basic problem is how to edit them, and where
(Graphics don't appear from nothing ;)) ).
If you need a graphic that needs all the screen,
the thing is easy: make the graphic in any editor and save it in a format
you know how to read (PCX I. E.).
But things look worse if you want to save a sprite
or a picture larger than your graphical mode. Well, there're many solutions:
Well, here I'm going to comment a file format for having sprites with different sizes. It's a little dificult, but with the example i think you will understand::
(Based on DIV Games Studio's FPG File format)
Header: 3 Bytes of File-Type | 1 Byte of version.
Individual Graphic, Header:
1 LongInteger of ID_graphic (* Not needed, only if you need it *)
1 Word of graphic_width.
1 Word of graphic_height.
1 Word of Pointer_to_palette_file (* NOTE 1 *)
1 LongInteger of nș of bytes used for the graphic (* NOTE 2 *)
Individual Graphic, Data:
Graphic_Width*Graphic_Height Bytes(Pixels). (* NOTE 2 *)
Then, if i want to read the graphic number X, i must read all the graphics before X, reading the field nș of bytes used and advancing the read pointer consequently.
Example: RRC
0
(Graphic 0)
0 - 2 - 2 - 0 - 4 - 123 - 123 -123 -123
(Graphic 1)
1 - 1 - 3 - 0 - 3 - 123 - 12 - 39
I have two graphics. One is (2x2) and the other is (1x3). For read the 2ș graphic, i need to advance 14 bytes from the start of the file, read a Longinteger (is nș of bytes used=>4), advance 4 bytes, and now i'm in the start of the header of the 2ș graphic.
An improvement is to use a file that contains indexes
to every graphic, and access directly to the start of the header of the
graphic.
There're more improvements:
(Comes from NOTE 1)
We can have a file with palettes, and this word points to the palette that uses this sprite. |
(Comes from NOTE 2)
We can compress every sprite with RLE, so nș of bytes used
is not equal to Graphic_Width*Graphic_Height. We use nș
of bytes used for advancing in the file and for know the size of the
compressed graphic.
BTW, Ultima 7 has a very similar file format (sprites of different size with RLE). |
IMA File Format (STAR)
In the adjunct game, We write the sprites (20x20 sized) in PCX files. But after this, i save them in a format called IMA. Is very easy, and its format is:
(160 graphics in a file)
Graphic, Data: 400 bytes (pixels)
Sprites aren't compressed and there's no header and
tail. And graphics are stored lineally (First 400 bytes => First graphic;
Second 400 bytes => Second graphic;...).
Easy, huh ? ^_^
READING GRAPHICS FROM HARD DISC
This section is very, very simple. How to read one sprite X? Well...:
G320x200.PAS holds type Sprite and every PutSprite(PintaCasillas).
Type of IMA file format is only File.
In the game we read an entire IMA (64000 bytes)
and data is passed to a XMS handle (our sprites are stored in 64000 XMS
chuncks). When we want to read a sprite nș X, we take 400 bytes starting
from the byte 400*X of the XMS chunck.
Well, next one will be more CRPG dedicated: Tiles.
If you have some doubt, our mail is in every part
of this site ^_^.
See you soon !!