updated to lastest retroluxury

This commit is contained in:
Andre Leiradella 2015-05-09 23:10:11 -03:00
parent 745b6b4af8
commit b41246c1e6
17 changed files with 731 additions and 87 deletions

11
retroluxury/LICENSE Normal file
View File

@ -0,0 +1,11 @@
The zlib/libpng License
Copyright (c) 2015 Andre Leiradella
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

196
retroluxury/README.md Normal file
View File

@ -0,0 +1,196 @@
# retroluxury
**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.
## API
### Background
The background is a 2D array of 16-bit pixels which represent what is seen on the screen. It's usually called **framebuffer**.
#### `int rl_backgrnd_create( int width, int height )`
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 [Interleave](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
TODO
### 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
Released under the zlib/libpng license.

View File

@ -284,6 +284,8 @@ static int l_color2alpha( lua_State* L )
return 1;
}
#define MAX( a, b ) ( a > b ? a : b )
static int l_blit( lua_State* L )
{
image_t* source = check( L, 1 );
@ -318,12 +320,11 @@ static int l_blit( lua_State* L )
int dg = ( dc >> 8 ) & 255;
int db = ( dc >> 16 ) & 255;
int a = ( sa * sa + da * ( 255 - sa ) ) / 255;
int r = ( sr * sa + dr * ( 255 - sa ) ) / 255;
int g = ( sg * sa + dg * ( 255 - sa ) ) / 255;
int b = ( sb * sa + db * ( 255 - sa ) ) / 255;
dest->pixels[ yy * dest->width + xx ] = a << 24 | b << 16 | g << 8 | r;
dest->pixels[ yy * dest->width + xx ] = MAX( sa, da ) << 24 | b << 16 | g << 8 | r;
}
xx++;

View File

@ -25,7 +25,7 @@ static int luamain( lua_State* L )
lua_newtable( L );
for ( i = 2; i < argc; i++ )
for ( i = 1; i < argc; i++ )
{
lua_pushstring( L, argv[ i ] );
lua_rawseti( L, -2, i - 1 );

View File

@ -2,6 +2,9 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include <lua.h>
#include <lauxlib.h>
@ -157,13 +160,95 @@ static int l_split( lua_State* L )
return 3;
}
static int l_scandir( lua_State* L )
{
const char* name = luaL_checkstring( L, 1 );
DIR* dir = opendir( name );
if ( dir )
{
struct dirent* entry;
int ndx = 1;
lua_createtable( L, 0, 0 );
while ( ( entry = readdir( dir ) ) != NULL )
{
lua_pushfstring( L, "%s%c%s", name, SEPARATOR, entry->d_name );
lua_rawseti( L, -2, ndx++ );
}
closedir( dir );
return 1;
}
lua_pushstring( L, strerror( errno ) );
return lua_error( L );
}
static void pushtime( lua_State* L, time_t* time )
{
struct tm* tm = gmtime( time );
char buf[ 256 ];
sprintf( buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec );
lua_pushstring( L, buf );
}
static int l_stat( lua_State* L )
{
static const struct { unsigned flag; const char* name; } modes[] =
{
//{ S_IFSOCK, "sock" },
//{ S_IFLNK, "link" },
{ S_IFREG, "file" },
{ S_IFBLK, "block" },
{ S_IFDIR, "dir" },
{ S_IFCHR, "char" },
{ S_IFIFO, "fifo" },
};
const char* name = luaL_checkstring( L, 1 );
struct stat buf;
int i;
if ( stat( name, &buf ) == 0 )
{
lua_createtable( L, 0, 0 );
lua_pushinteger( L, buf.st_size );
lua_setfield( L, -2, "size" );
pushtime( L, &buf.st_atime );
lua_setfield( L, -2, "atime" );
pushtime( L, &buf.st_mtime );
lua_setfield( L, -2, "mtime" );
pushtime( L, &buf.st_ctime );
lua_setfield( L, -2, "ctime" );
for ( i = 0; i < sizeof( modes ) / sizeof( modes[ 0 ] ); i++ )
{
lua_pushboolean( L, ( buf.st_mode & S_IFMT ) == modes[ i ].flag );
lua_setfield( L, -2, modes[ i ].name );
}
return 1;
}
lua_pushstring( L, strerror( errno ) );
return lua_error( L );
}
LUAMOD_API int luaopen_path( lua_State* L )
{
static const luaL_Reg statics[] =
{
{ "realpath", l_realpath },
//{ "sanitize", l_sanitize },
{ "split", l_split },
{ "split", l_split },
{ "scandir", l_scandir },
{ "stat", l_stat },
{ NULL, NULL }
};

View File

@ -1,6 +1,8 @@
local image = require 'image'
local path = require 'path'
local rleimage
local xml = [===[
local function prettyPrint( node, file, ident )
file = file or io.stdout
@ -334,6 +336,9 @@ local function newwriter()
prependu32 = function( self, x )
table.insert( self.content, 1, string.char( ( x >> 24 ) & 255, ( x >> 16 ) & 255, ( x >> 8 ) & 255, x & 255 ) )
end,
append = function( self, bytes )
self.content[ #self.content + 1 ] = bytes
end,
save = function( self, filename )
local file, err = io.open( filename, 'wb' )
if not file then error( err ) end
@ -343,13 +348,16 @@ local function newwriter()
size = function( self, filename )
self.content = { table.concat( self.content ) }
return #self.content[ 1 ]
end,
getcontent = function( self )
self.content = { table.concat( self.content ) }
return self.content[ 1 ]
end
}
end
local function compile( map, layers, coll )
local built = { tiles = {}, images = {}, layer0 = {}, layers = {} }
local imgset = {}
local out = newwriter()
-- build layer 0 and the tileset
@ -359,12 +367,13 @@ local function compile( map, layers, coll )
for i = 1, #layers[ 1 ] do
for _, layer in ipairs( map.layers ) do
if layer.name == layers[ 1 ][ i ] then
names[ layers[ 1 ][ i ] ] = layer
names[ layer.name ] = layer
end
end
end
local png = render( map, names )
local tileset = {}
for y = 0, png:getHeight() - 1, map.tileheight do
built.layer0[ y // map.tileheight + 1 ] = {}
@ -372,41 +381,104 @@ local function compile( map, layers, coll )
for x = 0, png:getWidth() - 1, map.tilewidth do
local sub = png:sub( x, y, x + 31, y + 31 )
if not imgset[ sub:getHash() ] then
if not tileset[ sub:getHash() ] then
built.tiles[ #built.tiles + 1 ] = sub
imgset[ sub:getHash() ] = #built.tiles - 1
tileset[ sub:getHash() ] = #built.tiles - 1
end
built.layer0[ y // map.tileheight + 1 ][ x // map.tilewidth + 1 ] = imgset[ sub:getHash() ]
built.layer0[ y // map.tileheight + 1 ][ x // map.tilewidth + 1 ] = tileset[ sub:getHash() ]
end
end
-- rl_map_t
out:writeu16( map.width )
out:writeu16( map.height )
out:writeu16( 1 ) -- layer count
out:writeu16( 0 ) -- pad
-- rl_tileset_t
out:writeu32( map.tilewidth * map.tileheight * 2 * #built.tiles + 6 ) -- total tileset size
out:writeu16( map.tilewidth )
out:writeu16( map.tileheight )
out:writeu16( #built.tiles )
for _, tile in ipairs( built.tiles ) do
for y = 0, map.tileheight - 1 do
for x = 0, map.tilewidth - 1 do
local r, g, b = image.split( tile:getPixel( x, y ) )
r, g, b = r * 31 // 255, g * 63 // 255, b * 31 // 255
out:writeu16( ( r << 11 ) | ( g << 5 ) | b )
end
-- build the other layers and the imageset
do
for l = 2, #layers do
local names = {}
for i = 1, #layers[ l ] do
for _, layer in ipairs( map.layers ) do
if layer.name == layers[ l ][ i ] then
names[ layer.name ] = layer
end
end
end
local png = render( map, names )
local imageset = {}
local indices = {}
built.layers[ l - 1 ] = indices
for y = 0, png:getHeight() - 1, map.tileheight do
indices[ y // map.tileheight + 1 ] = {}
for x = 0, png:getWidth() - 1, map.tilewidth do
local sub = png:sub( x, y, x + 31, y + 31 )
if not sub:invisible() then
if not imageset[ sub:getHash() ] then
built.images[ #built.images + 1 ] = sub
imageset[ sub:getHash() ] = #built.images
end
indices[ y // map.tileheight + 1 ][ x // map.tilewidth + 1 ] = imageset[ sub:getHash() ]
else
indices[ y // map.tileheight + 1 ][ x // map.tilewidth + 1 ] = 0
end
end
end
end
end
-- rl_map_t
out:writeu16( map.width )
out:writeu16( map.height )
out:writeu16( 1 + #built.layers ) -- layer count
-- rl_tileset_t
out:writeu32( map.tilewidth * map.tileheight * 2 * #built.tiles + 6 ) -- total tileset size
out:writeu16( map.tilewidth )
out:writeu16( map.tileheight )
out:writeu16( #built.tiles )
for _, tile in ipairs( built.tiles ) do
for y = 0, map.tileheight - 1 do
for x = 0, map.tilewidth - 1 do
local r, g, b = image.split( tile:getPixel( x, y ) )
r, g, b = r * 31 // 255, g * 63 // 255, b * 31 // 255
out:writeu16( ( r << 11 ) | ( g << 5 ) | b )
end
end
end
-- rl_imageset_t
do
local o = newwriter()
o:writeu16( #built.images )
-- rl_layer0
for _, image in ipairs( built.images ) do
local rle = rleimage( image, 32 ):get()
o:writeu32( #rle )
o:append( rle )
end
out:writeu32( o:size() )
out:append( o:getcontent() )
end
-- rl_layer0
for y = 1, map.height do
for x = 1, map.width do
out:writeu16( built.layer0[ y ][ x ] )
end
end
-- rl_layern
for _, layer in ipairs( built.layers ) do
for y = 1, map.height do
for x = 1, map.width do
out:writeu16( built.layer0[ y ][ x ] )
out:writeu16( layer[ y ][ x ] )
end
end
end
@ -450,6 +522,12 @@ Commands:
return 0
end
do
local dir, _, _ = path.split( path.realpath( args[ 0 ] ) )
local ok
ok, rleimage = loadfile( dir .. path.separator .. 'rlrle.lua' )()
end
local filename = path.realpath( args[ 1 ] )
local map = loadtmx( filename )

View File

@ -0,0 +1,13 @@
const char* rl_gitstamp =
"+------------------------------------------+\n"
"| RETROLUXURY |\n"
"| ____ _ _ ___ _ ____ |\n"
"| | __ ) | | | | |_ _| | | | _ \\ |\n"
"| | _ \\ | | | | | | | | | | | | |\n"
"| | |_) | | |_| | | | | |__ | |_| | |\n"
"| |____/ \\___/ |___| |____| |____/ |\n"
"| |\n"
"| HASH |\n"
"+------------------------------------------+\n";
const char* rl_githash = "HASH";

View File

@ -13,5 +13,10 @@ all: libretroluxury.a
libretroluxury.a: $(OBJS)
ar rcs $@ $+
rl_version.c: FORCE
cat ../etc/version.c.templ | sed s/HASH/`git rev-parse HEAD | tr -d "\n"`/g > $@
clean:
rm -f libretroluxury.a $(OBJS)
.PHONY: clean FORCE

View File

@ -37,4 +37,9 @@ value must be used when rle-encoding images with rlrle.lua.
#define RL_USERDATA_COUNT 1
#endif
/* Undef to use custom memory functions. */
#define rl_malloc malloc
#define rl_realloc realloc
#define rl_free free
#endif /* RL_CONFIG_H */

View File

@ -58,6 +58,62 @@ rl_image_t* rl_image_create( const void* data, size_t size )
return NULL;
}
rl_imageset_t* rl_imageset_create( const void* data, size_t size )
{
union
{
const void* restrict v;
const uint8_t* restrict u8;
const uint16_t* restrict u16;
const uint32_t* restrict u32;
}
ptr;
ptr.v = data;
int num_images = ne16( *ptr.u16++ );
rl_imageset_t* imageset = (rl_imageset_t*)rl_malloc( sizeof( rl_imageset_t ) + num_images * sizeof( rl_image_t* ) );
if ( imageset )
{
imageset->num_images = num_images;
for ( int i = 0; i < num_images; i++ )
{
size_t image_size = ne32( *ptr.u32++ );
imageset->images[ i ] = rl_image_create( ptr.v, image_size );
if ( !imageset->images[ i ] )
{
for ( int j = i - 1; j >= 0; --j )
{
rl_image_destroy( (void*)imageset->images[ j ] );
}
rl_free( imageset );
return NULL;
}
ptr.u8 += image_size;
}
return imageset;
}
return NULL;
}
void rl_imageset_destroy( const rl_imageset_t* imageset )
{
for ( int i = imageset->num_images - 1; i >= 0; --i )
{
rl_image_destroy( imageset->images[ i ] );
}
rl_free( (void*)imageset );
}
void rl_image_blit_nobg( const rl_image_t* image, int x, int y )
{
int x0 = 0;

View File

@ -26,10 +26,23 @@ typedef struct
}
rl_image_t;
typedef struct
{
int num_images;
const rl_image_t* images[ 0 ];
}
rl_imageset_t;
/* Creates an image given the RLE-encoded data produced by rlrle. */
rl_image_t* rl_image_create( const void* data, size_t size );
/* Destroys an image. */
#define rl_image_destroy( image ) do { rl_free( image ); } while ( 0 )
#define rl_image_destroy( image ) do { rl_free( (void*)image ); } while ( 0 )
/* Creates an image set. */
rl_imageset_t* rl_imageset_create( const void* data, size_t size );
/* Destroyes an image set. */
void rl_imageset_destroy( const rl_imageset_t* imageset );
/* Blits an image to the given background. */
void rl_image_blit_nobg( const rl_image_t* image, int x, int y );

View File

@ -2,28 +2,52 @@
#include <rl_memory.h>
#include <rl_backgrnd.h>
#include <string.h>
#include <rl_endian.c>
static rl_map_t* destroy( rl_map_t* map )
static rl_map_t* destroy( const rl_map_t* map )
{
if ( map )
{
if ( map->tileset )
for ( int i = map->num_layers - 1; i >= 0; --i )
{
rl_tileset_destroy( map->tileset );
rl_free( (void*)map->layers[ i ] );
}
if ( map->layer0 )
{
rl_free( map->layer0 );
rl_free( (void*)map->layer0 );
}
rl_free( map );
if ( map->imageset )
{
rl_imageset_destroy( (void*)map->imageset );
}
if ( map->tileset )
{
rl_tileset_destroy( (void*)map->tileset );
}
rl_free( (void*)map );
}
return NULL;
}
static void* alloc_zero( size_t size )
{
void* ptr = rl_malloc( size );
if ( ptr )
{
memset( ptr, 0, size );
}
return ptr;
}
rl_map_t* rl_map_create( const void* data, size_t size )
{
union
@ -40,69 +64,162 @@ rl_map_t* rl_map_create( const void* data, size_t size )
int width = ne16( *ptr.u16++ );
int height = ne16( *ptr.u16++ );
int num_layers = ne16( *ptr.u16++ );
ptr.u16++; /* padding */
rl_map_t* map = (rl_map_t*)rl_malloc( sizeof( rl_map_t ) );
rl_map_t* map = (rl_map_t*)alloc_zero( sizeof( rl_map_t ) + ( num_layers - 1 ) * sizeof( rl_layern_t ) );
if ( map )
if ( !map )
{
map->width = width;
map->height = height;
map->num_layers = num_layers;
return NULL;
}
map->width = width;
map->height = height;
map->num_layers = num_layers;
size_t tileset_size = ne32( *ptr.u32++ );
map->tileset = rl_tileset_create( ptr.v, tileset_size );
if ( !map->tileset )
{
return destroy( map );
}
ptr.u8 += tileset_size;
size_t imageset_size = ne32( *ptr.u32++ );
map->imageset = rl_imageset_create( ptr.v, imageset_size );
if ( !map->imageset )
{
return destroy( map );
}
ptr.u8 += imageset_size;
map->layer0 = (rl_layer0_t*)alloc_zero( width * height * sizeof( uint16_t ) );
if ( !map->layer0 )
{
return destroy( map );
}
uint16_t* restrict ndx = (uint16_t*)( (uint8_t*)map->layer0 + sizeof( rl_layer0_t ) );
const uint16_t* restrict end = ndx + width * height;
while ( ndx < end )
{
*ndx++ = ne16( *ptr.u16++ );
}
for ( int i = 1; i < num_layers; i++ )
{
map->layers[ i - 1 ] = (rl_layern_t*)alloc_zero( width * height * sizeof( uint16_t ) );
size_t tileset_size = ne32( *ptr.u32++ );
map->tileset = rl_tileset_create( ptr.v, tileset_size );
if ( map->tileset )
if ( !map->layers[ i - 1 ] )
{
ptr.u8 += tileset_size;
map->layer0 = (rl_layer0_t*)rl_malloc( width * height * sizeof( uint16_t ) );
if ( map->layer0 )
{
uint16_t* restrict ndx = map->layer0->indices;
const uint16_t* restrict end = ndx + width * height;
while ( ndx < end )
{
*ndx++ = ne16( *ptr.u16++ );
}
return map;
}
return destroy( map );
}
ndx = (uint16_t*)( (uint8_t*)map->layers[ i - 1 ] + sizeof( rl_layern_t ) );
end = ndx + width * height;
while ( ndx < end )
{
*ndx++ = ne16( *ptr.u16++ );
}
}
return destroy( map );
return map;
}
void rl_map_destroy( rl_map_t* map )
void rl_map_destroy( const rl_map_t* map )
{
destroy( map );
}
void rl_map_render_layer( rl_map_t* map, int ndx, int x, int y )
static void render_layer0( const rl_map_t* map, int x, int y )
{
int width, height;
rl_backgrnd_fb( &width, &height );
int bg_width, bg_height;
rl_backgrnd_fb( &bg_width, &bg_height );
if ( ndx == 0 )
const rl_tileset_t* tileset = map->tileset;
int ts_width = tileset->width;
int ts_height = tileset->height;
int dx = -( x % ts_width );
int dy = -( y % ts_height );
int max_x = dx + bg_width + ts_width;
int max_y = dy + bg_height + ts_height;
x /= ts_width;
y /= ts_height;
int pitch = map->width;
const uint16_t* restrict ndx = map->layer0->indices + y * pitch + x;
for ( y = dy; y < max_y; y += ts_height )
{
int wt = ( width + map->tileset->width - 1 ) / map->tileset->width + 1;
int ht = ( width + map->tileset->height - 1 ) / map->tileset->height;
const uint16_t* restrict next = ndx + pitch;
int dx = -( x % map->tileset->width );
int dy = -( y % map->tileset->height );
x /= map->tileset->width;
y /= map->tileset->height;
for ( int yy = 0; yy < ht; yy++ )
for ( x = dx; x < max_x; x += ts_width )
{
for ( int xx = 0; xx < wt; xx++ )
{
rl_tileset_blit_nobg( map->tileset, map->layer0->indices[ ( y + yy ) * map->width + ( x + xx ) ], dx + xx * map->tileset->width, dy + yy * map->tileset->height );
}
rl_tileset_blit_nobg( tileset, *ndx++, x, y );
}
ndx = next;
}
}
static void render_layern( const rl_map_t* map, int index, int x, int y )
{
int bg_width, bg_height;
rl_backgrnd_fb( &bg_width, &bg_height );
const rl_imageset_t* imageset = map->imageset;
int ts_width = map->tileset->width;
int ts_height = map->tileset->height;
int dx = -( x % ts_width );
int dy = -( y % ts_height );
int max_x = dx + bg_width + ts_width;
int max_y = dy + bg_height + ts_height;
x /= ts_width;
y /= ts_height;
int pitch = map->width;
const uint16_t* restrict ndx = map->layers[ --index ]->indices + y * pitch + x;
for ( y = dy; y < max_y; y += ts_height )
{
const uint16_t* restrict next = ndx + pitch;
for ( x = dx; x < max_x; x += ts_width )
{
index = *ndx++;
if ( index )
{
rl_image_blit_nobg( imageset->images[ index - 1 ], x, y );
}
}
ndx = next;
}
}
void rl_map_render_layer( const rl_map_t* map, int index, int x, int y )
{
if ( index )
{
render_layern( map, index, x, y );
}
else
{
render_layer0( map, x, y );
}
}

View File

@ -2,6 +2,7 @@
#define RL_MAP_H
#include <rl_userdata.h>
#include <rl_image.h>
#include <rl_tile.h>
#include <stdint.h>
@ -13,6 +14,9 @@ typedef struct
}
rl_layer0_t;
/* layern indices are *image* indices. */
typedef rl_layer0_t rl_layern_t;
typedef struct
{
rl_userdata_t ud;
@ -21,16 +25,17 @@ typedef struct
int height;
int num_layers;
rl_tileset_t* tileset;
rl_layer0_t* layer0;
const rl_tileset_t* tileset;
const rl_imageset_t* imageset;
const rl_layer0_t* layer0;
//rl_layern_t* layers[ 0 ];
rl_layern_t* layers[ 0 ];
}
rl_map_t;
rl_map_t* rl_map_create( const void* data, size_t size );
void rl_map_destroy( rl_map_t* map );
void rl_map_destroy( const rl_map_t* map );
void rl_map_render_layer( rl_map_t* map, int ndx, int x, int y );
void rl_map_render_layer( const rl_map_t* map, int index, int x, int y );
#endif /* RL_MAP_H */

View File

@ -226,6 +226,11 @@ void rl_sound_stop_ogg( void )
stb_vorbis_close( ogg_stream );
rl_free( ogg_alloc.alloc_buffer );
if ( ogg_stop_cb )
{
ogg_stop_cb( NULL );
}
ogg_stream = NULL;
}
}

View File

@ -64,6 +64,58 @@ static int compare( const void* e1, const void* e2 )
return c1 - c2;
}
void rl_sprites_render( void )
{
spt_t* sptptr = sprites;
const spt_t* endptr = sprites + num_sprites;
if ( sptptr < endptr )
{
do
{
sptptr->sprite->flags &= ~RL_SPRITE_TEMP_INV;
sptptr->sprite->flags |= sptptr->sprite->image == NULL;
sptptr++;
}
while ( sptptr < endptr );
}
qsort( (void*)sprites, num_sprites, sizeof( spt_t ), compare );
rl_sprite_t guard;
guard.flags = RL_SPRITE_UNUSED;
sprites[ num_sprites ].sprite = &guard; /* guard */
sptptr = sprites;
/* Iterate over active and visible sprites and blit them */
/* flags & 0x0007U == 0 */
if ( sptptr->sprite->flags == 0 )
{
do
{
rl_image_blit_nobg( sptptr->sprite->image, x0 + sptptr->sprite->x, y0 + sptptr->sprite->y );
sptptr++;
}
while ( sptptr->sprite->flags == 0 );
}
num_visible = sptptr - sprites;
/* Jump over active but invisible sprites */
/* flags & 0x0004U == 0x0000U */
if ( ( sptptr->sprite->flags & RL_SPRITE_UNUSED ) == 0 )
{
do
{
sptptr++;
}
while ( ( sptptr->sprite->flags & RL_SPRITE_UNUSED ) == 0 );
}
num_sprites = sptptr - sprites;
}
void rl_sprites_begin( void )
{
spt_t* sptptr = sprites;

View File

@ -38,6 +38,8 @@ rl_sprite_t* rl_sprite_create( void );
void rl_sprites_translate( int x0, int y0 );
void rl_sprites_render( void );
void rl_sprites_begin( void );
void rl_sprites_end( void );

View File

@ -7,7 +7,7 @@ const char* rl_gitstamp =
"| | |_) | | |_| | | | | |__ | |_| | |\n"
"| |____/ \\___/ |___| |____| |____/ |\n"
"| |\n"
"| 2deca58337d29d2f9bae4dd140d7c7b3cb12d0c9 |\n"
"| 9ff3b982d64cb8569d98ce12c3366612e383a5b5 |\n"
"+------------------------------------------+\n";
const char* rl_githash = "2deca58337d29d2f9bae4dd140d7c7b3cb12d0c9";
const char* rl_githash = "9ff3b982d64cb8569d98ce12c3366612e383a5b5";