better handling of stb header files; added in-place base64 decoding; removed outdated api documentation

This commit is contained in:
Andre Leiradella 2016-06-04 16:05:50 -03:00
parent 59f555e5a1
commit 3f173f528f
6 changed files with 110 additions and 230 deletions

228
README.md
View File

@ -2,235 +2,15 @@
**retroluxury** is a game library (wannabe) built on top of the [libretro](http://www.libretro.com/) API. It provides functions to blit images to the frame buffer, and to play [PCM audio](http://en.wikipedia.org/wiki/Pulse-code_modulation) and [Ogg Vorbis](http://en.wikipedia.org/wiki/Vorbis) files. **retroluxury** is a game library (wannabe) built on top of the [libretro](http://www.libretro.com/) API. It provides functions to blit images to the frame buffer, and to play [PCM audio](http://en.wikipedia.org/wiki/Pulse-code_modulation) and [Ogg Vorbis](http://en.wikipedia.org/wiki/Vorbis) files.
On top of that, **retroluxury** provides higher level functions to deal with sprites and draw maps created with the [Tiled](http://www.mapeditor.org/) map editor. On top of that, **retroluxury** provides higher level functions to load images and wave files, and deal with sprites.
## API ## API
### Background The API is changing a bit, please check the header files in the `src` folder.
The background is a 2D array of 16-bit pixels which represent what is seen on the screen. It's usually called **framebuffer**. ## Test core
* `int rl_backgrnd_create( int width, int height )` There's a minimal libretro core i available in the `test` folder, just `make` to generate the core and then run it with RetroArch.
Creates a framebuffer of `width` by `height` 16-bit pixels. Returns `0` on success or `-1` on error (which can only mean a memory allocation error for now.)
* `void rl_backgrnd_destroy( void )`
Releases the memory allocated by the `rl_backgrnd_create` function.
* `void rl_backgrnd_clear( uint16_t color )`
Clears the entire framebuffer to the given color. The 16-bit color can be calculated from 8-bit red, green and blue values with the following code:
int r = r * 31 / 255;
int g = g * 63 / 255;
int b = b * 31 / 255;
uint16_t color = ( r << 11 ) | ( g << 5 ) | b;
* `void rl_backgrnd_scroll( int dx, int dy )`
Scrolls the framebuffer by the given pixels. `dx` scrolls horizontally, and `dy` scrolls vertically. `rl_backgrnd_scroll( 0, -1 )` scrolls the framebuffer one pixel up.
`rl_backgrnd_scroll` doesn't do anything with lines "created" by the scroll. I.e., if you scroll the framebuffer one pixel left, the last column on the right will contain garbagge. It's up to the application to draw meaningful pixels in these places after a scroll.
* `uint16_t* rl_backgrnd_fb( int* width, int* height )`
Returns a pointer to the top-left pixel of the framebuffer, along with its width and height. Note that the framebuffer can have lines greater than `width` pixels (usually called *pitch*.) To calculate how much pixels to add to a pointer to the framebuffer in order to go one line down, use `width + RL_BACKGRND_MARGIN`.
### Images
Images are collections of [run-length encoded](http://en.wikipedia.org/wiki/Run-length_encoding) pixels, that can be drawn onto the framebuffer. Images also provide means to save the framebuffer pixels that are overwritten when they're drawn, and to restore those saved pixels back to framebuffer afterwards. This scheme allows for higher level contructions such as sprites.
Images have per-pixel transparency of 0, 25, 50, 75 and 100%.
* `rl_image_t* rl_image_create( const void* data, size_t size )`
Creates and returns an image based on the given data. This data can be created with the `rlrle.lua` tool.
* `rl_image_destroy( image )` (macro)
Frees the given image.
* `rl_imageset_t* rl_imageset_create( const void* data, size_t size )`
Creates a collection of images (imageset) from the given data.
* `void rl_imageset_destroy( const rl_imageset_t* imageset )`
Frees the given imageset.
* `void rl_image_blit_nobg( const rl_image_t* image, int x, int y )`
Drawn an image to the framebuffer at position (x, y). `rl_image_blit_nobg` doesn't save overwritten pixels on the framebuffer, so it's kind of a permanent operation, which will be visible on the screen until you overwrite the image with something else, i.e. by clearing the framebuffer.
* `uint16_t* rl_image_blit( const rl_image_t* image, int x, int y, uint16_t* bg )`
Save as `rl_image_blit_nobg`, but saves overwritten pixels on the framebuffer to the `bg` pointer. Make sure you allocate at least `image->used * sizeof(uint16_t)` bytes to `bg`.
* `void rl_image_unblit( const rl_image_t* image, int x, int y, const uint16_t* bg )`
Restores the framebuffer as it was before the image was drawn. The `bg` argument should be the same as the `rl_image_blit` call.
### Tiles
Tiles are similar to images, but they are always a rectangular block of 100% opaque pixels.
* `rl_tileset_t* rl_tileset_create( const void* data, size_t size )`
Creates a tileset (a collection of tiles having the same width and height) from the given data. Each tile is identified by its 0-based index in the tileset.
* `rl_tileset_destroy( tileset)` (macro)
Destroys the tileset.
* `void rl_tileset_blit_nobg( const rl_tileset_t* tileset, int index, int x, int y )`
Similar to `rl_image_blit_nobg`, but draws the tile identified by `index` in the given tileset.
* `uint16_t* rl_tileset_blit( const rl_tileset_t* tileset, int index, int x, int y, uint16_t* bg )`
Similar to `rl_image_blit`.
* `void rl_tileset_unblit( const rl_tileset_t* tileset, int x, int y, const uint16_t* bg )`
Similar to `rl_image_unblit`.
* `void rl_tile_blit_nobg( int width, int height, const uint16_t* pixels, int x, int y )`
Similar to `rl_image_blit_nobg`, but draws a rectangular array of `width` times `height` pixels located at `pixels`.
* `uint16_t* rl_tile_blit( int width, int height, const uint16_t* pixels, int x, int y, uint16_t* bg )`
Similar to `rl_image_blit`.
* `void rl_tile_unblit( int width, int height, int x, int y, const uint16_t* bg )`
Similar to `rl_image_unblit`.
### Sound
**retro luxury** supports stero, 44,100 Hz audio. All audio must be supplied at 44,100 Hz. Mono audio will be duplicated in both left and right channels.
Sounds are just PCM data which are mixed toghether. The `RL_MAX_VOICES` macro defines at compile time how much sounds can be played at the same time (usually called *voices*.) One Ogg Vorbis file can be played in addition to the voices.
* `void rl_sound_init( void )`
Initializes internal data.
* `void rl_sound_done( void )`
Stops all sounds and releases all memory used by the sound system.
* `rl_sound_t* rl_sound_create( const void* data, size_t size, int stereo )`
Creates a sound from the given data. The data is just `size / 2` signed 16-bit PCM data. If `stereo` is `true`, the sound is stereo and data is [interleaved](http://en.wikipedia.org/wiki/Interleave_sequence), with 16-bits for the left channel followed by 16-bits for the right channel and so forth: LRLRLR...
* `rl_sound_destroy( sound )` (macro)
Frees the given sound. Do **not** free a sound that's still playing.
* `int rl_sound_play( const rl_sound_t* sound, int repeat, rl_soundstop_t stop_cb )`
Plays a sound. If `repeat` is true, the sound will be repeated *ad infinitum* or until manually stopped. If `stop_cb` is not `NULL`, it'll be called when the sound stops, either because of calls to `rl_sound_stop` or `rl_sound_stop_all` or because it ended naturally.
The returned integer is an internal voice identifier which can be used in calls to `rl_sound_stop`.
* `void rl_sound_stop( int index )`
Stops a sound (voice) being played.
* `void rl_sound_stop_all( void )`
Mutes all voices. The Ogg Vorbis music is not affected.
* `int rl_sound_play_ogg( const void* data, size_t size, int repeat, rl_soundstop_t stop_cb )`
Starts playing the Ogg Vorbis file contained in `data`. If `repeat` is true, the music will restart automatically. If `stop_cb` is not `NULL`, it'll be called when the music either finishes or `rl_sound_stop_ogg` is called.
* `void rl_sound_stop_ogg( void )`
Interrupts the Ogg Vorbis music.
* `const int16_t* rl_sound_mix( void )`
Mixes all the active voices and the Ogg Vorbis music, if any, and returns a pointer to the stereo, 16-bit PCM audio data buffer that can be sent directly to a properly configured audio device. The data buffer has `RL_SAMPLES_PER_FRAME` stereo samples, meaning `RL_SAMPLES_PER_FRAME * 2` samples, which equals to `RL_SAMPLES_PER_FRAME * 2 * 2` bytes.
### Sprites
Sprites are just images with a spatial position, a layer index for depth sorting, and a visibility flag. They are blit/unblit as a group.
If you redraw the entire framebuffer every frame, you should:
1. Draw the framebuffer
1. Call `rl_sprites_blit_nobg`
1. Present the framebuffer
If your background is fixed, or if you update it instead of redrawing it completely, you should:
1. Update the framebuffer
1. Call `rl_sprites_blit`
1. Present the framebuffer
1. Call `rl_sprites_unblit`
* `void rl_sprite_init( void )`
Initializes internal data.
* `rl_sprite_t* rl_sprite_create( void )`
Creates a sprite. The `image` field of the sprite must be initialized before any sprites are drawn, either to a valid image or to NULL (in which case the sprite is invisible.)
* `rl_sprite_destroy( sprite ) (macro)`
Frees a sprite.
* `void rl_sprites_translate( int x0, int y0 )`
Translates all sprites.
* `void rl_sprites_blit_nobg( void )`
Blits all sprites without saving the background. Use this when the background is redrawn every frame.
* `void rl_sprites_blit( void )`
Blits all sprites saving their background. The `RL_BG_SAVE_SIZE` config macro defines the size of the scratch memory that will be used to save the sprites' backgrounds, so you may need to adjust its value if you blit too many sprites.
* `void rl_sprites_unblit( void )`
Unblits all sprites.
### Maps
TODO
### Misc
TODO (memory management, endianess conversion, userdata and compile-time configuration.)
## Conversion Tools
### rlrle.lua
TODO
### rlmap.lua
TODO
### rltile.lua
TODO
### rltileset.lua
TODO
## A Minimum libretro Core
TODO, but see `test/libretro/test.c`.
## License ## License

View File

@ -4,7 +4,7 @@ DEFINES=-DOUTSIDE_SPEEX -DRANDOM_PREFIX=speex -DEXPORT= -DFIXED_POINT
#CFLAGS=-O3 --std=c99 -Wall $(INCLUDES) $(DEFINES) #CFLAGS=-O3 --std=c99 -Wall $(INCLUDES) $(DEFINES)
CFLAGS=-O0 -g --std=c99 -Wall $(INCLUDES) $(DEFINES) CFLAGS=-O0 -g --std=c99 -Wall $(INCLUDES) $(DEFINES)
OBJS=rl_backgrnd.o rl_config.o rl_image.o rl_imgdata.o rl_pack.o rl_rand.o rl_resample.o rl_sound.o rl_snddata.o rl_sprite.o rl_version.o rl_xml.o external/resample.o OBJS=rl_backgrnd.o rl_base64.o rl_config.o rl_image.o rl_imgdata.o rl_pack.o rl_rand.o rl_resample.o rl_sound.o rl_snddata.o rl_sprite.o rl_version.o rl_xml.o external/resample.o
%.o: %.c %.o: %.c
gcc $(CFLAGS) -c $< -o $@ gcc $(CFLAGS) -c $< -o $@

92
src/rl_base64.c Normal file
View File

@ -0,0 +1,92 @@
#include <rl_base64.h>
size_t rl_base64_decode_inplace( void* buffer, size_t length )
{
static const uint8_t values[] =
{
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, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
size_t rest = length % 4;
length -= rest;
uint8_t* bin = (uint8_t*)buffer;
const uint8_t* digits = (uint8_t*)buffer;
const uint8_t* end = digits + length;
uint8_t d0, d1, d2, d3;
uint8_t b0, b1, b2;
if ( digits < end )
{
do
{
d0 = values[ digits[ 0 ] ];
d1 = values[ digits[ 1 ] ];
d2 = values[ digits[ 2 ] ];
d3 = values[ digits[ 3 ] ];
b0 = d0 << 2 | d1 >> 4;
b1 = ( d1 & 0x0f ) << 4 | d2 >> 2;
b2 = ( d2 & 0x03 ) << 6 | d3;
bin[ 0 ] = b0;
bin[ 1 ] = b1;
bin[ 2 ] = b2;
digits += 4;
bin += 3;
}
while ( digits < end );
}
if ( rest == 0 )
{
/* No remaining characters, check for padding. */
if ( length )
{
bin -= ( digits[ -1 ] == '=' ) + ( digits[ -2 ] == '=' );
}
}
else if ( rest == 3 )
{
/* Three characters remaining without padding. */
d0 = values[ digits[ 0 ] ];
d1 = values[ digits[ 1 ] ];
d2 = values[ digits[ 2 ] ];
b0 = d0 << 2 | d1 >> 4;
b1 = ( d1 & 0x0f ) << 4 | d2 >> 2;
bin[ 0 ] = b0;
bin[ 1 ] = b1;
bin += 2;
}
else if ( rest == 2 )
{
/* Two characters remaining without padding. */
d0 = values[ digits[ 0 ] ];
d1 = values[ digits[ 1 ] ];
b0 = d0 << 2 | d1 >> 4;
*bin++ = b0;
}
/* rest == 1 --> One character remaining without padding (invalid). */
return bin - (uint8_t*)buffer;
}

8
src/rl_base64.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef RL_BASE64_H
#define RL_BASE64_H
#include <stdint.h>
size_t rl_base64_decode_inplace( void* buffer, size_t length );
#endif /* RL_BASE64_H */

View File

@ -3,8 +3,9 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* stb_image config and inclusion */ /* stb_image config and inclusion */
#define STBI_ASSERT( x )
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#define STBI_ASSERT( x )
#define STBI_NO_STDIO
#include "external/stb_image.h" #include "external/stb_image.h"
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View File

@ -12,11 +12,12 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#ifdef RL_OGG_VORBIS #ifdef RL_OGG_VORBIS
#define STB_VORBIS_NO_CRT
#define STB_VORBIS_NO_STDIO
#define STB_VORBIS_NO_PUSHDATA_API #define STB_VORBIS_NO_PUSHDATA_API
#define STB_VORBIS_NO_STDIO
#define STB_VORBIS_NO_CRT
#define assert( x ) #define assert( x )
#undef NULL
// #define pow pow // #define pow pow
// #define floor floor // #define floor floor
@ -27,8 +28,6 @@
#define __forceinline __inline__ __attribute__((__always_inline__,__gnu_inline__)) #define __forceinline __inline__ __attribute__((__always_inline__,__gnu_inline__))
#endif #endif
#undef NULL
#include "external/stb_vorbis.c" #include "external/stb_vorbis.c"
#endif #endif