mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-10 21:52:28 -05:00
Port of Duke Nukem 3D
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
This commit is contained in:
parent
01c6dcf6c7
commit
a855d62025
994 changed files with 336924 additions and 15 deletions
514
apps/plugins/sdl/SDL_image/IMG_xpm.c
Normal file
514
apps/plugins/sdl/SDL_image/IMG_xpm.c
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
SDL_image: An example image loading library for use with SDL
|
||||
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* XPM (X PixMap) image loader:
|
||||
*
|
||||
* Supports the XPMv3 format, EXCEPT:
|
||||
* - hotspot coordinates are ignored
|
||||
* - only colour ('c') colour symbols are used
|
||||
* - rgb.txt is not used (for portability), so only RGB colours
|
||||
* are recognized (#rrggbb etc) - only a few basic colour names are
|
||||
* handled
|
||||
*
|
||||
* The result is an 8bpp indexed surface if possible, otherwise 32bpp.
|
||||
* The colourkey is correctly set if transparency is used.
|
||||
*
|
||||
* Besides the standard API, also provides
|
||||
*
|
||||
* SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
|
||||
*
|
||||
* that reads the image data from an XPM file included in the C source.
|
||||
*
|
||||
* TODO: include rgb.txt here. The full table (from solaris 2.6) only
|
||||
* requires about 13K in binary form.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "SDL_image.h"
|
||||
|
||||
#ifdef LOAD_XPM
|
||||
|
||||
/* See if an image is contained in a data source */
|
||||
int IMG_isXPM(SDL_RWops *src)
|
||||
{
|
||||
int start;
|
||||
int is_XPM;
|
||||
char magic[9];
|
||||
|
||||
if ( !src )
|
||||
return 0;
|
||||
start = SDL_RWtell(src);
|
||||
is_XPM = 0;
|
||||
if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
|
||||
if ( memcmp(magic, "/* XPM */", sizeof(magic)) == 0 ) {
|
||||
is_XPM = 1;
|
||||
}
|
||||
}
|
||||
SDL_RWseek(src, start, RW_SEEK_SET);
|
||||
return(is_XPM);
|
||||
}
|
||||
|
||||
/* Hash table to look up colors from pixel strings */
|
||||
#define STARTING_HASH_SIZE 256
|
||||
|
||||
struct hash_entry {
|
||||
char *key;
|
||||
Uint32 color;
|
||||
struct hash_entry *next;
|
||||
};
|
||||
|
||||
struct color_hash {
|
||||
struct hash_entry **table;
|
||||
struct hash_entry *entries; /* array of all entries */
|
||||
struct hash_entry *next_free;
|
||||
int size;
|
||||
int maxnum;
|
||||
};
|
||||
|
||||
static int hash_key(const char *key, int cpp, int size)
|
||||
{
|
||||
int hash;
|
||||
|
||||
hash = 0;
|
||||
while ( cpp-- > 0 ) {
|
||||
hash = hash * 33 + *key++;
|
||||
}
|
||||
return hash & (size - 1);
|
||||
}
|
||||
|
||||
static struct color_hash *create_colorhash(int maxnum)
|
||||
{
|
||||
int bytes, s;
|
||||
struct color_hash *hash;
|
||||
|
||||
/* we know how many entries we need, so we can allocate
|
||||
everything here */
|
||||
hash = malloc(sizeof *hash);
|
||||
if(!hash)
|
||||
return NULL;
|
||||
|
||||
/* use power-of-2 sized hash table for decoding speed */
|
||||
for(s = STARTING_HASH_SIZE; s < maxnum; s <<= 1)
|
||||
;
|
||||
hash->size = s;
|
||||
hash->maxnum = maxnum;
|
||||
bytes = hash->size * sizeof(struct hash_entry **);
|
||||
hash->entries = NULL; /* in case malloc fails */
|
||||
hash->table = malloc(bytes);
|
||||
if(!hash->table)
|
||||
return NULL;
|
||||
memset(hash->table, 0, bytes);
|
||||
hash->entries = malloc(maxnum * sizeof(struct hash_entry));
|
||||
if(!hash->entries) {
|
||||
free(hash->table);
|
||||
return NULL;
|
||||
}
|
||||
hash->next_free = hash->entries;
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int add_colorhash(struct color_hash *hash,
|
||||
char *key, int cpp, Uint32 color)
|
||||
{
|
||||
int index = hash_key(key, cpp, hash->size);
|
||||
struct hash_entry *e = hash->next_free++;
|
||||
e->color = color;
|
||||
e->key = key;
|
||||
e->next = hash->table[index];
|
||||
hash->table[index] = e;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* fast lookup that works if cpp == 1 */
|
||||
#define QUICK_COLORHASH(hash, key) ((hash)->table[*(Uint8 *)(key)]->color)
|
||||
|
||||
static Uint32 get_colorhash(struct color_hash *hash, const char *key, int cpp)
|
||||
{
|
||||
struct hash_entry *entry = hash->table[hash_key(key, cpp, hash->size)];
|
||||
while(entry) {
|
||||
if(memcmp(key, entry->key, cpp) == 0)
|
||||
return entry->color;
|
||||
entry = entry->next;
|
||||
}
|
||||
return 0; /* garbage in - garbage out */
|
||||
}
|
||||
|
||||
static void free_colorhash(struct color_hash *hash)
|
||||
{
|
||||
if(hash && hash->table) {
|
||||
free(hash->table);
|
||||
free(hash->entries);
|
||||
free(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/* portable case-insensitive string comparison */
|
||||
static int string_equal(const char *a, const char *b, int n)
|
||||
{
|
||||
while(*a && *b && n) {
|
||||
if(toupper((unsigned char)*a) != toupper((unsigned char)*b))
|
||||
return 0;
|
||||
a++;
|
||||
b++;
|
||||
n--;
|
||||
}
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
#define ARRAYSIZE(a) (int)(sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
/*
|
||||
* convert colour spec to RGB (in 0xrrggbb format).
|
||||
* return 1 if successful.
|
||||
*/
|
||||
static int color_to_rgb(char *spec, int speclen, Uint32 *rgb)
|
||||
{
|
||||
/* poor man's rgb.txt */
|
||||
static struct { char *name; Uint32 rgb; } known[] = {
|
||||
{"none", 0xffffffff},
|
||||
{"black", 0x00000000},
|
||||
{"white", 0x00ffffff},
|
||||
{"red", 0x00ff0000},
|
||||
{"green", 0x0000ff00},
|
||||
{"blue", 0x000000ff}
|
||||
};
|
||||
|
||||
if(spec[0] == '#') {
|
||||
char buf[7];
|
||||
switch(speclen) {
|
||||
case 4:
|
||||
buf[0] = buf[1] = spec[1];
|
||||
buf[2] = buf[3] = spec[2];
|
||||
buf[4] = buf[5] = spec[3];
|
||||
break;
|
||||
case 7:
|
||||
memcpy(buf, spec + 1, 6);
|
||||
break;
|
||||
case 13:
|
||||
buf[0] = spec[1];
|
||||
buf[1] = spec[2];
|
||||
buf[2] = spec[5];
|
||||
buf[3] = spec[6];
|
||||
buf[4] = spec[9];
|
||||
buf[5] = spec[10];
|
||||
break;
|
||||
}
|
||||
buf[6] = '\0';
|
||||
*rgb = strtol(buf, NULL, 16);
|
||||
return 1;
|
||||
} else {
|
||||
int i;
|
||||
for(i = 0; i < ARRAYSIZE(known); i++)
|
||||
if(string_equal(known[i].name, spec, speclen)) {
|
||||
*rgb = known[i].rgb;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static char *linebuf;
|
||||
static int buflen;
|
||||
static char *error;
|
||||
|
||||
/*
|
||||
* Read next line from the source.
|
||||
* If len > 0, it's assumed to be at least len chars (for efficiency).
|
||||
* Return NULL and set error upon EOF or parse error.
|
||||
*/
|
||||
static char *get_next_line(char ***lines, SDL_RWops *src, int len)
|
||||
{
|
||||
char *linebufnew;
|
||||
|
||||
if(lines) {
|
||||
return *(*lines)++;
|
||||
} else {
|
||||
char c;
|
||||
int n;
|
||||
do {
|
||||
if(SDL_RWread(src, &c, 1, 1) <= 0) {
|
||||
error = "Premature end of data";
|
||||
return NULL;
|
||||
}
|
||||
} while(c != '"');
|
||||
if(len) {
|
||||
len += 4; /* "\",\n\0" */
|
||||
if(len > buflen){
|
||||
buflen = len;
|
||||
linebufnew = realloc(linebuf, buflen);
|
||||
if(!linebufnew) {
|
||||
free(linebuf);
|
||||
error = "Out of memory";
|
||||
return NULL;
|
||||
}
|
||||
linebuf = linebufnew;
|
||||
}
|
||||
if(SDL_RWread(src, linebuf, len - 1, 1) <= 0) {
|
||||
error = "Premature end of data";
|
||||
return NULL;
|
||||
}
|
||||
n = len - 2;
|
||||
} else {
|
||||
n = 0;
|
||||
do {
|
||||
if(n >= buflen - 1) {
|
||||
if(buflen == 0)
|
||||
buflen = 16;
|
||||
buflen *= 2;
|
||||
linebufnew = realloc(linebuf, buflen);
|
||||
if(!linebufnew) {
|
||||
free(linebuf);
|
||||
error = "Out of memory";
|
||||
return NULL;
|
||||
}
|
||||
linebuf = linebufnew;
|
||||
}
|
||||
if(SDL_RWread(src, linebuf + n, 1, 1) <= 0) {
|
||||
error = "Premature end of data";
|
||||
return NULL;
|
||||
}
|
||||
} while(linebuf[n++] != '"');
|
||||
n--;
|
||||
}
|
||||
linebuf[n] = '\0';
|
||||
return linebuf;
|
||||
}
|
||||
}
|
||||
|
||||
#define SKIPSPACE(p) \
|
||||
do { \
|
||||
while(isspace((unsigned char)*(p))) \
|
||||
++(p); \
|
||||
} while(0)
|
||||
|
||||
#define SKIPNONSPACE(p) \
|
||||
do { \
|
||||
while(!isspace((unsigned char)*(p)) && *p) \
|
||||
++(p); \
|
||||
} while(0)
|
||||
|
||||
/* read XPM from either array or RWops */
|
||||
static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src)
|
||||
{
|
||||
int start = 0;
|
||||
SDL_Surface *image = NULL;
|
||||
int index;
|
||||
int x, y;
|
||||
int w, h, ncolors, cpp;
|
||||
int indexed;
|
||||
Uint8 *dst;
|
||||
struct color_hash *colors = NULL;
|
||||
SDL_Color *im_colors = NULL;
|
||||
char *keystrings = NULL, *nextkey;
|
||||
char *line;
|
||||
char ***xpmlines = NULL;
|
||||
int pixels_len;
|
||||
|
||||
error = NULL;
|
||||
linebuf = NULL;
|
||||
buflen = 0;
|
||||
|
||||
if ( src )
|
||||
start = SDL_RWtell(src);
|
||||
|
||||
if(xpm)
|
||||
xpmlines = &xpm;
|
||||
|
||||
line = get_next_line(xpmlines, src, 0);
|
||||
if(!line)
|
||||
goto done;
|
||||
/*
|
||||
* The header string of an XPMv3 image has the format
|
||||
*
|
||||
* <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ]
|
||||
*
|
||||
* where the hotspot coords are intended for mouse cursors.
|
||||
* Right now we don't use the hotspots but it should be handled
|
||||
* one day.
|
||||
*/
|
||||
if(sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4
|
||||
|| w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) {
|
||||
error = "Invalid format description";
|
||||
goto done;
|
||||
}
|
||||
|
||||
keystrings = malloc(ncolors * cpp);
|
||||
if(!keystrings) {
|
||||
error = "Out of memory";
|
||||
goto done;
|
||||
}
|
||||
nextkey = keystrings;
|
||||
|
||||
/* Create the new surface */
|
||||
if(ncolors <= 256) {
|
||||
indexed = 1;
|
||||
image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8,
|
||||
0, 0, 0, 0);
|
||||
im_colors = image->format->palette->colors;
|
||||
image->format->palette->ncolors = ncolors;
|
||||
} else {
|
||||
indexed = 0;
|
||||
image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
|
||||
0xff0000, 0x00ff00, 0x0000ff, 0);
|
||||
}
|
||||
if(!image) {
|
||||
/* Hmm, some SDL error (out of memory?) */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Read the colors */
|
||||
colors = create_colorhash(ncolors);
|
||||
if (!colors) {
|
||||
error = "Out of memory";
|
||||
goto done;
|
||||
}
|
||||
for(index = 0; index < ncolors; ++index ) {
|
||||
char *p;
|
||||
line = get_next_line(xpmlines, src, 0);
|
||||
if(!line)
|
||||
goto done;
|
||||
|
||||
p = line + cpp + 1;
|
||||
|
||||
/* parse a colour definition */
|
||||
for(;;) {
|
||||
char nametype;
|
||||
char *colname;
|
||||
Uint32 rgb, pixel;
|
||||
|
||||
SKIPSPACE(p);
|
||||
if(!*p) {
|
||||
error = "colour parse error";
|
||||
goto done;
|
||||
}
|
||||
nametype = *p;
|
||||
SKIPNONSPACE(p);
|
||||
SKIPSPACE(p);
|
||||
colname = p;
|
||||
SKIPNONSPACE(p);
|
||||
if(nametype == 's')
|
||||
continue; /* skip symbolic colour names */
|
||||
|
||||
if(!color_to_rgb(colname, p - colname, &rgb))
|
||||
continue;
|
||||
|
||||
memcpy(nextkey, line, cpp);
|
||||
if(indexed) {
|
||||
SDL_Color *c = im_colors + index;
|
||||
c->r = (Uint8)(rgb >> 16);
|
||||
c->g = (Uint8)(rgb >> 8);
|
||||
c->b = (Uint8)(rgb);
|
||||
pixel = index;
|
||||
} else
|
||||
pixel = rgb;
|
||||
add_colorhash(colors, nextkey, cpp, pixel);
|
||||
nextkey += cpp;
|
||||
if(rgb == 0xffffffff)
|
||||
SDL_SetColorKey(image, SDL_SRCCOLORKEY, pixel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the pixels */
|
||||
pixels_len = w * cpp;
|
||||
dst = image->pixels;
|
||||
for(y = 0; y < h; y++) {
|
||||
line = get_next_line(xpmlines, src, pixels_len);
|
||||
if(indexed) {
|
||||
/* optimization for some common cases */
|
||||
if(cpp == 1)
|
||||
for(x = 0; x < w; x++)
|
||||
dst[x] = (Uint8)QUICK_COLORHASH(colors,
|
||||
line + x);
|
||||
else
|
||||
for(x = 0; x < w; x++)
|
||||
dst[x] = (Uint8)get_colorhash(colors,
|
||||
line + x * cpp,
|
||||
cpp);
|
||||
} else {
|
||||
for (x = 0; x < w; x++)
|
||||
((Uint32*)dst)[x] = get_colorhash(colors,
|
||||
line + x * cpp,
|
||||
cpp);
|
||||
}
|
||||
dst += image->pitch;
|
||||
}
|
||||
|
||||
done:
|
||||
if(error) {
|
||||
if ( src )
|
||||
SDL_RWseek(src, start, RW_SEEK_SET);
|
||||
if ( image ) {
|
||||
SDL_FreeSurface(image);
|
||||
image = NULL;
|
||||
}
|
||||
IMG_SetError(error);
|
||||
}
|
||||
free(keystrings);
|
||||
free_colorhash(colors);
|
||||
free(linebuf);
|
||||
return(image);
|
||||
}
|
||||
|
||||
/* Load a XPM type image from an RWops datasource */
|
||||
SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
|
||||
{
|
||||
if ( !src ) {
|
||||
/* The error message has been set in SDL_RWFromFile */
|
||||
return NULL;
|
||||
}
|
||||
return load_xpm(NULL, src);
|
||||
}
|
||||
|
||||
SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
|
||||
{
|
||||
return load_xpm(xpm, NULL);
|
||||
}
|
||||
|
||||
#else /* not LOAD_XPM */
|
||||
|
||||
/* See if an image is contained in a data source */
|
||||
int IMG_isXPM(SDL_RWops *src)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* Load a XPM type image from an SDL datasource */
|
||||
SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src)
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
SDL_Surface *IMG_ReadXPMFromArray(char **xpm)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* not LOAD_XPM */
|
||||
Loading…
Add table
Add a link
Reference in a new issue