commit 2d7740a22de269fa0b0837e43751fbdfa0605241 Author: Raimon Zamora Date: Fri Sep 26 11:35:09 2025 +0200 - First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1966e35 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +wolf diff --git a/gif.c b/gif.c new file mode 100644 index 0000000..8c19b14 --- /dev/null +++ b/gif.c @@ -0,0 +1,478 @@ +#include +#include +#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 +{ + unsigned short width; + unsigned short height; + unsigned char fields; + unsigned char background_color_index; + unsigned char pixel_aspect_ratio; +} +screen_descriptor_t; + +typedef struct +{ + 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++ ) + { + 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; + } + + // 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 = 0x0; + // Always read one more bit than the code length + for ( i = 0; i < ( code_length + 1 ); i++ ) + { + // 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 ); + } + + if ( code == clear_code ) + { + 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++ ) + { + 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; + } + + // 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 ) + { + 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 ) + { + 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; + } + + 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; + + // TODO there could actually be lots of these + READ(&image_descriptor, 9); + + // TODO if LCT = true, read the LCT + + READ(&lzw_code_size, 1); + + 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 ); + + uncompress( lzw_code_size, compressed_data, compressed_data_length, + uncompressed_data ); + + if ( compressed_data ) free( compressed_data ); + + //if ( uncompressed_data ) + // free( uncompressed_data ); + + return uncompressed_data; +} + +/** + * @param gif_file the file descriptor of a file containing a + * GIF-encoded file. This should point to the first byte in + * the file when invoked. + */ +#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; + + 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); + break; + case EXTENSION_INTRODUCER: + buffer++; + size = *(buffer++); + buffer += size; + do { + size = *(buffer++); + buffer += size; + } while (size != 0); + + /*if ( !process_extension( buffer ) ) + { + return NULL; + }*/ + break; + case TRAILER: + break; + default: + fprintf( stderr, "Bailing on unrecognized block type %.02x\n", + block_type ); + return NULL; + } + } + return NULL; +} + + +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[] ) +{ + FILE* gif_file; + + if ( argc < 2 ) + { + fprintf( stderr, "Usage: %s \n", argv[ 0 ] ); + exit( 0 ); + } + + gif_file = fopen( argv[ 1 ], "rb" ); + + if ( gif_file == NULL ) + { + fprintf( stderr, "Unable to open file '%s'", argv[ 1 ] ); + perror( ": " ); + } + + process_gif_stream( gif_file ); + + fclose( gif_file ); +}*/ diff --git a/jdebug.cpp b/jdebug.cpp new file mode 100644 index 0000000..5cb0d2c --- /dev/null +++ b/jdebug.cpp @@ -0,0 +1,92 @@ +#include "jdebug.h" +#include + +namespace debug +{ + Uint8 bmp[448] {0x42, 0x4D, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x18, 0xF3, 0x83, 0x83, 0xCF, 0x83, 0x87, 0x00, 0x00, 0xF3, 0x39, 0x39, 0xCF, 0x79, 0xF3, 0x00, 0x00, 0x01, 0xF9, 0x39, 0xCF, 0x61, 0xF9, 0x00, 0x00, 0x33, 0xF9, 0x03, 0xE7, 0x87, 0x81, 0x00, 0x00, 0x93, 0x03, 0x3F, 0xF3, 0x1B, 0x39, 0x00, 0x00, 0xC3, 0x3F, 0x9F, 0x39, 0x3B, 0x39, 0x00, 0x41, 0xE3, 0x03, 0xC3, 0x01, 0x87, 0x83, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE7, 0x01, 0xC7, 0x81, 0x01, 0x83, 0x00, 0x00, 0xE7, 0x1F, 0x9B, 0xE7, 0x1F, 0x39, 0x00, 0x00, 0xE7, 0x8F, 0x39, 0xE7, 0x87, 0xF9, 0x00, 0x00, 0xC3, 0xC7, 0x39, 0xE7, 0xC3, 0xC3, 0x00, 0x00, 0x99, 0xE3, 0x39, 0xE7, 0xF1, 0xE7, 0x00, 0x00, 0x99, 0xF1, 0xB3, 0xC7, 0x39, 0xF3, 0x00, 0x00, 0x99, 0x01, 0xC7, 0xE7, 0x83, 0x81, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x83, 0xE7, 0x83, 0xEF, 0x39, 0x39, 0x00, 0x00, 0x39, 0xE7, 0x39, 0xC7, 0x11, 0x11, 0x00, 0x00, 0xF9, 0xE7, 0x39, 0x83, 0x01, 0x83, 0x00, 0x00, 0x83, 0xE7, 0x39, 0x11, 0x01, 0xC7, 0x00, 0x00, 0x3F, 0xE7, 0x39, 0x39, 0x29, 0x83, 0x00, 0x00, 0x33, 0xE7, 0x39, 0x39, 0x39, 0x11, 0x00, 0x00, 0x87, 0x81, 0x39, 0x39, 0x39, 0x39, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x39, 0x39, 0x83, 0x3F, 0x85, 0x31, 0x00, 0x00, 0x39, 0x31, 0x39, 0x3F, 0x33, 0x23, 0x00, 0x00, 0x29, 0x21, 0x39, 0x03, 0x21, 0x07, 0x00, 0x00, 0x01, 0x01, 0x39, 0x39, 0x39, 0x31, 0x00, 0x00, 0x01, 0x09, 0x39, 0x39, 0x39, 0x39, 0x00, 0x00, 0x11, 0x19, 0x39, 0x39, 0x39, 0x39, 0x00, 0x00, 0x39, 0x39, 0x83, 0x03, 0x83, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xC1, 0x39, 0x81, 0x83, 0x31, 0x01, 0x00, 0x00, 0x99, 0x39, 0xE7, 0x39, 0x23, 0x3F, 0x00, 0x00, 0x39, 0x39, 0xE7, 0xF9, 0x07, 0x3F, 0x00, 0x00, 0x31, 0x01, 0xE7, 0xF9, 0x0F, 0x3F, 0x00, 0x00, 0x3F, 0x39, 0xE7, 0xF9, 0x27, 0x3F, 0x00, 0x00, 0x9F, 0x39, 0xE7, 0xF9, 0x33, 0x3F, 0x00, 0x00, 0xC1, 0x39, 0x81, 0xF9, 0x39, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x39, 0x03, 0xC3, 0x07, 0x01, 0x3F, 0x00, 0x00, 0x39, 0x39, 0x99, 0x33, 0x3F, 0x3F, 0x00, 0x00, 0x01, 0x39, 0x3F, 0x39, 0x3F, 0x3F, 0x00, 0x00, 0x39, 0x03, 0x3F, 0x39, 0x03, 0x03, 0x00, 0x00, 0x39, 0x39, 0x3F, 0x39, 0x3F, 0x3F, 0x00, 0x00, 0x93, 0x39, 0x99, 0x33, 0x3F, 0x3F, 0x00, 0x00, 0xC7, 0x03, 0xC3, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}; + SDL_Texture* dbgtex; + static char dbg_str[1200]; + static char *cursor = nullptr; + + void init(SDL_Renderer *renderer) + { + dbgtex = SDL_CreateTextureFromSurface(renderer, SDL_LoadBMP_IO(SDL_IOFromMem(bmp, 448), 1)); + cursor = dbg_str; + SDL_SetTextureBlendMode(dbgtex, SDL_BLENDMODE_ADD); + } + + void render(SDL_Renderer *renderer) + { + int x = 0, y = 0, cc = 0; + SDL_FRect src {0, 0, 8, 8}, dst {0, 0, 8, 8}; + while (cc<1200 && dbg_str[cc] != 0) { + char chr = dbg_str[cc++]; + if (chr > 96) chr -= 32; + if (chr==46) chr = 32; + if (chr > 32) { + if (chr >= 65) { + src.x = ((chr-65)%6)*8; + src.y = ((chr-65)/6)*8; + } else if (chr < 65) { + src.x = ((chr-22)%6)*8; + src.y = ((chr-22)/6)*8; + } + SDL_RenderTexture(renderer, dbgtex, &src, &dst); + dst.x += 8; + if (dst.x >= 320) { + dst.x=0; dst.y += 8; + if (dst.y >= 240) cc = 2000; + } + } else if (chr==32) { + dst.x += 8; + if (dst.x >= 320) { + dst.x=0; dst.y += 8; + if (dst.y >= 240) cc = 2000; + } + } else if (chr==10 || chr==13) { + dst.x=0; dst.y += 8; + if (dst.y >= 240) cc = 2000; + } + } + cursor = dbg_str; *cursor=0; + } + + void println(const char *label, int value) + { + print(label); + print(" "); + print(value); + newline(); + } + + void print(int value) + { + char temp[20]; + SDL_itoa(value, temp, 10); + const int len = strlen(temp); + strcpy(cursor, temp); + cursor+=len; + } + + void print(const char *value) + { + const int len = strlen(value); + strcpy(cursor, value); + cursor+=len; + } + + void print(float value) + { + char temp[20]; + sprintf(temp, "%f", value); + const int len = strlen(temp); + strcpy(cursor, temp); + cursor+=len; + } + + void newline() + { + *(cursor++) = '\n'; + *cursor = '\0'; + } +} diff --git a/jdebug.h b/jdebug.h new file mode 100644 index 0000000..f53291b --- /dev/null +++ b/jdebug.h @@ -0,0 +1,14 @@ +#pragma once +#include + +namespace debug +{ + void init(SDL_Renderer *renderer); + void render(SDL_Renderer *renderer); + + void println(const char *label, int value); + void print(int value); + void print(const char *value); + void print(float value); + void newline(); +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1d7e642 --- /dev/null +++ b/main.cpp @@ -0,0 +1,393 @@ +#include +#include "gif.c" +#include +#include "jdebug.h" + +#define M_PI 3.14159265358979323846 +#define DEG_TO_RAD M_PI/180.0f + +struct vec2 { float x, y; }; +struct wall { Uint16 v1, v2; vec2 normal; float u1, u2; }; +struct sector { + std::vector walls; + std::vector verts; +}; + +SDL_Window *sdl_window; +SDL_Renderer *sdl_renderer; +SDL_Texture *sdl_texture; + +Uint32 *palette; +Uint8 *gif; +Uint8 screen[320*240]; + +std::vector sectors; +int current_sector; + +vec2 position = { 128.0f, 192.0f }; +float speed = 200.0f; +float height = 32.0f; +float orientation = 90.0f; + +// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines +// intersect the intersection point may be stored in the floats i_x and i_y. +const bool get_line_intersection(vec2 p0, vec2 p1, vec2 p2, vec2 p3, vec2 *i) +{ + vec2 s1, s2; + s1.x = p1.x - p0.x; s1.y = p1.y - p0.y; + s2.x = p3.x - p2.x; s2.y = p3.y - p2.y; + + float s, t; + s = (-s1.y * (p0.x - p2.x) + s1.x * (p0.y - p2.y)) / (-s2.x * s1.y + s1.x * s2.y); + t = ( s2.x * (p0.y - p2.y) - s2.y * (p0.x - p2.x)) / (-s2.x * s1.y + s1.x * s2.y); + + if (s >= 0 && s <= 1 && t >= 0 && t <= 1) + { + // Collision detected + if (i != NULL) + { + i->x = p0.x + (t * s1.x); + i->y = p0.y + (t * s1.y); + + } + return true; + } + + return false; // No collision +} + +inline const float distance(vec2 p1, vec2 p2) +{ + const float xx = p2.x-p1.x; + const float yy = p2.y-p1.y; + return SDL_sqrtf(xx*xx+yy*yy); +} + +inline const void normalize(vec2 *v) +{ + const float length = SDL_sqrtf(v->x*v->x + v->y*v->y); + if (length > 0.0f) { + v->x /= length; + v->y /= length; + } +} + +inline const float dot(vec2 v1, vec2 v2) +{ + return v1.x*v2.x + v1.y*v2.y; +} + +void putp(int x, int y, Uint8 color) +{ + if (x<0 || y<0 || x>=320 || y>=240) return; + screen[x+y*320]=color; +} + +void line(int x1, int y1, int x2, int y2, Uint8 color) +{ + float dx = float(x2-x1); + float dy = float(y2-y1); + float steps = SDL_max(SDL_fabsf(dx), SDL_fabsf(dy)); + + if (steps==0) { putp(x1,y1,color); return; } + + float incx = dx / steps; + float incy = dy / steps; + + float x = (float)x1; + float y = (float)y1; + + for (int i=0; i<=int(steps); ++i) + { + putp(int(x+0.5f),int(y+0.5f),color); + x += incx; + y += incy; + } + +} + +void createMap() +{ + current_sector = 0; + sector s; + s.verts.push_back({ 64.0f, 0.0f}); + s.verts.push_back({256.0f, 0.0f}); + s.verts.push_back({256.0f, 64.0f}); + s.verts.push_back({320.0f, 64.0f}); + s.verts.push_back({320.0f, 320.0f}); + s.verts.push_back({ 0.0f, 320.0f}); + s.verts.push_back({ 0.0f, 64.0f}); + s.verts.push_back({ 64.0f, 64.0f}); + + s.walls.push_back({0,1,{0,0},0.0f,0.0f}); + s.walls.push_back({1,2,{0,0},0.0f,0.0f}); + s.walls.push_back({2,3,{0,0},0.0f,0.0f}); + s.walls.push_back({3,4,{0,0},0.0f,0.0f}); + s.walls.push_back({4,5,{0,0},0.0f,0.0f}); + s.walls.push_back({5,6,{0,0},0.0f,0.0f}); + s.walls.push_back({6,7,{0,0},0.0f,0.0f}); + s.walls.push_back({7,0,{0,0},0.0f,0.0f}); + + for (auto &w : s.walls ) + { + w.u2 = distance(s.verts[w.v1], s.verts[w.v2]) / 64.0f; + vec2 norm = { s.verts[w.v2].x - s.verts[w.v1].x, s.verts[w.v2].y - s.verts[w.v1].y}; + normalize(&norm); + const float tmp = norm.x; norm.x = -norm.y; norm.y = tmp; + w.normal = norm; + } + sectors.push_back(s); + +} + +void drawColumn(sector &s, int screen_column, int start, int end, float a_inc, vec2 infi) +{ + const float angle = orientation + a_inc; + vec2 normal = { SDL_cosf(angle*DEG_TO_RAD), SDL_sinf(angle*DEG_TO_RAD) }; + vec2 result, tmp_result; + wall *w = nullptr; + float dist=100000.0f; + + for (auto &wall : s.walls) + { + if (dot(normal, wall.normal) >= 0) continue; + if (get_line_intersection(position, infi, s.verts[wall.v1], s.verts[wall.v2], &tmp_result)) + { + const float d = distance(position, tmp_result);// * SDL_cosf(a_inc*DEG_TO_RAD); + if (dv2].x-s.verts[w->v1].x, s.verts[w->v2].y-s.verts[w->v1].y}; + const vec2 AP = {result.x-s.verts[w->v1].x, result.y-s.verts[w->v1].y}; + float v = dot(AP,AB) / dot(AB,AB); v *= w->u2; v = (v-int(v))*64.0f; + //const float v = distance(s.verts[w.v1], result); + float wall_height = (64*277)/dist; + float dpix = 64/wall_height; + float cpix = 0; + float wall_start = 120-(wall_height/64)*(64-height); + if (wall_start<0) { + cpix = -wall_start*dpix; + wall_height += wall_start; + wall_start=0; + } + + // Pinta el sostre + for (int y=0; y> 1)); + float actual_dist = straight_dist / SDL_cosf(a_inc*DEG_TO_RAD); + int tx = abs(int(actual_dist * SDL_cosf(angle*DEG_TO_RAD) - position.x)) % 64; + int ty = abs(int(actual_dist * SDL_sinf(angle*DEG_TO_RAD) - position.y)) % 64; + putp(screen_column, y, gif[tx+ty*64]); + } + + // Pinta la pared + for (int i=0; i=240) break; + putp(screen_column, wall_start+i, gif[(int(v)%64)+int(cpix)*64]); + cpix += dpix; + } + + // Pinta el piso + int paint_end = wall_start+wall_height-1; + for (int y=paint_end+1; y<240-1; y++) { + float straight_dist = (277 * height) / (y - (240 >> 1)); + float actual_dist = straight_dist / SDL_cosf(a_inc*DEG_TO_RAD); + int tx = abs(int(actual_dist * SDL_cosf(angle*DEG_TO_RAD) + position.x)) % 64; + int ty = abs(int(actual_dist * SDL_sinf(angle*DEG_TO_RAD) + position.y)) % 64; + putp(screen_column, y, gif[tx+ty*64]); + } + //line(screen_column, 120-(wall_height), screen_column, 120+(wall_height), 5); + } +} + +int main(int argc, char *argv[]) +{ + SDL_Init(SDL_INIT_VIDEO); + sdl_window = SDL_CreateWindow("WOLF", 640, 480, 0); + SDL_SetWindowPosition(sdl_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + sdl_renderer = SDL_CreateRenderer(sdl_window, NULL); + sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 240); + + debug::init(sdl_renderer); + + FILE *f = fopen("walls.gif", "rb"); + fseek(f, 0, SEEK_END); + int filesize = ftell(f); + fseek(f, 0, SEEK_SET); + Uint8 *buffer = (Uint8*)malloc(filesize); + fread(buffer, filesize, 1, f); + fclose(f); + Uint16 w, h; + gif = LoadGif(buffer, &w, &h); + palette = LoadPalette(buffer); + free(buffer); + + createMap(); + + SDL_Event e; + bool should_exit = false; + Uint32 millis = SDL_GetTicks(); + float dt; + + int fps = 0; + int fps_count = 0; + int fps_time = SDL_GetTicks(); + + while (!should_exit) + { + dt = float(SDL_GetTicks() - millis)/1000.0f; + millis = SDL_GetTicks(); + + while (SDL_PollEvent(&e)) + { + if (e.type==SDL_EVENT_QUIT) { should_exit=true; break; } + if (e.type==SDL_EVENT_KEY_DOWN && e.key.scancode==SDL_SCANCODE_ESCAPE) { should_exit=true; break; } + } + + sector &s = sectors[current_sector]; + + const bool *keys = SDL_GetKeyboardState(NULL); + if (keys[SDL_SCANCODE_Q]) height += dt*speed; + if (keys[SDL_SCANCODE_A]) height -= dt*speed; + if (keys[SDL_SCANCODE_RIGHT]) orientation += dt*speed; + if (keys[SDL_SCANCODE_LEFT]) orientation -= dt*speed; + if (keys[SDL_SCANCODE_UP]) + { + vec2 newpos = { position.x + SDL_cosf(orientation*DEG_TO_RAD)*5, position.y }; + bool collision=false; + for (auto w : s.walls) if (get_line_intersection(position, newpos, s.verts[w.v1], s.verts[w.v2], NULL)) { collision=true; break; } + if (!collision) position.x += SDL_cosf(orientation*DEG_TO_RAD)*dt*speed; + + newpos = { position.x, position.y + SDL_sinf(orientation*DEG_TO_RAD)*5 }; + collision=false; + for (auto w : s.walls) if (get_line_intersection(position, newpos, s.verts[w.v1], s.verts[w.v2], NULL)) { collision=true; break; } + if (!collision) position.y += SDL_sinf(orientation*DEG_TO_RAD)*dt*speed; + } + if (keys[SDL_SCANCODE_DOWN]) + { + position.x -= SDL_cosf(orientation*DEG_TO_RAD)*dt*speed; + position.y -= SDL_sinf(orientation*DEG_TO_RAD)*dt*speed; + } + + // Clear screen + SDL_memset4(screen, 0x00000000, (320*240)>>2); + + int screen_column = 0; + for (float a_inc=-32.0f; a_inc<=32.0f; a_inc+=0.2f) + { + const float angle = orientation + a_inc; + vec2 infi; + infi.x = position.x + SDL_cosf(angle*DEG_TO_RAD)*40000; + infi.y = position.y + SDL_sinf(angle*DEG_TO_RAD)*40000; + + drawColumn(s, screen_column, 0, 240, a_inc, infi); + /* + vec2 result, tmp_result; + wall *w = nullptr; + float dist=100000.0f; + + for (auto &wall : s.walls) + { + if (get_line_intersection(position, infi, s.verts[wall.v1], s.verts[wall.v2], &tmp_result)) + { + const float d = distance(position, tmp_result);// * SDL_cosf(a_inc*DEG_TO_RAD); + if (dv2].x-s.verts[w->v1].x, s.verts[w->v2].y-s.verts[w->v1].y}; + const vec2 AP = {result.x-s.verts[w->v1].x, result.y-s.verts[w->v1].y}; + float v = dot(AP,AB) / dot(AB,AB); v *= w->u2; v = (v-int(v))*64.0f; + //const float v = distance(s.verts[w.v1], result); + float wall_height = (64*277)/dist; + float dpix = 64/wall_height; + float cpix = 0; + float wall_start = 120-(wall_height/64)*(64-height); + if (wall_start<0) { + cpix = -wall_start*dpix; + wall_height += wall_start; + wall_start=0; + } + + // Pinta el sostre + for (int y=0; y> 1)); + float actual_dist = straight_dist / SDL_cosf(a_inc*DEG_TO_RAD); + int tx = abs(int(actual_dist * SDL_cosf(angle*DEG_TO_RAD) - position.x)) % 64; + int ty = abs(int(actual_dist * SDL_sinf(angle*DEG_TO_RAD) - position.y)) % 64; + putp(screen_column, y, gif[tx+ty*64]); + } + + // Pinta la pared + for (int i=0; i=240) break; + putp(screen_column, wall_start+i, gif[(int(v)%64)+int(cpix)*64]); + cpix += dpix; + } + + // Pinta el piso + int paint_end = wall_start+wall_height-1; + for (int y=paint_end+1; y<240-1; y++) { + float straight_dist = (277 * height) / (y - (240 >> 1)); + float actual_dist = straight_dist / SDL_cosf(a_inc*DEG_TO_RAD); + int tx = abs(int(actual_dist * SDL_cosf(angle*DEG_TO_RAD) + position.x)) % 64; + int ty = abs(int(actual_dist * SDL_sinf(angle*DEG_TO_RAD) + position.y)) % 64; + putp(screen_column, y, gif[tx+ty*64]); + } + //line(screen_column, 120-(wall_height), screen_column, 120+(wall_height), 5); + } + */ + screen_column++; + } + + // Draw map walls + for (auto &w : s.walls) { + line(s.verts[w.v1].x/8, s.verts[w.v1].y/8, s.verts[w.v2].x/8, s.verts[w.v2].y/8, 4); + } + + // Draw map hero + vec2 lookat; + lookat.x = position.x + SDL_cosf(orientation*DEG_TO_RAD)*4; + lookat.y = position.y + SDL_sinf(orientation*DEG_TO_RAD)*4; + line(position.x/8, position.y/8, lookat.x/8, lookat.y/8, 1); + putp(int(position.x/8),int(position.y/8),7); + + // Send to texture and render + Uint32 *pixels; + int pitch; + SDL_LockTexture(sdl_texture, NULL, (void**)&pixels, &pitch); + for (int i=0; i<(320*240); ++i) + { + pixels[i] = 0xFF000000 | palette[screen[i]]; + } + SDL_UnlockTexture(sdl_texture); + SDL_RenderTexture(sdl_renderer, sdl_texture, NULL, NULL); + + fps_count++; + if (SDL_GetTicks()-fps_time>=1000) + { + fps = fps_count; + fps_count = 0; + fps_time = SDL_GetTicks(); + } + debug::println("fps:", fps); + debug::render(sdl_renderer); + + SDL_RenderPresent(sdl_renderer); + } + + return 0; +} \ No newline at end of file diff --git a/walls.gif b/walls.gif new file mode 100644 index 0000000..1cff7b1 Binary files /dev/null and b/walls.gif differ