FAT-Engine - SDK | (c) 2001/2002 TiCT |
API v1.10 (Application Programming Interface) |
The FAT-Engine, its features, the demo examples, the sourcecode and the documentation are provided AS-IS. Please don't ask for other features or extensions or for more detailed documentations.
If you don't understand a feature or its usage check the sourcecode of the corresponding demo. It shouldn't be hard to find out how the actual features of the FAT-Engine can be used.
Especially the sourcecode of the engine is provided AS-IS. The internals are too complicated to explain them in a few sentences and I have NOT enough time to explain them in details. Sorry.
Bug reports and similar are VERY welcome. Please use our Messageboard at
http://pub26.ezboard.com/btichessteamhq for this.
The following Software was (is) used by me to develop The FAT-Engine:
- TIGCC Development Environment
- TIGCC Tools Suite
- Image Studio 1.1
- VTI 2.5 beta 5
- UltraEdit32 8.00a (Trial)
- PaintShop Pro 7.00 (Trial)
- LCC - C-Compiler for Windows (download site 1)
- LCC - C-Compiler for Windows (download site 2)
- LCC - C-Compiler for Windows (download site 3)
A very good tutorial on Raycasting itself can be found at:
http://www.permadi.com/tutorial/raycast
Another very useful resource if you try to understand the techniques behind a raycasting engine is the sourcecode of Wolfenstein3D, DOOM and Quake which can be found here:
http://www.idsoftware.com/archives/sourcearc.html
Due to the restriction of the calculator a raycasting engine like the FAT-Engine is somewhat limited. Here is a list of the limitations:
- only textures of size 64x64 pixels with 2 planes are supported
- no support for transparent textures for walls
- no rendering of floor and ceiling
And here is the list of the features which are already build in:
- Support for maps of extensions up to 512 x 512
- Support for textures of size 64x64 pixels with 2 planes
- Support for a custom background image
- Support for sprites with any number of directions (for example: 8 directional sprites)
- Rendering is done in a backbuffer. The result is copied afterwards to any buffer you have specified.
- The FAT-Engine supplies fast sinus, cosinus, tangent and square-root functions based on internal lookup tables and it exports the external lookup tables, too
- The FAT-Engine supplies a function for exepack decompression (FAT_UnpackBuffer()).
- And last, but not least it supplies support for FAT standard texture format files, which can be used directly from the archive memory
Due to the restrictions of the AMS 2.0x versions every program which will use the FAT-Engine has to be located in ghostspace. This can be performed by either starting the program from the TICT-Explorer or with the use of a simple launcher program.
Since TIGCC 0.90 the compiler supports the commandline option -pack which can be used to exepack a program and generate a launcher program automatically. In my opinion this is the simpliest method to build a launcher and it gives your program the additionally benefit of being packed (needs less memory).
The following line shows how a program may be build exe-packed supposing the programs name is demo and the generated packed file should be called demodat:
tigcc -O3 -pack demodat demo.c
The simplest possible program which uses the FAT engine may look like this (it just outputs the version number of the FAT engine):
#define USE_TI89 #define USE_TI92P #define USE_V200 #include "fat.h" void _main(void) { if (FAT_LoadEngine() != FAT_LOADOKAY) { ST_helpMsg("loading FAT engine failed"); } else { ST_helpMsg(FAT_GetVersionString()); FAT_UnloadEngine(); } }Note that the include statement (include "fat.h") has to be almost the first line of your program. Only "#define SAVE_SCREEN" or the USE_XXX defines are allowed BEFORE it. Internally fat.h sets NO_EXIT_SUPPORT and includes tigcclib.h. So your program don't need any other include statements.
IMPORTANT: Make sure that your program DON'T USE "#define OPTIMIZE_ROM_CALLS". Otherwise your program may crash.
Function FAT_LoadEngine tries to resolve the FAT-Engine (fatlib.dll). It traverses the complete VAT to find a fitting version of this file (so it is not necessary that fatlib.dll is in the same directory than your program).
FAT_LoadEngine() may return one of these values:
- FAT_LOADOKAY (linking successfully completed)
- FAT_NOTGHOSTSPACE (ERROR: your program is NOT in ghostspace)
- FAT_NOTFOUND (NO matching FAT engine)
- FAT_LOCKFAILED (locking of FAT-Engine failed)
- FAT_OUTOFMEM (not enough memory for FAT-Engine available)
Only if FAT_LoadEngine returns FAT_LOADOKAY it is valid to proceed and to use functions of the FAT engine! No further checking is done by the functions of the engine and your program will very likely crash if FAT_LoadEngine hasn't returned FAT_LOADOKAY.
Additionally: DON'T forget to call FAT_UnloadEngine BEFORE returning from main (only if loading was successful).
Due to the fact that is a very critical point I repeat it once again (in big letters this time ;-):
Don't use ANY function of the FAT-Engine BEFORE you have called FAT_LoadEngine(), otherwise your program will very likely crash!
Since v1.10 your program will not crash immediately if you call a FAT function before FAT_LoadEngine(). You will see a flashing screen and a message ("FATAL: FAT-Engine not loaded") will be displayed in the status bar. Nevertheless it is very likely that your program will crash later on, because your program will not get the expected return value (if there is any). You should never see that flashing screen. If you see it, you know you have to call FAT_LoadEngine() sooner in your program.
The FAT-Engine lives in its own world which consists of squares and which is specified by a map. The map used in Demo 1 looks like this:
char map[16*16] = { 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 2, 0, 3, 3, 0, 2, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 3, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 1, 0, 2, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 3, 1, 0, 1, 1, 1, 1, 1, 0, 0, 3, 1, 3, 1, 2, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0, 3, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 3, 2, 0, 3, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 3, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 3, 2, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 3, 1, 2, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 1, 3, 1, 1, 1, 1 };Each entry in this map specifies if the corresponding square is empty (0) or filled with a cube which is textured on all sides with the specified texture number. Negative entries are ignored by the engine and treated as empty (0). You can use negative entries in the map to mark squares for your own game logic. For example: you could use negative entries to mark a square that it holds ammo of some type or a health pack. This way you don't have to use a separate map for stuff like this which saves some memory depending how large the used map is.
127 (CLOSED_DOOR_TILE) and -127 (OPEN_DOOR_TILE) are special values related to doors. Don't use them for anything else. For details about doors please read section "Doors Support" below.
Beside this logically setup the world of the FAT-Engine has the following constrains:
- Each square has the dimension 64x64.
- Angles ranges from 0 to 576 where 576 is 360 degrees.
- The y-axis is INVERTED and maps directly to the above array. The x-axis run from left to right and the y-axis from up to down.
- The field of view is 60 degrees (ANGLE_060). Due to the fact that the rendering window of the FAT-Engine is 96 pixels wide ANGLE_060 is defined as 96 for speedup reasons (that's where the "strange" angle values come from).
Beside FAT_LoadEngine() and FAT_UnloadEngine() the FAT-Engine supplies the following functions:
- short FAT_Sin16384(short angle)
This function returns sin(angle)*16384.- short FAT_Cos16384(short angle)
This function returns cos(angle)*16384.- long FAT_Tan512(short angle)
This function returns tan(angle)*512. Note that this function returns a long, because -/+ infinity is mapped to -/+ 65535.- unsigned long FAT_FastSqrt(unsigned long x)
Returns the square root of x. Note that the returned value may be wrong by 1. If you really need the exact value you can do the following:unsigned long s = FAT_FastSqrt(value); if (s*s > value) s--; // round down if value is wrong by 1But normally the returned square root value should be already good enough. If you use it for example to calculate distances in your program, being 1 wrong doesn't matter compared to the 64x64 sized fields of the map, isn't it?- short FAT_GetMainVersion()
returns main version number. If this version number doesn't match FAT_LoadEngine will refuse to load the engine.- unsigned short FAT_GetSubVersion()
returns sub version number. This version number may differ from the one used in your fat.h file. It just indicates internally engine restructuration.- char* FAT_GetVersionString()
returns an embedded version string which looks like this: "FAT-Engine vX.Y" (X is the main version number and Y the sub version number).- char* FAT_GetPoweredByString()
returns an embedded version string which looks like this: "powered by FAT-Engine vX.Y" (X is the main version number and Y the sub version number).- char* FAT_GetCopyrightString()
returns an embedded copyright string which looks like this: "(c) 2001-2002 TiCT"- char* FAT_GetBuildDateString()
returns an embedded build date string which looks like this: "Mar 6 2002" (the date when the engine was build).- char* FAT_GetBuildTimeString()
returns an embedded build time string which looks like this: "12:50:40" (the time when the engine was build).- short FAT_UnpackBuffer(unsigned char* src, unsigned char* dest)
This function can be used to decompressed exepacked data pointed to by src into buffer dest. Note that buffer dest has to be large enough hold the decompressed data. The unpacking function returns FAT_UNPACK_OKAY (0) if the unpacking was processed successfully.
If an input buffer contains valid exepacked data can be checked by using FAT_ValidEXEPACK(pointer_to_inputdata) which will return 0 if the data is NOT valid. The required size for the output buffer can be evaluated by using FAT_UnpackSize(pointer_to_inputdata). It will return the number of bytes necessary for the output buffer (Don't forget to check first if the input buffer contains valid exepacked data!).
A simple decompression function which returns an allocated buffer holding the decompressed data may look like this:unsigned char* DecompressIt(unsigned char* src) { unsigned char* dest = NULL; if (!FAT_ValidEXEPACK(src)) return NULL; // is input really exepacked? if ((dest = malloc(FAT_UnpackSize(src)))) { // allocate memory for output data if (FAT_UnpackBuffer(src,dest)) { // decompress // unpacking failed free(dest); dest = NULL; } } return dest; }- void FAT_Render(FATCONFIG*)
This function takes a pointer to a FATCONFIG structure (see below), renders the view and copies the result to the destination planes you have specified.- DEPTHDATA* FAT_GetDepthBuffer()
Returns structure which holds the depth information for each column after a picture is rendered. Note that the depthdata structure has to be retrieved only once. It will be filled after each call to FAT_Render() with new informations. The DEPTHDATA structure looks like this:typedef struct { short height[96]; // used rendering heights (clipped) unsigned short* lightdata[96]; // used textures for light plane (a copy NOT the original) unsigned short* darkdata[96]; // used textures for dark plane (a copy NOT the original) short distance[96]; // distances (unclipped) } DEPTHDATA;The values of this structure may be used, for example, to implement sprite drawing or any other effect which depends on the depth of each column. The following image illustrates the distance values of structure DEPTHDATA:
For each column the corresponding distance value tells you how far away the wall is. The corresponding height value will tell you how tall that strip of the wall will be displayed (nearer -> taller) and the lightdata and darkdata entries are copies of the textures which were used to texturize this wall strip.- short FAT_GetClipHeight()
Returns the maximum virtual height used for vertical wall strips. Each vertical wall strip which is taller, gets clipped to this height.- void FAT_SetPredrawCallback(void(*)(FATCONFIG*,DEPTHDATA*))
This looks like a very complicated function, isn't it? Well, it's not that complicated, but it takes another function as argument (in details: a pointer to this function). What the heck is a predraw callback? A predraw callback is a function which will be called after the DEPTHDATA (see above) is filled by the engine and before the engine will draw anything. If you register an own function as predraw callback then your program can modify the content of the DEPTHDATA structure before it is used to render the view. A simple example for such a predraw function can be seen in Demo3. There the predraw callback is used to simulate the "fade-in-the-distance" effect. Here is the commented code of Demo3's predraw callback.void MyOwnPredrawCallback(FATCONFIG* fc,DEPTHDATA* dd) { short i; // step through all DEPTHDATA entries ... for (i=0;i<ANGLE_060;i++) { // if distance to intersection is smaller than 76 ... leave it unmodified (too near) if (dd->distance[i] < 76) continue; // if distance is between 76 and 99 ... use BLACK as lightdata if (dd->distance[i] < 100) { dd->lightdata[i<<1] = 0xffffffffL; dd->lightdata[(i<<1)+1] = 0xffffffffL; } // if distance is between 100 and 169 ... use BLACK as darkdata else if (dd->distance[i] < 170) { dd->darkdata[i<<1] = 0xffffffffL; dd->darkdata[(i<<1)+1] = 0xffffffffL; } // all other intersections are too far away ... use BLACK for both light and darkdata else { dd->lightdata[i<<1] = 0xffffffffL; dd->lightdata[(i<<1)+1] = 0xffffffffL; dd->darkdata[i<<1] = 0xffffffffL; dd->darkdata[(i<<1)+1] = 0xffffffffL; } } } ... ... // registrates our callback function so FAT-Engine will call it ... FAT_SetPredrawCallback(MyOwnPredrawCallback); ... ...There are much more effects possible than such a simple fade effect. Just be creative ... ;-)- void FAT_SetPreHUDCallback(void(*)(FATCONFIG*,unsigned short*,unsigned short*))
Again a "complicated" function. Using FAT_SetPreHUDCallback you can register another callback function which will be called, before the rendered view is finally copied into the destination buffers. A simple example of the use of a PreHUDCallback is the "lightning" effect in Demo 3, which inverts the rendered data if a special variable is set. Here is the code of Demo3's prehud callback.void MyOwnPreHUDCallback(FATCONFIG* fc,unsigned short* plane0,unsigned short* plane1) { short i; if (!dont_modify) return; // only invert view if dont_modify is 0 for (i=0;i<6*96;i++,plane0++,plane1++) *plane0 = ~*plane0,*plane1 = ~*plane1; } ... ... // registrates our prehud callback function so FAT-Engine will call it ... FAT_SetPreHUDCallback(MyOwnPreHUDCallback); ... ...Note that the data in the given buffers (plane0 and plane1) is very specially arranged. Each buffer contains the graphics data of 6 vertical strips each 16 pixels wide (1 short). First comes 96 shorts of the first vertical strip, then 96 shorts of the second vertical strip and so on. This special arrangement is caused by how the FAT-Engine renders its view.- short* FAT_GetSinCos16384Tab()
returns the start address of the internal table which is used in functions FAT_Sin16384() AND (!!) FAT_Cos16384(). The table holds 145 short entries (one for each angle value up to ANGLE_090) and each entry corresponds to sin(angle)*16384.- short* FAT_GetFisheyeTab()
returns start address of internal fisheye correction table. This table holds 96 short entries (one for each calculated display strip). The entries are calculated by the following loop:// only PSEUDO-CODE - values are calculated similar to this for (i=-ANGLE_030,idx=0; i<ANGLE_030; i++,idx++) { entry[idx] = (short)(256 * cos(TO_RADIAN(i))); }- short* FAT_Get64DivTanTab()
returns start address of internal 64DivTan table. This table holds 144 short entries. The entries are calculated by the following loop:// only PSEUDO-CODE - values are calculated similar to this for (i=0; i<ANGLE_090; i++) { entry[i] = (short)(64.0 / tan(TO_RADIAN(i))); }- short* FAT_Get64TanTab()
returns start address of internal 64Tan table. This table holds 144 short entries. The entries are calculated by the following loop:// only PSEUDO-CODE - values are calculated similar to this for (i=0; i<ANGLE_090; i++) { entry[i] = (short)(64.0 * tan(TO_RADIAN(i))); }- short* FAT_Get128DivSinTab()
returns start address of internal 128DivSin table. This table holds 144 short entries. The entries are calculated by the following loop:// only PSEUDO-CODE - values are calculated similar to this for (i=0; i<ANGLE_090; i++) { entry[i] = (short)(128.0 / sin(TO_RADIAN(i))); }- short* FAT_Get256TanTab()
returns start address of internal 256Tan table. This table holds 144 short entries. The entries are calculated by the following loop:// only PSEUDO-CODE - values are calculated similar to this for (i=0; i<ANGLE_090; i++) { entry[i] = (short)(256.0 * tan(TO_RADIAN(i))); }- short* FAT_Get256DivTanTab()
returns start address of internal 256DivTan table. This table holds 144 short entries. The entries are calculated by the following loop:// only PSEUDO-CODE - values are calculated similar to this for (i=0; i<ANGLE_090; i++) { entry[i] = (short)(256.0 / tan(TO_RADIAN(i))); }- unsigned short* FAT_Get512TanTab()
returns start address of internal 512Tan table. This table holds 144 unsigned short entries (NOTE: unsigned !!). The entries are calculated by the following loop:// only PSEUDO-CODE - values are calculated similar to this for (i=0; i<ANGLE_090; i++) { entry[i] = (unsigned short)(512.0 * tan(TO_RADIAN(i))); }- short FAT_GetArcTanYX(short y, short x)
returns arctan(y/x). This function is very useful if you want to calculate the angle between two objects. For example: the angle between a sprite and the camera is calculated this way:angle = FAT_GetArcTanYX(sprite_ypos - camera_ypos, sprite_xpos - camera_xpos);- void FAT_SetSkipWords(short nr_words_to_skip)
Normally the FAT engine assumes that the destination buffer where it renders its view into is 240 pixels wide. If you want to use renderbuffer with a different width you can use this function to set the number of words which gets skipped at the end of each rendered line. By default the number of skipped words is 9 ((240-96)/16). Note that the renderbuffer width have to be a multiple of 16 pixels and the smallest width is 96 pixels. Here is an example how to use a 96 pixels wide renderbuffer:unsigned short renderbuffer1[6*96]; // for plane 0 unsigned short renderbuffer2[6*96]; // for plane 1 FAT_SetSkipWords(0); fc.dest_plane0 = renderbuffer1; // fc is the used FATCONFIG structure fc.dest_plane1 = renderbuffer2;IMPORTANT NOTE: Calling FAT_SetSkipWords is only valid AFTER FAT_LoadEngine() was executed without any error.- void FAT_SetHUD(unsigned short* plane0,unsigned short* plane1,unsigned short* mask)
If you want the FAT-Engine to render a HUD (head-up-display) above its render view you can set the graphics of the HUD by calling this function.
Each of the given parameters have to point to an unsigned short array of size 576 (96x96 pixels large graphics = 12*96 bytes = 6*96 shorts). To disable the drawing of the HUD just call FAT_SetHUD(NULL,NULL,NULL).
IMPORTANT NOTE: The mask data used for the HUD is somewhat different from the mask data used by the sprite routines from the TIGCCLIB. In detail: the given mask data is AND'ed with the content of the rendered view and then the HUD gfx data is OR'ed to the result. This way the drawing is much faster, because no internal inverting of the maskdata is necessary. Instead you have to invert the mask data by yourself before you hand the mask over to the FAT-Engine. Additionally note, that any pixel which is set in the HUD gfx is definitely set in the resulting output, too. The maskdata is internally NOT applied on the HUD gfx.
ADDITIONALLY: You can hand-over a NULL pointer for a plane. Than this plane will not processed with HUD data. I'm not sure if this is useful, but it will work.
- void FAT_SetUpperHUD(unsigned short* plane0,unsigned short* plane1,unsigned short* mask)
To reduce the necessary memory of a HUD you can use this function to render a HUD only in the upper part of the screen.
Each of the given parameters have to point to an unsigned short array of size 288 (96x48 pixels large graphics = 12*48 bytes = 6*48 shorts).
NOTE: The following two sequences will render the same HUD.Instead of: FAT_SetHUD(hud_plane0,hud_plane1,hud_mask); You can also use: FAT_SetUpperHUD(hud_plane0,hud_plane1,hud_mask); FAT_SetLowerHUD(hud_plane0+288,hud_plane1+288,hud_mask+288);Note, that any pixel which is set in the HUD gfx is definitely set in the resulting output, too. The maskdata is internally NOT applied on the HUD gfx.- void FAT_SetLowerHUD(unsigned short* plane0,unsigned short* plane1,unsigned short* mask)
To reduce the necessary memory of a HUD you can use this function to render a HUD only in the lower part of the screen.
Each of the given parameters have to point to an unsigned short array of size 288 (96x48 pixels large graphics = 12*48 bytes = 6*48 shorts).
NOTE: The following two sequences will render the same HUD.Instead of: FAT_SetHUD(hud_plane0,hud_plane1,hud_mask); You can also use: FAT_SetUpperHUD(hud_plane0,hud_plane1,hud_mask); FAT_SetLowerHUD(hud_plane0+288,hud_plane1+288,hud_mask+288);Note, that any pixel which is set in the HUD gfx is definitely set in the resulting output, too. The maskdata is internally NOT applied on the HUD gfx.- HANDLE FAT_GetHandleOfFile(const char* filename)
Returns the handle of the file specified by its filename or 0 if file doesn't exist.- void* FAT_LockHandleOfFile(HANDLE handle_of_file)
Locks the handle of a file and returns the pointer to the start address.- void FAT_UnlockHandleOfFile(HANDLE handle_of_file)
Unlocks the handle of a file. Make sure that it was you who have locked the file!- short FAT_GetNumberOfTextures(unsigned char* ptr)
Returns the number of textures of a FAT texture format block. To get the number of textures within a FAT texture file you can to it like that:HANDLE h = FAT_GetHandleOfFile("mytex"); if (!h) { // file not found! :(( } else { unsigned char* src = FAT_LockHandleOfFile(h); if (!src) { // problems while locking file :(( } else { short nr = FAT_GetNumberOfTextures(src+2); // important: src+2 to skip length of file bytes if (nr == -1) { // ERROR: File is NOT a FAT texture file!! } else { // OKAY - when we'll come here "nr" contains number of textures! } FAT_UnlockHandleOfFile(h); // IMPORTANT: Don't forget to unlock the file! } }IMPORTANT NOTE: If you are using the address to a file to call FAT_GetNumberOfTextures() make sure that you skip the first 2 bytes of the address, because these holds the length of the file itself!- short FAT_LoadTextures(TEXCONFIG* dest, unsigned char* src, short start_idx, short nr_textures)
loads a specified number of textures starting at index start_idx from a FAT texture block into the given TEXCONFIG array. Returns 1 if successfully loaded (otherwise 0).
Loading textures in the context of the FAT engine means loading the texture description (TEXCONFIG) only! The binary data of the textures stay where they are. Normally textures are stored in files. If you load textures from a file and use them you MUST garantee that the file stays locked as long as you use the textures. Otherwise really bad things may happen.
Here is a short demonstration how to load, let's say the textures of an 8-directional sprite from a file (suppose this file only contains these 8 textures):HANDLE h = FAT_GetHandleOfFile("mytex"); if (!h) { // file not found! :(( } else { unsigned char* src = FAT_LockHandleOfFile(h); if (!src) { // problems while locking file :(( } else { short nr = FAT_GetNumberOfTextures(src+2); // important: src+2 to skip length of file bytes if (nr != 8) { // ERROR: File is NOT a FAT texture or it contains not as much textures as required!! } else { TEXCONFIG sprite_textures[8]; nr = FAT_LoadTextures(sprite_textures,src+2,0,8); if (nr != 8) { // ERROR: loading failed } else { // Now you can use the sprite textures! // MAKE SURE THAT YOU CALL FAT_UnlockHandleFile() first // if you don't use the sprite textures anymore! // Normally this is at the end of your program!!! } } // Unlock the file when the sprite textures are NOT used anymore // But NOT sooner!!! FAT_UnlockHandleOfFile(h); } }IMPORTANT NOTE: If you are using the address to a file to call FAT_LoadTextures() make sure that you skip the first 2 bytes of the address, because these holds the length of the file itself!- short FAT_GetNumberOfGenericData(unsigned char* ptr)
Beside textures (TEXCONFIGs) a standard texture format file can hold generic data blocks. This function returns the number of generic data blocks contained by the standard texture format block to which ptr points (returns -1 if an error occurs).
IMPORTANT NOTE: If you are using the address to a file to call FAT_GetNumberOfGenericData() make sure that you skip the first 2 bytes of the address, because these holds the length of the file itself!- void* FAT_GetGenericData(unsigned char* ptr,short idx, unsigned short length)
Beside textures (TEXCONFIGs) a standard texture format file can hold generic data blocks. This function returns a pointer to the generic data block number idx contained by the standard texture format block to which ptr points (returns NULL if an error occurs). For stability reasons the passed length in bytes of this block MUST match the stored length of the block in the texture format header.
Sometimes the length of a generic data block is not known in previous by the client program. To prevent the engine from comparing the stored length with the given one, use define FAT_DONTCHECKLENGTH as value for length.
IMPORTANT NOTE: If you are using the address to a file to call FAT_GetGenericData() make sure that you skip the first 2 bytes of the address, because these holds the length of the file itself!- unsigned short FAT_GetGenericDataLength(unsigned char* ptr,short idx)
Returns the length of the GENERICDATA block with index idx. If an error occurs, this function returns FAT_NOLENGTH.
IMPORTANT NOTE: If you are using the address to a file to call FAT_GetGenericDataLength() make sure that you skip the first 2 bytes of the address, because these holds the length of the file itself!- PADSTATES FAT_GetPadState(void)
Returns a value of type PADSTATES which holds a series of key-pressed flags. 16 different keys can be queried using the returned value like this:PADSTATES key = FAT_GetPadState(); if (key & PADSTATE_UP) { // up key is pressed ... do something }Due to the different keyboard layout of the TI-89 and the TI-92p the key to PADSTATE mapping differs for both calcs. I have taken the mapping from Library GenLib which is known as an excellent gaming platform for kernel-dependent programming.
Here is a list of all macros and their corresponding keys on the TI-89/TI-92+:
PADSTATE macro TI-89 key TI-92p key PADSTATE_ESC Escape Escape PADSTATE_UP Cursor Up Cursor Up PADSTATE_DOWN Cursor Down Cursor Down PADSTATE_UPDOWN Cursor Up OR Down Cursor Up OR Down PADSTATE_LEFT Cursor Left Cursor Left PADSTATE_RIGHT Cursor Right Cursor Right PADSTATE_LEFTRIGHT Cursor Left OR Right Cursor Left OR Right PADSTATE_APPS APPS APPS PADSTATE_PLUS Plus Plus PADSTATE_MINUS Minus Minus PADSTATE_KA F1 2nd PADSTATE_KB F2 Diamond PADSTATE_KC F3 Home PADSTATE_KD F4 X PADSTATE_KE F5 Shift PADSTATE_KF F6 Alpha PADSTATE_KG F7 Mode PADSTATE_KH F8 Y
IMPORTANT: Make sure that you redirect AutoINT1 and AutoINT5 to dummy handlers or to turn them off completely BEFORE you call FAT_GetPadState(). Internally FAT_GetPadState() uses _rowread() and _rowread will otherwise interfere with the standard AutoINT1 and AutoINT5 handlers.- FAT_AllKeysReleased()
Nice macro using rowread(0) which loops until all keys are released.- FAT_WaitKeyPressed()
Nice macro using rowread(0) which loops until a key is pressed.- short FAT_AddDoor(short xtile, short ytile, unsigned char type, unsigned char state, short position, TEXCONFIG* doortexture, TEXCONFIG* sidetexture, void* clientdata)
Adds a door at tile (xtile/ytile).Returns 1 if door was successfully added or 0 if the maximum number of doors (MAX_NR_DOORS) is already reached.
Before a door will be rendered by the engine it has to be added using this function. The given door type have to be one of the following constants: DOOR_HORIZONTAL or DOOR_VERTICAL (in future versions types for pushable walls will be added here!).
The given state can be any unsigned char value (since the engine doesn't touch this). The following constants are predefined in fat.h, because most programs are likely to use them: DOOR_CLOSED, DOOR_CLOSING, DOOR_OPENING and DOOR_OPEN.
Value position tells the engine how much open a door is. Value 0 means a completely closed door, value 64 a completely open door. The state of the door is not queried by the engine itself. Only value position is used to evaluate how to render the door.
doortexture and sidetexture are pointers to TEXCONFIG structures which are used to render the door itself and the adjacent walls. sidetexture can be set to NULL if you don't want the adjacent walls to be rendered with any special texture they'll be rendered using the normal texture for their tile. Side textures are very useful, though, because they make it easy to recognize a door from far down a hallway.
clientdata can point to any data you want. The engine will not use it, but just store it in the FATDOOR structure.
Make sure that the map tile (xtile/ytile) contains value CLOSED_DOOR_TILE (127) which indicates a door which is complete closed or partitionally open. If a door is completely open you should set the corresponding map tile to value OPEN_DOOR_TILE (-127) which speedups the rendering process (but it is not necessary to set value OPEN_DOOR_TILE for correct rendering).
For explanations about the doors support in general, please read section "Doors Support" below.- FATDOOR* FAT_GetDoor(short xtile,short ytile)
If you have added previously a door at tile (xtile/ytile), this function will return a pointer to the corresponding FATDOOR structure. Otherwise it will return NULL. For speedup reasons FAT_GetDoor() caches internally the result of a previous successfully requested door. If you request again the same door you will get the result faster.- FATDOOR* FAT_GetDoorsArray(void)
Returns pointer to array of FATDOOR structures holding all actually added doors sorting by their ytile position.- short FAT_GetNrDoors(void)
Returns number of actually added doors.- void FAT_RemoveAllDoors(void)
Removes all previously added doors (for example: if you load a new map).
The most important part of the FAT-Engine is the render function and structure FATCONFIG. Structure FATCONFIG is defined like this:
typedef struct { short map_width; // width of the map short map_height; // height of the map char* map_data; // pointer to the map data itself (negative values gets ignored!) TEXCONFIG* textures; // pointer to the used textures (see section "Texture Formats") short nr_sprites; // number of sprites FATSPRITE* sprites; // the sprite array short cam_xpos; // camera position x short cam_ypos; // camera position y short cam_orientation; // camera orientation (0 .. 575) unsigned short* dest_plane0; // destination plane0 to copy result into (240x128) unsigned short* dest_plane1; // destination plane1 to copy result into (240x128) unsigned short* background; // pointer to image with 96x96 pixels and 2 planes unsigned long frame_counter; // frame counter (gets incremented by engine) } FATCONFIG;NOTE: dest_plane0 and dest_plane1 have to be pointers to even addresses (!!!) for speedup reasons. If you setup them with the results of GetPlane(0) and GetPlane(1) the display will be drawn at the left part of the LCD.
NOTE2: please read section "Texture Formats" to see how the 64x64 pixel textures and the background image have to be structured (At least the background image has to be supplied in a very special format).
NOTE3: Only camera orientation values between 0 and 575 are valid!
For speedup reasons the camera orientation ranges from 0 to 575. Headerfile fat.h contains the following defines for special angle values:
#define ANGLE_000 0 #define ANGLE_015 24 #define ANGLE_030 48 #define ANGLE_045 72 #define ANGLE_060 96 #define ANGLE_090 144 #define ANGLE_180 288 #define ANGLE_270 432 #define ANGLE_360 576 // DON'T (!!!) use this value, use ANGLE_000 instead //----------------------------------------------------------------------------- // angles when you look on the map as it is coded ... //----------------------------------------------------------------------------- #define ANGLE_NORTH ANGLE_270 #define ANGLE_EAST ANGLE_000 #define ANGLE_SOUTH ANGLE_090 #define ANGLE_WEST ANGLE_180If you modify the camera orientation, please make sure that the angle is always in the valid range (0..575). You can do this for example by the following two lines:
while (angle<ANGLE_000) angle+=ANGLE_360; while (angle>=ANGLE_360) angle-=ANGLE_360; // note the EQUAL sign in the comparison here!A more comfortable way is to use macro FAT_ClampAngle(). The macro will NOT modify its input parameter, but it returns the clamped value of its input. If you want to modify it's input use it like this:angle = FAT_ClampAngle(angle);
Please read the following document: How To Debug Client Programs using the FAT-Console
IMPORTANT NOTE: Every texture used with the FAT-Engine has to start on an even address!!
Background Image Format (96x96 pixels)
Due to speedups in version 0.63 of the FAT-Engine the 96x96 pixel background image which can be set in the FATCONFIG structure has to be supplied in a very special format. Instead of handing just a "normal" 96x96 pixel picture with 2 planes over to the engine each plane has to be supplied in a 6-strips format, where each strip is 16 pixel wide (2 bytes).
Suppose the following normal input data (the spacing will show already the strips):unsigned char bg[96*12] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12, // 1. line (6*2 bytes) 13,14, 15,16, 17,18, 19,20, 21,22, 23,24, // 2. line (6*2 bytes) 25,26, 27,28, 29,30, 31,32, 33,34, 35,36, // 3. line (6*2 bytes) 37,38, 39,40, 41,42, 43,44, 45,46, 47,48, // 4. line (6*2 bytes) 49,50, 51,52, 53,54, 55,56, 57,58, 59,60, // 5. line (6*2 bytes) 61,62, 63,64, 65,66, 67,68, 69,70, 71,72, // 6. line (6*2 bytes) .... .... };then the image has to be converted in the following format:unsigned char bg[96*2] = { 1, 2,13,14,25,26, ................. // 1. strip (96*2 bytes) 3, 4,15,16,27,28, ................. // 2. strip (96*2 bytes) 5, 6,17,18,29,30, ................. // 3. strip (96*2 bytes) 7, 8,19,20,31,32, ................. // 4. strip (96*2 bytes) 9,10,21,22,33,34, ................. // 5. strip (96*2 bytes) 11,12,23,24,35,36, ................. // 6. strip (96*2 bytes) };I'll hope you guess what I mean.
Other Textures and Mask Planes
Since API 0.63 all used textures and mask planes have to rotated 90 degrees to the left. In directory src/tools you can find a tool called fixtex64 which performs this rotation on a 64x64 pixel ImageStudio export file (B/W or grayscale).
The FAT-Engine uses generally 64x64 pixel textures for it operations. Due to the fact that a single grayscale 64x64 texture takes 1024 bytes re-using of textures is necessary to keep the memory constrains at a moderate level. To support the re-using of textures not the pure plane data is handed over to the FAT-Engine, but an array of texture configuration structures has to be used.
The texture configuration structure (TEXCONFIG) is defined this way:typedef struct { unsigned short* lightdata; // pointer to a 16 "columns" wide strip of 64x64 texture (light plane data) unsigned short* darkdata; // pointer to a 16 "columns" wide strip of 64x64 texture (dark plane data) unsigned short* maskdata; // a possible mask for it or NULL (ONLY USED FOR SPRITES!) unsigned short mirrored; // if set to STRIP_NORMAL this strip is rendered normal // if set to STRIP_MIRRORED this strip is rendered mirrored // if set to STRIP_IGNORE this strip will be ignored (not rendered) // IMPORTANT NOTE: STRIP_IGNORE works for sprite textures ONLY! // for wall textures STRIP_IGNORE is treated like STRIP_MIRROR! } TEXSTRIP; typedef struct { TEXSTRIP strips[4]; // 4 texture strips } TEXCONFIG;Examine the demo programs to see how to setup the texture structures correctly.
Since v1.07 the FAT-Engine supports sliding doors. Doors have no depth and are rendered in the center of block either horizontally or vertically. By setting a position value between 0 and 64 the client can specify much a door is open (0 - completely closed / 64 - completely open).
Each door needs two adjacenting walls to be rendered correctly. The Adjacenting walls are rendered with a different texture than the texture which is defined for the complete adjacenting block.
In the map tiles which holds a door have to be marked with value CLOSED_DOOR_TILE (127). If a door is completely open you can set the value of the corresponding map tile to OPEN_DOOR_TILE (-127) to speedup rendering (but it is not necessary to set value OPEN_DOOR_TILE for correct rendering). Beside setting the map tile to value CLOSED_DOOR_TILE, you have to call function FAT_AddDoor() once to setup all necessary parameters for a door like textures and similar. Internally a door is represented by the following structure:typedef struct { short xtile; // x position of door short ytile; // y position of door unsigned char type; // DOOR_HORIZONTAL or DOOR_VERTICAL (types for pushable walls will follow!) unsigned char state; // DOOR_OPEN, DOOR_OPENING, DOOR_CLOSED, or DOOR_CLOSING // Note: state is not evaluated by the engine, its only // for the client to keep track of the state of a door short position; // 0 = closed, 64 or higher = open, between = partially open TEXCONFIG* doortexture; // pointer to door texture TEXCONFIG* sidetexture; // pointer to side texture //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! void* clientdata; // maybe used freely by the client program to // store any data it wants (NOT USED BY ENGINE) //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } FATDOOR;Up to MAX_NR_DOORS (64) doors can be used in a level. The following functions are related to doors:FAT_AddDoor() ... add door to level FAT_GetDoor() ... get door at tile (x,y) FAT_GetDoorsArray() ... get FATDOOR array of all added doors (sorted by y) FAT_GetNrDoors() ... get number of added doors FAT_RemoveAllDoors() ... remove all added doors (for example if you load another level)See the API docs above for more details about the doors related functions.
The FAT-Engine will not modify the entries within the FATDOOR structures. It is up to the client to "animate" the doors by updating their position value. This way the client can fully control how fast a door opens/closes as well as if doors could be partitionally opened (for example: stuck half-open).
AGAIN: To add a door which should be rendered by the FAT-Engine you have to use value CLOSED_DOOR_TILE (127) in the map AND you have to call FAT_AddDoor() once specifying the rest of the door data like textures and similar.
The FAT-Engine supports sprites as well. The graphics data of sprites is defined by a number of TEXCONFIG entries: One TEXCONFIG entry for each supported viewing direction (a sprite should look like different if you view in from the front than from the back, isn't it?). Actually the engine supports any number of directions which are a power of 2 (1,2,4,8,16 ...), but it is optimized for 1 and 8-directional sprites.
Before you setup ANY field in a FATSPRITE structure, please make sure that you call function FAT_InitSprite(FATSPRITE* pointer_to_sprite) once and hand over a pointer to your FATSPRITE structure. This will fill all fields of the structures with 0.
The next important step during sprite setup is to set field drawmode of your FATSPRITE structure to one of the following values:
SPRITEMODE_UNUSED don't render this sprite SPRITEMODE_SIZE64 render full 64-bit height of sprite SPRITEMODE_UPPER32 render only 32-bit upper part of sprite SPRITEMODE_LOWER32 render only 32-bit lower part of sprite
As you can see from the above table it is possible to render only the upper or lower part of a sprite. The idea behind is that for small objects like medipaks which are lying on the ground it is a waste of time to render the 32-bit upper part of it, because it will be fully transparent. Nevertheless such a "half" sprite will need 64x64 textures, but you gain rendering speed.
For sprites field mirrored in structure TEXSTRIP can hold the following 3 different values:
STRIP_NORMAL render strip normally STRIP_MIRROR render strip mirrored STRIP_IGNORE ignore strip (don't render it)
IMPORTANT NOTE: STRIP_IGNORE is only handled for sprites yet (not for wall textures). A ignored strip is completely transparent which results in a great speedup during rendering. If your sprites contains empty strips it is a good idea to set the mirrored field to STRIP_IGNORE.
After you have initialized your FATSPRITE structure and you have set the drawmode, the most important step is to setup field sprites of the FATCONFIG structure to point to an array FATSPRITE structures and to set field nr_sprites to tell the engine the size of this array.
There is not much to know about the rest of FATSPRITE structure. Beside some internal data fields it contains the following ones (all entries which are important for a client program):short xpos; // x position of sprite short ypos; // y position of sprite short orientation; // orientation of sprite (0 ... 575) short nr_textures; // number of textures used for this sprite // (for example: 8 for 8 directional sprites) TEXCONFIG* textures; // pointer to start of TEXCONFIG array short height; // filled by FAT engine short centerx; // filled by FAT engine unsigned char* clientdata; // this pointer can be used freely by the client program unsigned short drawmode; // sprite drawing mode to use short angle; // filled by FAT engine struct _FATSPRITE* prev; // used by FAT engine for reversed Z drawing // (if this is NULL, than the actual sprite is the // farthest away sprite which is still visible) struct _FATSPRITE* next; // used by FAT engine for reversed Z drawing // (starting from the farthest away sprite this // points to the next nearest sprite OR NULL if // there are no more visible sprites)Entry height will be filled by the engine during rendering. It contains the height in pixel of the sprite as seen from the actual point of view. If a sprite is not visible on the screen height will be set to -1
Entry centerx is filled by the engine during rendering, too. It contains the vertical position of the sprite in the 96x96 pixels FAT-Engine's view. If a sprite is not visible on the screen centerx will be set to -1.
Entry angle is filled by the engine during rendering and contains the angle between the camera orientation and the sprite. If a sprite is not visible on the screen angle will be set to -1.
Entries prev and next are used by the FAT-Engine for reversed Z drawing (The Engine draws the farthest away sprite first) and will be set "calculated" by the engine during rendering. Just follow pointer prev until it contains NULL. This sprite entry is the farthest away sprite which gets still drawn. Starting from the farthest away sprite you can follow pointer next to proceed to the next sprite in the sorted list until next contains NULL.
Normally a client program needs more informations about a sprite depending on the logic of the program. To store any information about the sprite you can use pointer clientdata. Just define an own structure for the necessary data and setup clientdata to point to an instance of this data.
Yet the FAT-Engine doesn't support different sprite states like "standing", "walking" or "running". The logic for states like this have to be implemented in the client program. The fastest way to handle the different graphics data of, for example, a walking sprite, just replace pointer textures periodically by another one.
For the TEXCONFIG array indices of 8-directional sprites fat.h contains the following useful defines:#define TEX_AWAY 0 #define TEX_RIGHT_AWAY 1 #define TEX_RIGHT 2 #define TEX_RIGHT_TOWARD 3 #define TEX_TOWARD 4 #define TEX_LEFT_TOWARD 5 #define TEX_LEFT 6 #define TEX_LEFT_AWAY 7