diff --git a/source/defines.h b/source/defines.h new file mode 100644 index 0000000..0a233a1 --- /dev/null +++ b/source/defines.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +constexpr int SPRITE_WIDTH = 29; +constexpr int SPRITE_HEIGHT = 64; +constexpr int WINDOW_WIDTH = 160; +constexpr int WINDOW_HEIGHT = 160; +constexpr int WINDOW_ZOOM = 4; +constexpr int SPRITE_POS_X = (WINDOW_WIDTH - SPRITE_WIDTH) / 2; +constexpr int SPRITE_POS_Y = (WINDOW_HEIGHT - SPRITE_HEIGHT) / 2; + +constexpr int NUM_PALETTES = 2; +constexpr int NUM_FRAMES = 4; +constexpr Uint64 ANIMATION_SPEED = 200; diff --git a/source/game.cpp b/source/game.cpp deleted file mode 100644 index 28ad512..0000000 --- a/source/game.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "jUnit.h" - -void init() -{ - jInit("demo6_palette", 320, 240, 2); - jSetPal(0, 0x00000000); - jCls(0); - jSurface peiv = jLoadSurface("resources/williams.gif"); - jLoadPal("resources/pal01.gif"); - jSetSource(peiv); -} - -void update() -{ - jCls(0); - jBlit(100, 60, 0, 0, 29, 64); -} \ No newline at end of file diff --git a/source/gif.c b/source/gif.c index f029375..732d6e1 100644 --- a/source/gif.c +++ b/source/gif.c @@ -3,329 +3,326 @@ #include #include -#define EXTENSION_INTRODUCER 0x21 -#define IMAGE_DESCRIPTOR 0x2C -#define TRAILER 0x3B - -#define GRAPHIC_CONTROL 0xF9 -#define APPLICATION_EXTENSION 0xFF -#define COMMENT_EXTENSION 0xFE -#define PLAINTEXT_EXTENSION 0x01 - -#define READ(dst, size) memcpy(dst, buffer, size); buffer += size - -typedef struct +namespace GIF { - unsigned short width; - unsigned short height; - unsigned char fields; - unsigned char background_color_index; - unsigned char pixel_aspect_ratio; -} -screen_descriptor_t; +#define EXTENSION_INTRODUCER 0x21 +#define IMAGE_DESCRIPTOR 0x2C +#define TRAILER 0x3B -typedef struct -{ - unsigned char r; - unsigned char g; - unsigned char b; -} -rgb; +#define GRAPHIC_CONTROL 0xF9 +#define APPLICATION_EXTENSION 0xFF +#define COMMENT_EXTENSION 0xFE +#define PLAINTEXT_EXTENSION 0x01 -typedef struct -{ - unsigned short image_left_position; - unsigned short image_top_position; - unsigned short image_width; - unsigned short image_height; - unsigned char fields; -} -image_descriptor_t; +#define READ(dst, size) \ + memcpy(dst, buffer, size); \ + buffer += size -typedef struct -{ - unsigned char byte; - int prev; - int len; -} -dictionary_entry_t; - -typedef struct -{ - unsigned char extension_code; - unsigned char block_size; -} -extension_t; - -typedef struct -{ - unsigned char fields; - unsigned short delay_time; - unsigned char transparent_color_index; -} -graphic_control_extension_t; - -typedef struct -{ - unsigned char application_id[ 8 ]; - unsigned char version[ 3 ]; -} -application_extension_t; - -typedef struct -{ - unsigned short left; - unsigned short top; - unsigned short width; - unsigned short height; - unsigned char cell_width; - unsigned char cell_height; - unsigned char foreground_color; - unsigned char background_color; -} -plaintext_extension_t; - -//static unsigned short width = 0; -//static unsigned short height = 0; -//static unsigned char* uncompressed_data = NULL; - -void uncompress( int code_length, - const unsigned char *input, - int input_length, - unsigned char *out ) -{ - //int maxbits; - int i, bit; - int code, prev = -1; - dictionary_entry_t *dictionary; - int dictionary_ind; - unsigned int mask = 0x01; - int reset_code_length; - int clear_code; // This varies depending on code_length - int stop_code; // one more than clear code - int match_len; - - clear_code = 1 << ( code_length ); - stop_code = clear_code + 1; - // To handle clear codes - reset_code_length = code_length; - - // Create a dictionary large enough to hold "code_length" entries. - // Once the dictionary overflows, code_length increases - dictionary = ( dictionary_entry_t * ) - malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) ); - - // Initialize the first 2^code_len entries of the dictionary with their - // indices. The rest of the entries will be built up dynamically. - - // Technically, it shouldn't be necessary to initialize the - // dictionary. The spec says that the encoder "should output a - // clear code as the first code in the image data stream". It doesn't - // say must, though... - for ( dictionary_ind = 0; - dictionary_ind < ( 1 << code_length ); - dictionary_ind++ ) + typedef struct { - dictionary[ dictionary_ind ].byte = dictionary_ind; - // XXX this only works because prev is a 32-bit int (> 12 bits) - dictionary[ dictionary_ind ].prev = -1; - dictionary[ dictionary_ind ].len = 1; - } + unsigned short width; + unsigned short height; + unsigned char fields; + unsigned char background_color_index; + unsigned char pixel_aspect_ratio; + } screen_descriptor_t; - // 2^code_len + 1 is the special "end" code; don't give it an entry here - dictionary_ind++; - dictionary_ind++; - - // TODO verify that the very last byte is clear_code + 1 - while ( input_length ) + typedef struct { - code = 0x0; - // Always read one more bit than the code length - for ( i = 0; i < ( code_length + 1 ); i++ ) + unsigned char r; + unsigned char g; + unsigned char b; + } rgb; + + typedef struct + { + unsigned short image_left_position; + unsigned short image_top_position; + unsigned short image_width; + unsigned short image_height; + unsigned char fields; + } image_descriptor_t; + + typedef struct + { + unsigned char byte; + int prev; + int len; + } dictionary_entry_t; + + typedef struct + { + unsigned char extension_code; + unsigned char block_size; + } extension_t; + + typedef struct + { + unsigned char fields; + unsigned short delay_time; + unsigned char transparent_color_index; + } graphic_control_extension_t; + + typedef struct + { + unsigned char application_id[8]; + unsigned char version[3]; + } application_extension_t; + + typedef struct + { + unsigned short left; + unsigned short top; + unsigned short width; + unsigned short height; + unsigned char cell_width; + unsigned char cell_height; + unsigned char foreground_color; + unsigned char background_color; + } plaintext_extension_t; + + // static unsigned short width = 0; + // static unsigned short height = 0; + // static unsigned char* uncompressed_data = NULL; + + void uncompress(int code_length, + const unsigned char *input, + int input_length, + unsigned char *out) + { + // int maxbits; + int i, bit; + int code, prev = -1; + dictionary_entry_t *dictionary; + int dictionary_ind; + unsigned int mask = 0x01; + int reset_code_length; + int clear_code; // This varies depending on code_length + int stop_code; // one more than clear code + int match_len; + + clear_code = 1 << (code_length); + stop_code = clear_code + 1; + // To handle clear codes + reset_code_length = code_length; + + // Create a dictionary large enough to hold "code_length" entries. + // Once the dictionary overflows, code_length increases + dictionary = (dictionary_entry_t *) + malloc(sizeof(dictionary_entry_t) * (1 << (code_length + 1))); + + // Initialize the first 2^code_len entries of the dictionary with their + // indices. The rest of the entries will be built up dynamically. + + // Technically, it shouldn't be necessary to initialize the + // dictionary. The spec says that the encoder "should output a + // clear code as the first code in the image data stream". It doesn't + // say must, though... + for (dictionary_ind = 0; + dictionary_ind < (1 << code_length); + dictionary_ind++) { - // This is different than in the file read example; that - // was a call to "next_bit" - bit = ( *input & mask ) ? 1 : 0; - mask <<= 1; - - if ( mask == 0x100 ) - { - mask = 0x01; - input++; - input_length--; - } - - code = code | ( bit << i ); + dictionary[dictionary_ind].byte = dictionary_ind; + // XXX this only works because prev is a 32-bit int (> 12 bits) + dictionary[dictionary_ind].prev = -1; + dictionary[dictionary_ind].len = 1; } - if ( code == clear_code ) + // 2^code_len + 1 is the special "end" code; don't give it an entry here + dictionary_ind++; + dictionary_ind++; + + // TODO verify that the very last byte is clear_code + 1 + while (input_length) { - code_length = reset_code_length; - dictionary = ( dictionary_entry_t * ) realloc( dictionary, - sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) ); - - for ( dictionary_ind = 0; - dictionary_ind < ( 1 << code_length ); - dictionary_ind++ ) + code = 0x0; + // Always read one more bit than the code length + for (i = 0; i < (code_length + 1); i++) { - dictionary[ dictionary_ind ].byte = dictionary_ind; - // XXX this only works because prev is a 32-bit int (> 12 bits) - dictionary[ dictionary_ind ].prev = -1; - dictionary[ dictionary_ind ].len = 1; - } - dictionary_ind++; - dictionary_ind++; - prev = -1; - continue; - } - else if ( code == stop_code ) - { - /*if ( input_length > 1 ) - { - fprintf( stderr, "Malformed GIF (early stop code)\n" ); - exit( 0 ); - }*/ - break; - } + // This is different than in the file read example; that + // was a call to "next_bit" + bit = (*input & mask) ? 1 : 0; + mask <<= 1; - // Update the dictionary with this character plus the _entry_ - // (character or string) that came before it - if ( ( prev > -1 ) && ( code_length < 12 ) ) - { - if ( code > dictionary_ind ) - { - fprintf( stderr, "code = %.02x, but dictionary_ind = %.02x\n", - code, dictionary_ind ); - exit( 0 ); - } - - // Special handling for KwKwK - if ( code == dictionary_ind ) - { - int ptr = prev; - - while ( dictionary[ ptr ].prev != -1 ) + if (mask == 0x100) { - ptr = dictionary[ ptr ].prev; + mask = 0x01; + input++; + input_length--; } - dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte; + + code = code | (bit << i); } - else + + if (code == clear_code) { - int ptr = code; - while ( dictionary[ ptr ].prev != -1 ) + code_length = reset_code_length; + dictionary = (dictionary_entry_t *)realloc(dictionary, + sizeof(dictionary_entry_t) * (1 << (code_length + 1))); + + for (dictionary_ind = 0; + dictionary_ind < (1 << code_length); + dictionary_ind++) { - ptr = dictionary[ ptr ].prev; + dictionary[dictionary_ind].byte = dictionary_ind; + // XXX this only works because prev is a 32-bit int (> 12 bits) + dictionary[dictionary_ind].prev = -1; + dictionary[dictionary_ind].len = 1; } - dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte; + dictionary_ind++; + dictionary_ind++; + prev = -1; + continue; } - - dictionary[ dictionary_ind ].prev = prev; - - dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1; - - dictionary_ind++; - - // GIF89a mandates that this stops at 12 bits - if ( ( dictionary_ind == ( 1 << ( code_length + 1 ) ) ) && - ( code_length < 11 ) ) + else if (code == stop_code) { - code_length++; - - dictionary = ( dictionary_entry_t * ) realloc( dictionary, - sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) ); + /*if ( input_length > 1 ) + { + fprintf( stderr, "Malformed GIF (early stop code)\n" ); + exit( 0 ); + }*/ + break; } - } - prev = code; - - // Now copy the dictionary entry backwards into "out" - match_len = dictionary[ code ].len; - while ( code != -1 ) - { - out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte; - if ( dictionary[ code ].prev == code ) + // Update the dictionary with this character plus the _entry_ + // (character or string) that came before it + if ((prev > -1) && (code_length < 12)) { - fprintf( stderr, "Internal error; self-reference." ); - exit( 0 ); - } - code = dictionary[ code ].prev; - } + if (code > dictionary_ind) + { + fprintf(stderr, "code = %.02x, but dictionary_ind = %.02x\n", + code, dictionary_ind); + exit(0); + } - out += match_len; + // Special handling for KwKwK + if (code == dictionary_ind) + { + int ptr = prev; + + while (dictionary[ptr].prev != -1) + { + ptr = dictionary[ptr].prev; + } + dictionary[dictionary_ind].byte = dictionary[ptr].byte; + } + else + { + int ptr = code; + while (dictionary[ptr].prev != -1) + { + ptr = dictionary[ptr].prev; + } + dictionary[dictionary_ind].byte = dictionary[ptr].byte; + } + + dictionary[dictionary_ind].prev = prev; + + dictionary[dictionary_ind].len = dictionary[prev].len + 1; + + dictionary_ind++; + + // GIF89a mandates that this stops at 12 bits + if ((dictionary_ind == (1 << (code_length + 1))) && + (code_length < 11)) + { + code_length++; + + dictionary = (dictionary_entry_t *)realloc(dictionary, + sizeof(dictionary_entry_t) * (1 << (code_length + 1))); + } + } + + prev = code; + + // Now copy the dictionary entry backwards into "out" + match_len = dictionary[code].len; + while (code != -1) + { + out[dictionary[code].len - 1] = dictionary[code].byte; + if (dictionary[code].prev == code) + { + fprintf(stderr, "Internal error; self-reference."); + exit(0); + } + code = dictionary[code].prev; + } + + out += match_len; + } } -} -static int read_sub_blocks( unsigned char* buffer, unsigned char **data ) -{ - int data_length; - int index; - unsigned char block_size; - - // Everything following are data sub-blocks, until a 0-sized block is - // encountered. - data_length = 0; - *data = NULL; - index = 0; - - while ( 1 ) + static int read_sub_blocks(unsigned char *buffer, unsigned char **data) { - READ(&block_size, 1); + int data_length; + int index; + unsigned char block_size; - if ( block_size == 0 ) // end of sub-blocks + // Everything following are data sub-blocks, until a 0-sized block is + // encountered. + data_length = 0; + *data = NULL; + index = 0; + + while (1) { - break; + READ(&block_size, 1); + + if (block_size == 0) // end of sub-blocks + { + break; + } + + data_length += block_size; + *data = (unsigned char *)realloc(*data, data_length); + + // TODO this could be split across block size boundaries + READ(*data + index, block_size); + + index += block_size; } - data_length += block_size; - *data = (unsigned char*)realloc( *data, data_length ); - - // TODO this could be split across block size boundaries - READ(*data + index, block_size); - - index += block_size; + return data_length; } - return data_length; -} + unsigned char *process_image_descriptor(unsigned char *buffer, + rgb *gct, + int gct_size, + int resolution_bits) + { + image_descriptor_t image_descriptor; + int compressed_data_length; + unsigned char *compressed_data = NULL; + unsigned char lzw_code_size; + int uncompressed_data_length = 0; + unsigned char *uncompressed_data = NULL; -unsigned char* process_image_descriptor( unsigned char* buffer, - rgb *gct, - int gct_size, - int resolution_bits ) -{ - image_descriptor_t image_descriptor; - int compressed_data_length; - unsigned char *compressed_data = NULL; - unsigned char lzw_code_size; - int uncompressed_data_length = 0; - unsigned char *uncompressed_data = NULL; + // TODO there could actually be lots of these + READ(&image_descriptor, 9); - // TODO there could actually be lots of these - READ(&image_descriptor, 9); + // TODO if LCT = true, read the LCT - // TODO if LCT = true, read the LCT + READ(&lzw_code_size, 1); - READ(&lzw_code_size, 1); + compressed_data_length = read_sub_blocks(buffer, &compressed_data); - compressed_data_length = read_sub_blocks( buffer, &compressed_data ); + // width = image_descriptor.image_width; + // height = image_descriptor.image_height; + uncompressed_data_length = image_descriptor.image_width * + image_descriptor.image_height; + uncompressed_data = (unsigned char *)malloc(uncompressed_data_length); -// width = image_descriptor.image_width; -// height = image_descriptor.image_height; - uncompressed_data_length = image_descriptor.image_width * - image_descriptor.image_height; - uncompressed_data = (unsigned char*)malloc( uncompressed_data_length ); + uncompress(lzw_code_size, compressed_data, compressed_data_length, + uncompressed_data); - uncompress( lzw_code_size, compressed_data, compressed_data_length, - uncompressed_data ); + if (compressed_data) + free(compressed_data); - if ( compressed_data ) free( compressed_data ); + // if ( uncompressed_data ) + // free( uncompressed_data ); - //if ( uncompressed_data ) - // free( uncompressed_data ); - - return uncompressed_data; -} + return uncompressed_data; + } /** * @param gif_file the file descriptor of a file containing a @@ -334,101 +331,104 @@ unsigned char* process_image_descriptor( unsigned char* buffer, */ #define rb (*(buffer++)) -uint32_t* LoadPalette(unsigned char *buffer) { - unsigned char header[7]; - screen_descriptor_t screen_descriptor; - //int color_resolution_bits; - - int global_color_table_size = 0; // number of entries in global_color_table - uint32_t *global_color_table = NULL; - - READ(header, 6); - READ(&screen_descriptor, 7); - - //color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; - global_color_table = (uint32_t *)calloc(1, 1024); - - if (screen_descriptor.fields & 0x80) { - global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); - - //global_color_table = (rgb *)malloc(3 * global_color_table_size); - //READ(global_color_table, 3 * global_color_table_size); - for (int i=0; i> 4 ) + 1; + // color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; + global_color_table = (uint32_t *)calloc(1, 1024); - if ( screen_descriptor.fields & 0x80 ) - { - //int i; - // If bit 7 is set, the next block is a global color table; read it - global_color_table_size = 1 << - ( ( ( screen_descriptor.fields & 0x07 ) + 1 ) ); - - global_color_table = ( rgb * ) malloc( 3 * global_color_table_size ); - - // XXX this could conceivably return a short count... - READ(global_color_table, 3 * global_color_table_size); - } - - while ( block_type != TRAILER ) - { - READ(&block_type, 1); - - unsigned char size; - switch ( block_type ) + if (screen_descriptor.fields & 0x80) { + global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); + + // global_color_table = (rgb *)malloc(3 * global_color_table_size); + // READ(global_color_table, 3 * global_color_table_size); + for (int i = 0; i < global_color_table_size; ++i) + { + global_color_table[i] = (0xFF << 24) + (buffer[0] << 16) + (buffer[1] << 8) + buffer[2]; + buffer += 3; + } + } + return global_color_table; + } + + static unsigned char *process_gif_stream(unsigned char *buffer, unsigned short *w, unsigned short *h) + { + unsigned char header[7]; + screen_descriptor_t screen_descriptor; + int color_resolution_bits; + + int global_color_table_size = 0; // number of entries in global_color_table + rgb *global_color_table = NULL; + + unsigned char block_type = 0x0; + + // A GIF file starts with a Header (section 17) + READ(header, 6); + header[6] = 0x0; + + // XXX there's another format, GIF87a, that you may still find + // floating around. + /*if ( strcmp( "GIF89a", (char*)header ) ) + { + fprintf( stderr, + "Invalid GIF file (header is '%s', should be 'GIF89a')\n", + header ); + return NULL; + }*/ + + // Followed by a logical screen descriptor + // Note that this works because GIFs specify little-endian order; on a + // big-endian machine, the height & width would need to be reversed. + + // Can't use sizeof here since GCC does byte alignment; + // sizeof( screen_descriptor_t ) = 8! + READ(&screen_descriptor, 7); + *w = screen_descriptor.width; + *h = screen_descriptor.height; + + color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; + + if (screen_descriptor.fields & 0x80) + { + // int i; + // If bit 7 is set, the next block is a global color table; read it + global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); + + global_color_table = (rgb *)malloc(3 * global_color_table_size); + + // XXX this could conceivably return a short count... + READ(global_color_table, 3 * global_color_table_size); + } + + while (block_type != TRAILER) + { + READ(&block_type, 1); + + unsigned char size; + switch (block_type) + { case IMAGE_DESCRIPTOR: - return process_image_descriptor(buffer, - global_color_table, - global_color_table_size, - color_resolution_bits); + return process_image_descriptor(buffer, + global_color_table, + global_color_table_size, + color_resolution_bits); break; case EXTENSION_INTRODUCER: buffer++; size = *(buffer++); buffer += size; - do { + do + { size = *(buffer++); buffer += size; } while (size != 0); @@ -441,18 +441,18 @@ static unsigned char* process_gif_stream(unsigned char *buffer, unsigned short* case TRAILER: break; default: - fprintf( stderr, "Bailing on unrecognized block type %.02x\n", - block_type ); + fprintf(stderr, "Bailing on unrecognized block type %.02x\n", + block_type); return NULL; + } } + return NULL; } - return NULL; -} - -unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) { - return process_gif_stream(buffer, w, h); -} + unsigned char *LoadGif(unsigned char *buffer, unsigned short *w, unsigned short *h) + { + return process_gif_stream(buffer, w, h); + } /*int main( int argc, char *argv[] ) { @@ -475,4 +475,4 @@ unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* process_gif_stream( gif_file ); fclose( gif_file ); -}*/ \ No newline at end of file +}*/} \ No newline at end of file diff --git a/source/jUnit.cpp b/source/jUnit.cpp deleted file mode 100644 index 4f4902b..0000000 --- a/source/jUnit.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "jUnit.h" -#include "gif.c" -#include - -struct jSurface_s -{ - Uint8 *data; - Uint16 w, h; -}; - -static SDL_Window *jWin = nullptr; -static SDL_Renderer *jRen = nullptr; -static SDL_Texture *jTex = nullptr; -static jSurface jScreen; -static jSurface jDestSurf; -static jSurface jSourceSurf = nullptr; -static Uint32 paleta[256]; -static int jWidth = 320; -static int jHeight = 240; -static int jZoom = 2; -static int transparentColor = 0; - -jSurface jNewSurface(int w, int h) -{ - jSurface surf = (jSurface)malloc(sizeof(jSurface_s)); - surf->w = w; - surf->h = h; - surf->data = (Uint8 *)malloc(w * h); - return surf; -} - -void jDeleteSurface(jSurface surf) -{ - if (surf) - { - free(surf->data); - free(surf); - } -} - -void jSetDest(jSurface surf) -{ - jDestSurf = (surf == nullptr) ? jScreen : surf; -} - -void jSetSource(jSurface surf) -{ - jSourceSurf = surf; -} - -void jBlit(int dx, int dy, int sx, int sy, int w, int h) -{ - if (jSourceSurf == nullptr) - { - return; - } - - for (int iy = 0; iy < h; ++iy) - { - for (int ix = 0; ix < w; ++ix) - { - jPutPixel(dx + ix, dy + iy, jGetPixel(sx + ix, sy + iy)); - } - } -} - -jSurface jLoadSurface(const char *filename) -{ - FILE *f = fopen(filename, "rb"); - if (!f) - { - return nullptr; - } - - fseek(f, 0, SEEK_END); - long size = ftell(f); - fseek(f, 0, SEEK_SET); - Uint8 *buffer = (Uint8 *)malloc(size); - fread(buffer, size, 1, f); - fclose(f); - - Uint16 w, h; - Uint8 *pixels = LoadGif(buffer, &w, &h); - if (pixels == nullptr) - { - return nullptr; - } - jSurface surf = (jSurface)malloc(sizeof(jSurface_s)); - surf->w = w; - surf->h = h; - surf->data = pixels; - free(buffer); - return surf; -} - -void jLoadPal(const char *filename) -{ - FILE *f = fopen(filename, "rb"); - if (!f) - { - return; - } - - fseek(f, 0, SEEK_END); - long size = ftell(f); - fseek(f, 0, SEEK_SET); - Uint8 *buffer = (Uint8 *)malloc(size); - fread(buffer, size, 1, f); - fclose(f); - - Uint32 *pal = LoadPalette(buffer); - if (pal == nullptr) - { - return; - } - free(buffer); - for (int i = 0; i < 256; ++i) - { - paleta[i] = pal[i]; - } -} - -void jInit(const char *titol, int w, int h, int z) -{ - SDL_Init(SDL_INIT_VIDEO); - jWidth = w; - jHeight = h; - jZoom = z; - jWin = SDL_CreateWindow(titol, w * z, h * z, 0); - jRen = SDL_CreateRenderer(jWin, nullptr); - SDL_SetRenderLogicalPresentation(jRen, w, h, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE); - jTex = SDL_CreateTexture(jRen, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); - jScreen = jNewSurface(w, h); - jDestSurf = jScreen; -} - -void jSetPal(int index, Uint32 color) -{ - paleta[index] = color; -} - -void jCls(Uint8 color) -{ - for (int i = 0; i < jDestSurf->w * jDestSurf->h; ++i) - { - jDestSurf->data[i] = color; - } -} - -void jFlip() -{ - Uint32 *pixels; - int pitch; - SDL_LockTexture(jTex, nullptr, (void **)&pixels, &pitch); - for (int i = 0; i < jWidth * jHeight; ++i) - { - pixels[i] = paleta[jScreen->data[i]]; - } - SDL_UnlockTexture(jTex); - SDL_RenderTexture(jRen, jTex, nullptr, nullptr); - SDL_RenderPresent(jRen); -} - -void jPutPixel(int x, int y, Uint8 color) -{ - if (x < 0 || y < 0 || x >= jDestSurf->w || y >= jDestSurf->h || color == transparentColor) - { - return; - } - jDestSurf->data[x + y * jDestSurf->w] = color; -} - -Uint8 jGetPixel(int x, int y) -{ - return jSourceSurf->data[x + y * jSourceSurf->w]; -} \ No newline at end of file diff --git a/source/jUnit.h b/source/jUnit.h deleted file mode 100644 index a375dbd..0000000 --- a/source/jUnit.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include - -typedef struct jSurface_s *jSurface; - -void init(); -void update(); - -jSurface jNewSurface(int w, int h); -void jDeleteSurface(jSurface surf); -void jSetDest(jSurface surf); -void jSetSource(jSurface surf); - -jSurface jLoadSurface(const char* filename); - -void jPutPixel(int x, int y, Uint8 color); -Uint8 jGetPixel(int x, int y); - -void jBlit(int dx, int dy, int sx, int sy, int w, int h); - -void jInit(const char *titol, int w, int h, int z); - -void jSetPal(int index, Uint32 color); -void jLoadPal(const char *filename); - -void jCls(Uint8 color); - -void jFlip(); diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..3b91b52 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,55 @@ +#include "palette.h" +#include "defines.h" +#include + +void init() +{ + Palette::init("demo6_palette", WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_ZOOM); + Palette::Surface peiv = Palette::loadSurface("resources/williams.gif"); + Palette::loadPalette("resources/pal01.gif"); + Palette::setSrc(peiv); +} + +void update() +{ + const int FRAME = (SDL_GetTicks() / ANIMATION_SPEED) % NUM_FRAMES; + Palette::setPalette(255, 0xFF444466); + Palette::clear(255); + Palette::blit(SPRITE_POS_X, SPRITE_POS_Y, FRAME * SPRITE_WIDTH, 0, SPRITE_WIDTH, SPRITE_HEIGHT); +} + +int main(int argc, char *argv[]) +{ + init(); + SDL_Event event; + bool should_exit = false; + while (!should_exit) + { + while (SDL_PollEvent(&event)) + { + // Evento de salida + if (event.type == SDL_EVENT_QUIT) + { + should_exit = true; + break; + } + + // Eventos de teclado + if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0) + { + switch (event.key.key) + { + case SDLK_ESCAPE: + should_exit = true; + break; + + case SDLK_SPACE: + Palette::switchPalette(); + break; + } + } + } + update(); + Palette::flip(); + } +} \ No newline at end of file diff --git a/source/paleta.cpp b/source/paleta.cpp deleted file mode 100644 index 0a8c774..0000000 --- a/source/paleta.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "jUnit.h" - -int main(int argc, char *argv[]) -{ - init(); - SDL_Event event; - bool exit = false; - while (!exit) - { - while (SDL_PollEvent(&event)) - { - if ((event.type == SDL_EVENT_QUIT) || (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0 && event.key.key == SDLK_ESCAPE)) - { - exit = true; - break; - } - update(); - jFlip(); - } - } -} \ No newline at end of file diff --git a/source/palette.cpp b/source/palette.cpp new file mode 100644 index 0000000..0c90d61 --- /dev/null +++ b/source/palette.cpp @@ -0,0 +1,191 @@ +#include "palette.h" +#include "gif.c" +#include +#include +#include +#include "defines.h" + +namespace Palette +{ + struct SurfaceData + { + Uint8 *data; + Uint16 w, h; + }; + + static SDL_Window *window = nullptr; + static SDL_Renderer *renderer = nullptr; + static SDL_Texture *texture = nullptr; + static Surface screen; + static Surface dst_surface; + static Surface src_surface = nullptr; + static Uint32 palette[256]; + static int width = 0; + static int height = 0; + static int zoom = 0; + static int transparent_color = 14; + static int palette_number = 0; + + Surface newSurface(int w, int h) + { + Surface surf = (Surface)malloc(sizeof(SurfaceData)); + surf->w = w; + surf->h = h; + surf->data = (Uint8 *)malloc(w * h); + return surf; + } + + void deleteSurface(Surface surf) + { + if (surf) + { + free(surf->data); + free(surf); + } + } + + void setDst(Surface surf) + { + dst_surface = (surf == nullptr) ? screen : surf; + } + + void setSrc(Surface surf) + { + src_surface = surf; + } + + void blit(int dx, int dy, int sx, int sy, int w, int h) + { + if (src_surface == nullptr) + { + return; + } + + for (int iy = 0; iy < h; ++iy) + { + for (int ix = 0; ix < w; ++ix) + { + putPixel(dx + ix, dy + iy, getPixel(sx + ix, sy + iy)); + } + } + } + + Surface loadSurface(const char *filename) + { + FILE *f = fopen(filename, "rb"); + if (!f) + { + return nullptr; + } + + fseek(f, 0, SEEK_END); + long size = ftell(f); + fseek(f, 0, SEEK_SET); + Uint8 *buffer = (Uint8 *)malloc(size); + fread(buffer, size, 1, f); + fclose(f); + + Uint16 w, h; + Uint8 *pixels = GIF::LoadGif(buffer, &w, &h); + if (pixels == nullptr) + { + return nullptr; + } + Surface surf = (Surface)malloc(sizeof(SurfaceData)); + surf->w = w; + surf->h = h; + surf->data = pixels; + free(buffer); + return surf; + } + + void loadPalette(const char *filename) + { + FILE *f = fopen(filename, "rb"); + if (!f) + { + return; + } + + fseek(f, 0, SEEK_END); + long size = ftell(f); + fseek(f, 0, SEEK_SET); + Uint8 *buffer = (Uint8 *)malloc(size); + fread(buffer, size, 1, f); + fclose(f); + + Uint32 *pal = GIF::LoadPalette(buffer); + if (pal == nullptr) + { + return; + } + free(buffer); + for (int i = 0; i < 256; ++i) + { + palette[i] = pal[i]; + } + } + + void init(const char *titol, int w, int h, int z) + { + SDL_Init(SDL_INIT_VIDEO); + width = w; + height = h; + zoom = z; + window = SDL_CreateWindow(titol, w * z, h * z, 0); + renderer = SDL_CreateRenderer(window, nullptr); + SDL_SetRenderLogicalPresentation(renderer, w, h, SDL_LOGICAL_PRESENTATION_INTEGER_SCALE); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h); + SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST); + screen = newSurface(w, h); + dst_surface = screen; + } + + void setPalette(int index, Uint32 color) + { + palette[index] = color; + } + + void clear(Uint8 color) + { + for (int i = 0; i < dst_surface->w * dst_surface->h; ++i) + { + dst_surface->data[i] = color; + } + } + + void flip() + { + Uint32 *pixels; + int pitch; + SDL_LockTexture(texture, nullptr, (void **)&pixels, &pitch); + for (int i = 0; i < width * height; ++i) + { + pixels[i] = palette[screen->data[i]]; + } + SDL_UnlockTexture(texture); + SDL_RenderTexture(renderer, texture, nullptr, nullptr); + SDL_RenderPresent(renderer); + } + + void putPixel(int x, int y, Uint8 color) + { + if (x < 0 || y < 0 || x >= dst_surface->w || y >= dst_surface->h || color == transparent_color) + { + return; + } + dst_surface->data[x + y * dst_surface->w] = color; + } + + Uint8 getPixel(int x, int y) + { + return src_surface->data[x + y * src_surface->w]; + } + + void switchPalette() + { + palette_number = (palette_number + 1) % NUM_PALETTES; + std::array palettes{"resources/pal01.gif", "resources/pal02.gif"}; + loadPalette(palettes.at(palette_number).c_str()); + } +} \ No newline at end of file diff --git a/source/palette.h b/source/palette.h new file mode 100644 index 0000000..9db4774 --- /dev/null +++ b/source/palette.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace Palette +{ + typedef struct SurfaceData *Surface; + + Surface newSurface(int w, int h); + void deleteSurface(Surface surf); + void setDst(Surface surf); + void setSrc(Surface surf); + + Surface loadSurface(const char *filename); + + void putPixel(int x, int y, Uint8 color); + Uint8 getPixel(int x, int y); + + void blit(int dx, int dy, int sx, int sy, int w, int h); + + void init(const char *titol, int w, int h, int z); + + void setPalette(int index, Uint32 color); + void loadPalette(const char *filename); + + void clear(Uint8 color); + + void flip(); + void switchPalette(); +} \ No newline at end of file