cpcrslib v.2
(Only English version of this text
will be maintained)
Español. Ojo. La
ayuda en español está obsoleta.
Amstrad CPC Library for z88dk.
Download last version (03/30/2009): cpcrslib
cpcrslib is a C library containing routines and functions that allow to the handling of sprites and tile-mapping in Amstrad CPC. The library is written to be used with z88dk compiler. cpcrslib also incorporates keyboard routines to redefine and to detect keys, as well as general routines to change to the screen mode or the colours.
So far, next games have been coded using cpcrslib:
Small Games for Smart Minds by ESP Soft.
Mariano The Dragon by ESP Soft.
Sort'em by LuBlu Entertainment.
Phantomas Thales #1: Marsport by The Mojon Twins.
Nanako Descens to Hell by The Mojon Twins.
News.
03/30/2009
cpc_ClrScr: Fills screen with ink 0 (similar to CLG)
cpc_DisableFirmware: Disables interruption jump from
&0038
cpc_EnableFirmware: Restores interruption jump
previously removed with cpc_DisableFirmware
cpc_PrintGphStrStd: New mode 1 8x8 pixel writing
routine, memory address
cpc_PrintGphStrStdXY: New mode 1 8x8 pixel writing
routine, (x,y) for positioning text
cpc_ShowTileMap: Modified. Removed EI/DI instructions
to avoid music/sound delays while showing tile Map.
cpc_RRI, cpc_RLI: Modified. There was a bug when using
IX.
cpc_ScanKeyboard: New routine for scanning whole
keyboard (from cpcwiki keyboard programming).
cpc_TestKeyF: New routine to test if a key has been
pressed but it must be used after cpc_ScanKeyboard. This way is faster than
previous one if 3 or more keys have to be tested.
cpc_WyzPlayer: Modified interruption backup because
previously it assumed it was a JP XXXX jump and sometimes is not correct.
Example disc included: All the code examples compiled
and ready to run in a single disk.
03/23/2009
cpc_RRI: Moves a screen rectangle one byte to the left
(<-), most left byte goes to the right side (no byte info lost)
cpc_RLI: Moves a screen rectangle one byte to the
right (->), most left byte goes to the left side (no byte info lost)
cpc_TouchTiles: New
routine to set a tile rectangle as touched in order to be shown in the next
cpc_ShowTouchedTiles call.
02/23/2009
cpc_GetTiles, cpc_PutTiles: New routines to capture
into a buffer a tile map area and to copy from buffer to tile map.
02/22/2009
cpc_UpdScr: Routine has been modified in order to get
faster code.
cpc_PutCpTileMapo2b:
New routine to draw compiled sprites into the map tile.
02/20/2009
Multiplication routine almost always can be
substituted by a specific faster one. Routines were generic multiplication is
used can be fast changed modifying code in multiplication1.asm and
multiplication2.asm before compiling the library. Using optimized
multiplication routines gets better performance in the program so it’s
recommended to use them.
02/19/2009
cpc_PutSpTileMap: Code optimized, smaller and faster. Now tiles
touched by a sprite are found faster.
02/16/2009
cpc_PutTrSpriteTileMap2b:
New routine similar to cpc_PutTrSpTileMap2b but without the internal buffer
address calculation, it requires use of cpc_SpUpdX and cpc_SpUpdY to update the
sprite position or by the normal way but using cpc_SuperbufferAddress() after
x,y update.
cpc_UpdateTileMap:
Update to include cpc_PutTrSpTileMap2 and cpc_PutTrSpriteTileMap2 routines.
02/11/2009
cpc_ScrollLeft0,
cpc_ScrollLeft, cpc_ScrollRight0, cpc_ScrollRight: New routines for software
scroll using tile map. (See example included in file)
02/09/2009
cpc_PutTrSpTileMap2b:
Draws a sprite using one of the colours as transparent. It requires selecting
transparent colour during compilation. (See example included in file)
01/16/2009
cpc_TestKey
: Code optimized, smaller and faster.
cpc_RedefineKey:
Code optimized, smaller and faster.
cpc_AnyKeyPressed:
Rewritten, smaller and faster.... previous version doesn't work.
cpc_SetBorder:
Changed caller function, now it's smaller and faster routine.
cpc_InitTileMap:
Changed caller function, now it's smaller and faster routine.
05/21/2008
New
uncruch routine: Exomizer. Z80 code by Metalbrain, compression algorithm by
Magnus Lind. Exomizer crunch files more than pucrunch does.
03/12/2008
Minor
changes in tile map sprite drawing: The superbuffer address is updated during
the drawing.
02/28/2008
New
function added: it make all the steps in the sprite drawing when drawing in a
tile map. cpc_UpdateTileMap(spriteList). Small sprite demo sample modified to
support this new function.
02/21/2008
Touched
tiles code modified, now it’s only required to modify the table in
TileMapConf.asm file.
02/16/2008
New
functions added
cpc_SetInkGphStr(char colour, char value) Set text char colours in mode 0. It replaces cpc_SetColorGphStr.
cpc_SetInkGphStrM1(char colour, char value) Set text char colours in mode 1.
cpc_PutMaskSpriteTileMap2b(sprite) Previously this routine was
cpc_PutSpTileMap2b, renamed.
cpc_PutSpTileMap2b( sprite) Draws an unmasked
sprite in a tile map.
02/13/2008
New
functions added
cpc_PutTile4x16(int *tile, char *x, char *y) Draw
4x16 tiles directly in the screen
cpc_AnyKeyPressed() If a key
is pressed it returns 1 else returns 0.
cpc_SetColorGphStr(char colour, char value) Set text char colours in mode 0.
And some bugs corrected in mode 0 text routines.
Specs.
Routines and functions.
A sprite is a two-dimensional image that can be drawn everywhere in the screen as many times as wanted. The next routines put sprites in the screen by several drawing methods.
This is the sprite data used in the examples:
|
extern
char sprite[]; extern
char sprite_sd[]; extern
char sprite_mask0[]; extern
char sprite_mask[]; #asm ._sprite defb 2,2
// width, height ._sprite_sd defb $ff,$ff //sprite data defb $ff,$ff ._sprite_mask0 defb 2,2 ._sprite_mask defb &ff,0,&ff,0 defb &ff,0,&ff,0 #endasm |
And this is the sprite structure used in the routines:
|
struct
st_sprite { // minimun sprite
structure to be used in sprite functions. int sp0; //2 bytes: sprite data 0-1 int
sp1; //2 bytes: previos
sprite data 2-3 int
coord0; //2 bytes: superbuffer address 4-5 int
coord1; //2 bytes: previouse
superbuffer address 6-7 unsigned
char cx, cy; //2 bytes: sprite
cordinates 8-9 unsigned
char ox, oy; //2 bytes: previous
sprite cordinates 10-11 unsigned
char pm; //1 byte: sprite printing
method. 12 unsigned
char move; // 13 } ; |
|
|
The sprite data is divided in two parts: The first one is two bytes representing the sprite dimension in bytes (if it is a masked sprite, the dimensions are the same as if it were an unmasked sprite).
The second one is the sprite data; it is a serial of bytes that represent the sprite in the way the CPC screen understands.
|
cpc_PutSp void cpc_PutSp(int
*sprite, char *height, char
*width, int *address) Puts the sprite in the specified address. The sprite dimensions are in the call parameters, not in the sprite data. Parameters: sprite: Sprite data (without dimensions) height : sprite height width: sprite width address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutSpTr, cpc_PutMaskSp, cpc_PutSpXOR Example:
|
|
cpc_PutSpXOR void cpc_PutSpXOR(int
*sprite, char *height, char
*width, int *address) Puts the sprite in the specified address, using XOR method with the screen byte. The sprite dimensions are in the call parameters, not in the sprite data. Parameters: sprite: Sprite data (without dimensions) height : sprite height width: sprite width address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutSpTr, cpc_PutMaskSp, cpc_PutSp Example:
|
|
cpc_PutMaskSp void cpc_PutMaskSp(int *sprite, char
*height, char *width, int
*address) Puts a masked sprite in the screen, the first byte is the mask data, the second the sprite data. The sprite dimensions are in the call parameters, not in the sprite data. Parameters: sprite: Sprite data (without dimensions) height : sprite height width: sprite width address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutSpTr, cpc_PutSpXor, cpc_PutSp Example:
|
|
cpc_PutSpTr void cpc_PutSpTr(int
*sprite, char *height, char
*width, int *address) Puts mode 0 sprite taking into account that colour number 0 is transparent so the background is shown. Parameters: sprite: Sprite data (without dimensions) height : sprite height width: sprite width address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutMaskSp, cpc_PutSpXOR, cpc_PutSp Example:
|
|
cpc_PutSprite void cpc_PutSpTr(int
*sprite, int *address) Puts the sprite in the specified address. The sprite dimensions are in the sprite data. Parameters: sprite: Sprite data including width and height. address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutMaskSprite, cpc_PutSpriteXOR Example:
|
|
cpc_PutMaskSprite void cpc_PutMaskSprite(int *sprite, int
*address) Puts a masked sprite in the specified address. The sprite dimensions are in the first and second sprite bytes. Next bytes are the mask and the sprite bytes alternatively. Parameters: sprite: Sprite data including width and height. address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutSprite, cpc_PutSpriteXOR Example:
|
|
cpc_PutSpriteXOR void cpc_PutSpriteXOR(int *sprite, int
*address) Puts the sprite in the specified address, using XOR method with the screen byte, sprite dimensions are in the sprite data. Parameters: sprite: Sprite data including width and height. address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutSprite, cpc_PutMaskSprite Example:
|
|
cpc_PutMaskSp2x8 void cpc_PutMaskSp2x8(int *sprite, int
*address) Puts a 2x8 bytes masked sprite in the specified address. The sprite has not the dimensions in its data definition. The porpoise of this routine in provide a faster method for drawing 2x8 sprites. Parameters: sprite: Sprite data including width and height. address: screen address where the sprite will be drawn Returns: Draws the sprite
in the specified address. See also: cpc_PutMaskSp4x16 Example:
|
|
cpc_PutMaskSp4x16 void cpc_PutMaskSp4x16(int *sprite, int
*address) Puts a 4x16 bytes masked sprite in the specified address. The sprite has not the dimensions in its data definition. The porpoise of this routine in provide a faster method for drawing 4x16 sprites. Parameters: sprite: Sprite data including width and height. address: screen address where the sprite will be drawn Returns: Draws the
sprite in the specified address. See also: cpc_PutMaskSp2x8 Example:
|
|
cpc_GetSP void cpc_GetSp(int *buffer, char height, char width, int *origin) Captures a screen area starting from origin and sized by width and height and copy it to buffer. Parameters: buffer: captured data destination. height: capture height. width: capture width. origin: capture starting address. Returns: See also: Example:
|
|
cpc_CollSp char cpc_CollSp(struct
sprite0, struct sprite1) Test if two sprites are colliding. Parameters include the position of the sprites and the sprites. Parameters: sprite0: sprite structure sprite1: sprite structure Returns: Return 1 if
both sprites are colliding, 0 if not colliding. See also: Example:
|
|
cpc_SpRRM1 void cpc_SpRRM1(int *sprite) Rotate to the right a mode 1 sprite. Parameters: sprite: sprite data with dimensions. Returns: See also: cpc_SPRLM1 Example:
|
|
cpc_SpRLM1 void cpc_SpRLM1(int *sprite) Rotate to the left a mode 1 sprite. Parameters: sprite: sprite data with dimensions. Returns: See also: cpc_SPRLM1 Example:
|
Tiles
Tiles are fixed elements in the screen, usually for map drawing. There are some specific routines for tiles, but the sprite routines can be used in the same way for drawing tiles.
|
cpc_PutTile2x8 void cpc_PutTile2x8(int *tile, char
x, char y) Puts the 2x8 bytes tile in the specified address given in x,y coordinates. Parameters: tile: Tile data without dimensions. x: screen coordinate y: screen coordinate Returns: Draws the sprite
in the specified address. See also: cpc_PutTile4x16 Example:
|
|
cpc_PutTile4x16 void cpc_PutTile4x16(int *tile, char
x, char y) Puts the 4x16 bytes tile in the specified address given in x,y coordinates. Parameters: tile: Tile data without dimensions. x: screen coordinate y: screen coordinate Returns: Draws the
sprite in the specified address. See also: cpc_PutTile2x8 Example:
|
General example about sprites (from masked sprite sample)
|
#include "cpcrslib.h" extern unsigned char sp_8x8[]; extern unsigned char sp_16x16[]; extern unsigned char tile_8x8[]; extern unsigned char buffer[]; #asm ._sp_8x8 defb $88,$70,$11,$E0 //MASK, SPRITE, MASK, SPRITE... Mask is drawn using highest ink
number defb $11,$E0,$88,$70 defb $00,$96,$00,$96 defb $00,$F0,$00,$F0 defb $00,$F7,$00,$FE defb $00,$C7,$00,$3E defb $00,$F3,$00,$FC defb $88,$70,$11,$E0 ._sp_16x16 defb $88,$70,$11,$E0,$88,$70,$11,$E0 //MASK, SPRITE, MASK, SPRITE... defb $11,$E0,$88,$70,$11,$E0,$88,$70 defb $00,$96,$00,$96,$00,$96,$00,$96 defb $00,$F0,$00,$F0,$00,$F0,$00,$F0 defb $00,$F7,$00,$FE,$00,$F7,$00,$FE defb $00,$C7,$00,$3E,$00,$C7,$00,$3E defb $00,$F3,$00,$FC,$00,$F3,$00,$FC defb $88,$70,$11,$E0,$88,$70,$11,$E0 defb $88,$70,$11,$E0,$88,$70,$11,$E0 defb $11,$E0,$88,$70,$11,$E0,$88,$70 defb $00,$96,$00,$96,$00,$96,$00,$96 defb $00,$F0,$00,$F0,$00,$F0,$00,$F0 defb $00,$F7,$00,$FE,$00,$F7,$00,$FE defb $00,$C7,$00,$3E,$00,$C7,$00,$3E defb $00,$F3,$00,$FC,$00,$F3,$00,$FC defb $88,$70,$11,$E0,$88,$70,$11,$E0 ._tile_8x8 defb $07,$0E //Unmasked defb $2D,$C3 defb $0F,$2D defb $0F,$2D defb $0F,$0F defb $0F,$2D defb $0F,$0F defb $07,$0E ._buffer defs 64 #endasm main(){ cpc_SetMode(1); //mode change.
The interrupt standard jump must be disabled. cpc_SetModo(1); //Firmware routine for mode changing. cpc_SetColour(17,11); //Ink change using hardware. The interrupt
standard jump must be disabled. cpc_SetInk(17,11); //Ink change using firmware. // Put a 2x8
bytes sprite in specified coordinates cpc_PutTile2x8(tile_8x8,10,90); // Put a 2x8
bytes masked sprite into the specified screen address (&C00B) cpc_PutMaskSp2x8(sp_8x8,0xc00b); // Same but
using a 4x16 bytes sprite cpc_PutMaskSp4x16(sp_16x16,0xc190); // This routine is for using in mode 0
due to it uses ink 0 as transparent. cpc_PutSpTr(tile_8x8,8,2,0xc19b); // Put a sprite
of specified dimensions into screen. cpc_PutSp(tile_8x8,8,2,0xc19b); // Captures a screen box of the
specified dimensions and stores it onto memory cpc_GetSp(buffer,8,8,0xc054); // In this
example, prints the captured area in &c190 cpc_PutSp(buffer,8,8,0xc190); while (1){} //Repeat until the end of the world } |
The library has been compiled in order to have 12 different keys available. If more keys are needed, modifying it is quite simple only space for key assignation is required in cpc_KeysData.
|
cpc_RedefineKey void cpc_RedefineKey(char number) Waits until a key is pressed and assigns it to the key number specified Parameters: number: Key number to be assigned Returns: See also: cpc_AssignKey Example:
|
|
cpc_AssignKey void cpc_AssignKey(char number, int
value) Assign a key to the specified key number. Parameters: number: Key number to be assigned value: Represents a key so must be selected from correct values in order to work correctly. Values must be taken from the keyboard table. Returns: See also: cpc_RedefineKey Example:
|
|
cpc_TestKey char cpc_TestKey(char
number) Tests if the key assigned to selected number has been pressed. Parameters: number: Key number to be checked Returns: Returns 1 if key assigned to number is pressed else return 0. See also: cpc_AnyKeyPressed, cpc_TestKeyF Example:
|
|
cpc_AnyKeyPressed char cpc_AnyKeyPressed(void) Tests if any key has been pressed. Parameters: Returns: Returns 1 if any key has been pressed else return 0. See also: cpc_TestKey, cpc_TestKeyF Example:
|
|
cpc_ScanKeyboard void cpc_ScanKeyboard(void) Scan entire keyboard and stores all keys pressed. Parameters: Returns: See also: cpc_TestKeyF Example:
|
|
cpc_TestKeyF char cpc_TestKeyF(char
number) Tests if the key assigned to selected number has been pressed. Use it after cpc_ScanKeyboard. This pair of routines is recommended when 3 or more keys must be checked. It’s recommended in order to decrease the execution time. Parameters: number: Key number to be checked Returns: Returns 1 if key assigned to number is pressed else return 0. See also: cpc_AnyKeyPressed, cpc_ScanKeyboard, cpc_TestKey Example:
|
Keyboard table (source: cpcwiki)
|
Byte: |
&80 |
&40 |
&20 |
&10 |
&08 |
&04 |
&02 |
&01 |
|
&40 |
F Dot |
ENTER |
F3 |
F6 |
F9 |
CURDOWN |
CURRIGHT |
CURUP |
|
&41 |
F0 |
F2 |
F1 |
F5 |
F8 |
F7 |
COPY |
CURLEFT |
|
&42 |
CONTROL |
\ |
SHIFT |
F4 |
] |
RETURN |
[ |
CLR |
|
&43 |
. |
/ |
: |
; |
P |
@ |
- |
^ |
|
&44 |
, |
M |
K |
L |
I |
O |
9 |
0 |
|
&45 |
SPACE |
N |
J |
H |
Y |
U |
7 |
8 |
|
&46 |
V |
B |
F |
G |
T |
R |
5 |
6 |
|
&47 |
X |
C |
D |
S |
W |
E |
3 |
4 |
|
&48 |
Z |
CAPSLOCK |
A |
TAB |
Q |
ESC |
2 |
1 |
|
&49 |
DEL |
- |
- |
- |
- |
- |
- |
- |
Example about keyboard managing (from keyboard sample)
|
#include
"cpcrslib.h" main(){ cpc_SetModo(1);
//Set mode using firmware cpc_PrintStr("Press key to
redefine"); //Show text using
firmware cpc_RedefineKey(0); //redefine key. cpc_PrintStr("Press key to test
it"); while (1) { if (cpc_TestKey(0)==1) { //test if the key has been pressed. cpc_PrintStr("ok"); } } } |
Another example using alternative testing routines
|
#include
"cpcrslib.h" main(){ cpc_SetModo(1);
//Set mode using firmware cpc_PrintStr("Press key to
redefine"); //Show text using
firmware cpc_RedefineKey(0); //redefine key. cpc_PrintStr("Press key to test
it"); while (1) { cpc_ScanKeyboard(); if (cpc_TestKeyF(0)==1) { //test if the key has been pressed. cpc_PrintStr("ok"); } } } |
|
|
Two routines have been included in order to support compressed files by Pucrunch and Exomizer compressors.
|
cpc_Uncrunch void cpc_Uncrunch(int
origin, int destination) Uncompress a pucrunch compressed file. Parameters: origin: address of the compressed data. destination: address where the data will be uncompressed Returns: See also: cpc_UnExo Example:
|
|
cpc_UnExo void cpc_UnExo(int
origin, int destination) Uncompress a exomizer compressed file Parameters: origin: address of the compressed data. destination: address where the data will be uncompressed Returns: See also: cpc_Uncrunch Example:
|
Example about uncrunching file (from pucrunch sample)
|
#include "cpcrslib.h" extern unsigned char binary_data[]; #asm ._binary_data BINARY
"tonteria.pu" //includes a
pucrunch file #endasm main(){ cpc_SetModo(1); cpc_Uncrunch(binary_data,0xc000); while (1) {} } |
Note:
In the cpcrslib pack windows executable
files to compress from a DOS box are included. Syntax:
pucruch -d -c0 filein
fileout
exo filein fileout
Fileout
is the file to incluye in the C program to be uncompressed by cpcrslib.
These routines allow text writing in a screen position (in mode 0 or mode 1)
Mode 0:
cpc_PrintGphStr("HI;BOY<",0xc190); // specifying screen address
cpc_PrintGphStrXY("BYE;GUY<",20,100); //screen coordinates x,y
cpc_SetInkGphStr(char colour, char value); // Set text char colour in mode 0. Each char is defined up to 4 colours (0..3), values for a nice result are:
|
0 |
2 |
8 |
10 |
32 |
34 |
40 |
42 |
128 |
130 |
136 |
138 |
160 |
162 |
168 |
170 |
Mode 1:
cpc_PrintGphStrM1("HI;BOY <",0xc190); //specifying screen address
cpc_PrintGphStrXYM1("BYE;GUY <",20,100); //screen coordinates x,y
cpc_SetInkGphStM1r(char colour, char value); // Set text char colour in mode 1. Each char is defined up to 4 colours (0..3). ), values for a nice result are:
0, 8,
128, 136
Each character is 4x8 pixels and can be modified in cpc_Chars.asm file and compiling the library.
Mode Selection
cpc_SetMode(mode) //Hardware routine. It requires disabling the Standard jump of the interruption.
cpc_SetModo(mode) // firmware routine
Ink change:
cpc_SetColour(ink number, hardware colour) //Hardware routine. It requires disabling the Standard jump of the interruption.
//firmware:
cpc_SetBorder(colour)
cpc_SetInk(ink number, colour)
cpc_GetScrAddress(x,y) //returns the x,y coordinates screen address. For example: cpc_ScrAdress(0,0) -> &C000
//Rotation routines
cpc_RLI(screen
rectangle origin, width, height)
cpc_RRI(screen
rectangle origin, width, height)
|
#include "cpcrslib.h" void main (void) { while (1){ cpc_RRI(0xc050+8,10,50); cpc_RLI(0xc050+50,10,50); } } |
Almost all the library routines are in the included examples.
This library cpcwyzlib includes a sound player coded by WYZ. Don’t forget compiling with –lcpcwyzlib.
Tracker available at: WYZTracker in CPCWiki There are threads about it in a Spanish forum: Amstrad.es Forum WYZTracker thread and in CPCWiki forum: CPCWiki thread
cpc_WyzInitPlayer(SOUND_TABLE RULE_TABLE, EFFECT_TABLE, SONG_TABLE); //Configure the placer with required data
cpc_WyzSetBuffer(int buffer); //Set music buffer. Must be done before loading and playing any song.
cpc_WyzLoadSong(0); //select song number
cpc_WyzSetPlayerOff(); //stop music and sound
cpc_WyzSetPlayerOn(); //activate music and sound
cpc_WyzStartEffect(2,1); //play a sound effect #1 in channel 2
Tracker can be used to make music for the WYZPlayer but not to make sound effects (SFX), however SFX format is quite simple:
defb
byte1,byte2
defb
byte1,byte2
...
defb
&ff
Where byte 1 and bits 7, 6, 5 & 4 from byte2 are the sound frequency and bits 3, 2, 1 & 0 of byte2 is the amplitude. Effect finishes when &ff is found.
List of functions and routines:
cpc_UpdScr()
cpc_UpdScrAddresses()
cpc_ShowTileMap(z)
cpc_SetTile(tx,ty,tile)
cpc_SetTouchTile(tx,ty,tile)
cpc_ReadTile(tx,ty)
cpc_TouchTileXY(x,y)
cpc_ShowTouchedTiles()
cpc_PutSpTileMap(struct
sprite)
cpc_PutTrSpTileMap2b(sprite)
cpc_PutTrSpriteTileMap2b(sprite)
cpc_PutMaskSpTileMap2b(sprite)
cpc_PutMaskSpriteTileMap2b(sprite)
cpc_PutORSpTileMap2b(sprite)
cpc_PutCpTileMapo2b(sprite)
cpc_SuperbufferAddress(x,y)
cpc_ResetTouchedTiles()
cpc_SpUpdX(struct
sprite, value)
cpc_SpUpdY(struct
sprite, value)
cpc_ScrollRight0();
cpc_ScrollLeft0();
cpc_ScrollRight();
cpc_ScrollLeft();
cpc_GetTiles(x,y,w,h,buffer);
cpc_PutTiles(x,y,w,h,buffer);
cpc_TouchTiles(x,y,w,h);
How to use the tile map routines.
A little
bit of theory.
This routines allow to draw and to move sprites in the screen without blinking and regenerating the background. Sprites can be of whatever dimensions, and can be whatever number of them, but is necessary to consider that the capacities of the CPC are limited and the bigger and the more sprites in the screen, the CPC will require more time to draw them.
Tile are of 2x8 bytes (width x height). The maximum definable are is 40x20 tile, depending on the screen mode this will be 320x160 pixels ( mode 1) or 160x160 pixels (mode 0).
The tiles and the sprites are drawn in a buffer area call superbuffer. The visible screen is updated from this superbuffer.
The superbuffer, in used memory would be 40x2x160 bytes=12800 bytes (&3200) at the most. By default, the beginning of the superbuffer is located at &100 and would arrive at the most until &3300 (&3200+&100). It is important to have this into account to put the beginning of the program code over the superbuffer, if no, when using it, it will crash giving unexpected results in the execution.
Steps drawing a tile map in the screen:
1. Set the map tiles. The map is a matrix (10x5 tile example):
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
2. Send whole superbuffer to the visible screen.
Representing a sprite requiere next steps:
1. Look up the tiles touched by the sprite in its present position and in its previous one (phase 1). These tiles are the touched tiles.
2. Supperbuffer touched tiles are updated to clear its last state.
3. The sprites are drawn in superbuffer (phase 2)
4. Touched tiles are sent to the visible screen. The sprite is shown in its new position.
There are two kinds of coordinates: Tile coordinates (tx.ty) and screen coordinates(x,y). The first ones refer to the tile map (see example above) and the screen coordinates refer to the pixel (better, the byte) of the sprite in superbuffer.
For example, (x,y)=(10,10) points somewhere in the red tile of the sample map.
(tx,ty)=(2,3) is the blue tile of the sample map.
Now,
a little bit of practise:
Defining screen:
1º Set each map tile:
cpc_SetTile(x,y,tile);
This code defines the example map:
void draw_tilemap(void) {
unsigned char x,y;
y=0;
for(x=0; x<10;x++) {
cpc_SetTile(x,y,1);
}
for(y=1;y<4;y++) {
for (x=0;
x<10;x++) {
cpc_SetTile(x,y,0);
}
}
y=4;
for (x=0; x<10;x++)
{
cpc_SetTile(x,y,2);
}
}
2º. Show entire map screen:
cpc_ShowTileMap(0);
Having defined the screen, we can put sprites on it.
The next structure is mandatory to define the sprites:
struct sprites{
int sp0; //2
bytes Current Sprite
int sp1; //2
bytes Previous Sprite
int coord0; //2
bytes superbuffer address
int coord1; //2
bytes Previous superbuffer address
unsigned char cx,
cy; //2 bytes Current coordinates
unsigned char ox,
oy; //2 bytes Previous coordinates
unsigned char move; //Not
yet implemented.
}
If new fields are required, they will be added at the end of the structure.
To initialise a sprite, these are the fields to be filled:
• sp0 (current sprite data)
• sp1 (current sprite data the first time)
• ox
• oy
• cx
• cy
Now the sprites can be drawn maintaining the background.
En un ciclo de
movimiento, lo primero que hay que hacer es resetear la tabla de tiles tocados
(los últimos que se han traladado a la pantalla visible):
cpc_ResetTouchedTiles();
Draw and move sprites is a 4 steps cycle:
1. All the sprites to superbuffer (phase 1)
cpc_PutSpTileMap(sprite00);
cpc_PutSpTileMap(sprite01);
...
(This update the touched tile table to be restablished later)
To update a tile during the sprite movement cycle:
cpc_SetTile(tx,ty,tile);
cpc_TouchTileXY(tx,ty); //mete el
tile en la tabla de tiles tocados para restaurarlos
Or making the previous two functions in just one call:
cpc_SetTouchTile_xy(tx,ty,tile)
2. Clear superbuffer (where the sprites are):
cpc_UpdScr();
3. Drawing the sprites in superbuffer (Phase 2)
cpc_PutMaskSpTileMap2b(sprite00);
cpc_PutORSpTileMap2b(sprite01);
...
4. Finally, all the touch tiles are sent to the visible screen:
cpc_ShowTouchedTiles();
That all!
There is several options to draw sprites in superbuffer:
cpc_PutMaskSpTileMap2b(): draw a masked sprite
cpc_PutTrSpTileMap2b(): draw an sprite using one o its colours as transparent. It requires two parameters to be included in compilation time: mascara1 & mascara2. See TileMapConf.asm
cpc_PutORSpTileMap2b draw an unmasked sprite doing OR operation.
cpc_PutSpTileMap2b(): draw a unmasked sprite
cpc_ReadTile(tx,ty) return the tile number of the tile map spicified by (tx,ty)
Other way of moving sprites is with the following routines:
cpc_SpUpdX(struct sprite, value) // move sprite left (<0) or
right (>0) in the value quantity
cpc_SpUpdY(struct sprite, value) // move sprite up (<0) or down (>0) in the value quantity
cpc_PutMaskSpriteTileMap2b(struct sprite) // puts the masked sprite in the tile map, it’s faster than cpc_PutMaskSpTileMap2b but requires to move sprite with the functions cpc_SpUpdX or cpc_SpUpdX, there is an example in small_sprite_demo.c file.
cpc_PutTrSpriteTileMap2b(struct sprite): // puts the masked sprite in the tile map, it’s faster than cpc_PutTrSpTileMap2b but requires to move sprite with the functions cpc_SpUpdX or cpc_SpUpdX,
cpc_UpdateTileMap(listaSprites) // it includes all the functions to draw sprites in the screen in a single function. This function makes previously defined steps without
cpc_SetTile(tx,ty,tile), cpc_TouchTileXY(tx,ty) y cpc_SetTouchTileXY(tx,ty,tile) functions that will be called before cpc_UpdateTileMap() and after cpc_ResetTouchedTiles().
The parameter is a list of the sprites that
are going to be drawn. Last
element of the list must be 0xffff.
int
spriteList[10];
spriteList[0]=sprite00;
...
sprite[n]=0xffff; //last element
On the other hand, the control of if sprite draws or recovers its background does with the value move of the structure of sprites. So that is made first stage the program pays attention to bit 0 of move. If it is 0 is not executed, if it is 1, is executed.
In order to see if sprite is drawn in the map of tiles, code pays attention to
bits 1, 2 and 3 of move. If they are
000 not draws sprite. The remaining
values are:
001 -> cpc_PutMaskSpriteTileMap2b
010 -> cpc_PutMaskSpTileMap2b
011 -> cpc_PutORSpTileMap2b
100 -> cpc_PutSpTileMap2b
101 -> cpc_PutTrSpTileMap2
110 ->
cpc_PutTrSpriteTileMap2
For example, I want to draw sprite00 with the last function all the short
while, and that always recovers its bottom: the value move would be
sprite00.move=9;
If sprite does not move of its site, it is enough drawing it without recovering
its background:
sprite00.move=8; //00001000
If I want to recover the background but that sprite is not drawn (for example,
to make disappear sprite that before was drawn):
sprite00.move=1; //00000001
And so on.
Scrolling
routines
4 new functions have been added to have horizontal software scroll. These are not enhanced scrolling routines and maybe are not very usefull but they can be used to make some kind of effects. Each step scrolls a tile to the left or to th right. Scrolling consists in two steps:
1.
Moving background tile map with
cpc_ScrollLeft0() or
cpcScrollRight0(). Before doing this step, tile map updating is
mandatory because the left or the right column has been moved (or deleted) and
it’s time to update it with new screen information.
2.
Scrolling visible area with cpc_ScrollLeft() or
cpcScrollRight(). This step get the new left or right tile column and
draw it on visible screen before scrolling.
It has been included a new example using scroll: see scroll_transparent folder.
For scrolling is needed the left column of the screen to be defined in TileMapConf.asm file.
Tile
Map Capturing
cpc_GetTiles(unsigned char x, unsigned char y, unsigned
char w, unsigned char h, int buffer)
Captures tiles in area defined by x,y,w,h and stores them into buffer
For example:
|
Int
buffer[6]; cpc_GetTiles(1,4,2,3,buffer); |
Captures and stores into buffer a rectangle defined by x=1, y=4 and width=2 and height=3. Capture next tiles (1,4),(1,5), (2,4),(2,5), (3,4),(3,5)
cpc_PutTiles(unsigned char x, unsigned char y, unsigned
char w, unsigned char h, int buffer)
Read buffer for tiles and set tile map from them:
For example:
|
Int
buffer[6]; cpc_PutTiles(1,4,2,3,buffer); |
Sets next tiles (1,4),(1,5), (2,4),(2,5), (3,4),(3,5) from buffer.
TileMapConf.asm
This file is the configuration file of the tile map:
Buffer address
Visible screen address
Tile data
Tile map dimension…
It has to be linked during the compilation (take a look at the tile examples make.bat file)
XLIB TileMapConf
XDEF tiles
XDEF pantalla_juego
XDEF tiles_tocados
XDEF posiciones_pantalla
XDEF
posiciones_super_buffer
XDEF posicion_inicial_area_visible
XDEF
posicion_inicial_superbuffer
XDEF ancho_pantalla_bytes
XDEF alto_pantalla_bytes
XDEF
ancho_pantalla_bytes_visible
;
***************************************************
;
Transparent colour for cpc_PutTrSpTileMap2b/ cpc_PutTrSpriteTileMap2b routine
XDEF mascara1
XDEF mascara2
;
***************************************************
;XDEF tile
;
***************************************************
; Scroll
Left Addresses column
; not
requiered if scroll not used
XDEF
ColumnScr
; ***************************************************
;
***************************************************
;
Transparent colour for cpc_PutTrSpTileMap2b routine
; For
printing sprites using transparent color (mode 0) transparent color selection
is requiered.
; Selección color
transparente. Escribir las 2 máscaras que correspondan al color elegido.
;Example colour number 7:
defc mascara1 = $54
defc mascara2 = $a8
;0: $00,
$00
;1: $80,
$40
;2: $04,
$08
;3: $44,
$88
;4: $10,
$20
;5: $50,
$A0
;6: $14,
$28
;7: $54,
$A8
;8: $01,
$02
;9: $41,
$82
;10: $05,
$0A
;11: $45,
$8A
;12: $11,
$22
;13: $51,
$A2
;14: $15,
$2A
;15: $55,
$AA
;
***************************************************
;------------------------------------------------------------------------------------
; SCREEN AND BUFFER ADDRESSES
;------------------------------------------------------------------------------------
defc posicion_inicial_area_visible = $c050 ;Begin of the screen area
defc posicion_inicial_superbuffer = $100 ;Begin of the superbuufer (2x8xT_WIDTHxT_HEIGHT bytes)
;------------------------------------------------------------------------------------
;------------------------------------------------------------------------------------
; TILE MAP DIMENSIONS
;------------------------------------------------------------------------------------
defc T_WIDTH = 32 ;max=40 tiles
defc T_HEIGHT = 16 ;max=20 tiles
;------------------------------------------------------------------------------------
;------------------------------------------------------------------------------------
; Other parameters
(internal use)
;------------------------------------------------------------------------------------
;------------------------------------------------------------------------------------
; El ancho de pantalla
influye determinantemente en numerosas rutinas que hay que actualizar si se
cambia.
defc ancho_pantalla_bytes
= 2*T_WIDTH ;Cada tile es de 2
bytes de ancho.
defc alto_pantalla_bytes
= 8*T_HEIGHT ;Cada
tile es de 8 bytes de alto.
defc
ancho_pantalla_bytes_visible = 2*T_WIDTH
;dentro del area definida,
cuánto se debe mostrar.
.TileMapConf
;------------------------------------------------------------------------------------
.posiciones_pantalla ;Posiciones
en las que se dibujan los tiles
defw
posicion_inicial_area_visible+$50*0
defw
posicion_inicial_area_visible+$50*1
defw posicion_inicial_area_visible+$50*2
defw
posicion_inicial_area_visible+$50*3
defw
posicion_inicial_area_visible+$50*4
defw
posicion_inicial_area_visible+$50*5
defw
posicion_inicial_area_visible+$50*6
defw
posicion_inicial_area_visible+$50*7
defw posicion_inicial_area_visible+$50*8
defw
posicion_inicial_area_visible+$50*9
defw
posicion_inicial_area_visible+$50*10
defw
posicion_inicial_area_visible+$50*11
defw
posicion_inicial_area_visible+$50*12
defw
posicion_inicial_area_visible+$50*13
defw posicion_inicial_area_visible+$50*14
defw
posicion_inicial_area_visible+$50*15
defw
posicion_inicial_area_visible+$50*16
defw
posicion_inicial_area_visible+$50*17
defw
posicion_inicial_area_visible+$50*18
defw
posicion_inicial_area_visible+$50*19
.posiciones_super_buffer ;muestra el inicio de cada línea
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*0
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*1
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*2
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*3
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*4
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*5
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*6
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*7
defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*8
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*9
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*10
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*11
defw posicion_inicial_superbuffer+8*ancho_pantalla_bytes*12
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*13
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*14
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*15
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*16
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*17
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*18
defw
posicion_inicial_superbuffer+8*ancho_pantalla_bytes*19
.pantalla_actual defw 0
.pantalla_juego defs T_WIDTH*T_HEIGHT ;En tiles, es el mapa donde cada byte dice el tile que tiene.
defb $FF ;Este
byte es importante, marca el fin de la pantalla.
.tiles_tocados defs 150 ;touch
tile table
;cuando un tile es tocado, se marca en esta tabla
para luego restaurarlo.
;Es una tabla sin duplicados. Cada tile tocado se representa por 2 bytes. Se pueden
;tocar hasta 75 tiles.
;------------------------------------------------------------------------------------
; ***************************************************
; Scroll Left Addresses column
; not requiered if scroll not used comment it ;)
; one word for each scrollable line
.ColumnScr
defw $C0AA
defw $C8AA
defw $D0AA
defw $D8AA
defw $E0AA
defw $E8AA
defw $F0AA
defw $F8AA
…
; ***************************************************
;------------------------------------------------------------------------------------
; TILE DATA. TILES MUST BE DEFINED HERE
;------------------------------------------------------------------------------------
.tiles ;Each tile is 2x8 bytes.
;defb 2,8
;defb $70,$c0
;defb $f0,$68
;defb $f0,$84
;defb $f0,$e0
;defb $f0,$a4
;defb $e0,$c0
;defb $50,$60
;defb $00,$00
(c)
Raúl Simarro 2007-09 Contact, doubts,
suggestions, ...