diff --git a/.gitattributes b/.gitattributes index 1779aa5..86467ff 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ *.png filter=lfs diff=lfs merge=lfs -text *.ogg filter=lfs diff=lfs merge=lfs -text *.xm filter=lfs diff=lfs merge=lfs -text +*.tga filter=lfs diff=lfs merge=lfs -text diff --git a/CMakeLists.txt b/CMakeLists.txt index a260110..569cb32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,7 @@ set(TWN_SOURCE_FILES src/rendering/twn_text.c src/rendering/twn_triangles.c src/rendering/twn_circles.c + src/rendering/twn_skybox.c # for dynamic load based solution main is compiled in a separate target $<$>:src/twn_main.c @@ -300,6 +301,8 @@ function(use_townengine target sources output_directory data_dir) set(TWN_BOOTSTRAP_EXEC_ARGS "$,--data-dir ./data.${PACKAGE_EXTENSION},--data-dir ${data_dir}>") + # todo: generate by python script instead + # todo: handle the case where no numerical trace exists string(JOIN "\n" TWN_BOOTSTRAP_SH "#!/bin/env sh" "cd \"$(dirname \"$0\")\"" diff --git a/apps/scenery/scenes/ingame.c b/apps/scenery/scenes/ingame.c index 5d48ee2..2d3ca37 100644 --- a/apps/scenery/scenes/ingame.c +++ b/apps/scenery/scenes/ingame.c @@ -58,28 +58,30 @@ static void ingame_tick(State *state) { for (int y = 64; y--;) { for (int x = 64; x--;) { - float d0 = stb_perlin_noise3((float)x * TERRAIN_FREQUENCY, (float)y * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 20 - 6; - float d1 = stb_perlin_noise3((float)(x + 1) * TERRAIN_FREQUENCY, (float)y * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 20 - 6; - float d2 = stb_perlin_noise3((float)(x + 1) * TERRAIN_FREQUENCY, (float)(y - 1) * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 20 - 6; - float d3 = stb_perlin_noise3((float)x * TERRAIN_FREQUENCY, (float)(y - 1) * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 20 - 6; + float d0 = stb_perlin_noise3((float)x * TERRAIN_FREQUENCY, (float)y * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 3 - 6; + float d1 = stb_perlin_noise3((float)(x + 1) * TERRAIN_FREQUENCY, (float)y * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 3 - 6; + float d2 = stb_perlin_noise3((float)(x + 1) * TERRAIN_FREQUENCY, (float)(y - 1) * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 3 - 6; + float d3 = stb_perlin_noise3((float)x * TERRAIN_FREQUENCY, (float)(y - 1) * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 3 - 6; - unfurl_triangle("/assets/grass.gif", + unfurl_triangle("/assets/grass.png", (Vec3){ (float)x, d0, (float)y }, (Vec3){ (float)x + 1, d1, (float)y }, (Vec3){ (float)x, d3, (float)y - 1 }, - (Vec2sh){ 1024, 768 }, - (Vec2sh){ 1024, 0 }, - (Vec2sh){ 0, 768 }); + (Vec2sh){ 128, 128 }, + (Vec2sh){ 128, 0 }, + (Vec2sh){ 0, 128 }); - unfurl_triangle("/assets/grass.gif", + unfurl_triangle("/assets/grass.png", (Vec3){ (float)x + 1, d1, (float)y }, (Vec3){ (float)x + 1, d2, (float)y - 1 }, (Vec3){ (float)x, d3, (float)y - 1 }, - (Vec2sh){ 1024, 0 }, + (Vec2sh){ 128, 0 }, (Vec2sh){ 0, 0 }, - (Vec2sh){ 0, 768 }); + (Vec2sh){ 0, 128 }); } } + + push_skybox("/assets/miramar/miramar_*.tga"); } diff --git a/data/assets/grass.gif b/data/assets/grass.gif deleted file mode 100644 index af9a09f..0000000 Binary files a/data/assets/grass.gif and /dev/null differ diff --git a/data/assets/grass.png b/data/assets/grass.png new file mode 100644 index 0000000..b7425e2 --- /dev/null +++ b/data/assets/grass.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fb40609623602651097527c2896ae4890b4d34d24a9c81a50f557d6d9e97e31 +size 111676 diff --git a/data/assets/miramar/README.TXT b/data/assets/miramar/README.TXT new file mode 100644 index 0000000..909ab96 --- /dev/null +++ b/data/assets/miramar/README.TXT @@ -0,0 +1,15 @@ +THIS SKY WAS UPDATED AT THE 27TH +THE ORIG HAD SOME ERRORS + +MIRAMAR +high res 1024^2 environment map +ships as TGA. + + +By Jockum Skoglund aka hipshot +hipshot@zfight.com +www.zfight.com +Stockholm, 2005 08 25 + + +Modify however you like, just cred me for my work, maybe link to my page. diff --git a/data/assets/miramar/miramar_down.tga b/data/assets/miramar/miramar_down.tga new file mode 100644 index 0000000..b814f57 --- /dev/null +++ b/data/assets/miramar/miramar_down.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ba4b02c44ddc2a91c08c491c39adfe86b93d3a2f57609b87eef59d0349ef6cc +size 196626 diff --git a/data/assets/miramar/miramar_east.tga b/data/assets/miramar/miramar_east.tga new file mode 100644 index 0000000..c5388b7 --- /dev/null +++ b/data/assets/miramar/miramar_east.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e85d35e4346b6d80cad4d3a0b5290cc4752da25c8fc7bd7c48c0a4ba796ff4d +size 196626 diff --git a/data/assets/miramar/miramar_north.tga b/data/assets/miramar/miramar_north.tga new file mode 100644 index 0000000..ac5a1f3 --- /dev/null +++ b/data/assets/miramar/miramar_north.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce9c1af06a83bd0f8f93a44b81404255391b272efbb59d99163521657a325dd0 +size 196626 diff --git a/data/assets/miramar/miramar_south.tga b/data/assets/miramar/miramar_south.tga new file mode 100644 index 0000000..a9f792c --- /dev/null +++ b/data/assets/miramar/miramar_south.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd2dbb920b542b1c4caf91bf5289331df0434a8ffa7b0cf6c3a40ecf50aae977 +size 196626 diff --git a/data/assets/miramar/miramar_up.tga b/data/assets/miramar/miramar_up.tga new file mode 100644 index 0000000..3656adc --- /dev/null +++ b/data/assets/miramar/miramar_up.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7533ec7e7ddd3987fb7627e7de350ad84af57a3c64c1dd90a29ea3994eb40e3 +size 196626 diff --git a/data/assets/miramar/miramar_west.tga b/data/assets/miramar/miramar_west.tga new file mode 100644 index 0000000..000eabb --- /dev/null +++ b/data/assets/miramar/miramar_west.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:46818c3ae4320543deaf2ba3037b15675ab2557af2bd144958216899cbfd47e7 +size 196626 diff --git a/include/twn_rendering.h b/include/twn_rendering.h index d7041c4..5cf1740 100644 --- a/include/twn_rendering.h +++ b/include/twn_rendering.h @@ -73,4 +73,7 @@ TWN_API void unfurl_triangle(const char *path, /* pushes a camera state to be used for all future unfurl_* commands */ TWN_API void set_camera(const Camera *camera); +/* expects '*' masks that will be expanded to 6 names: 'up', 'down', 'east', 'west', 'north' and 'south' */ +TWN_API void push_skybox(const char *paths); + #endif diff --git a/src/rendering/twn_gl_15_rendering.c b/src/rendering/twn_gl_15_rendering.c index 1da4391..eaf651d 100644 --- a/src/rendering/twn_gl_15_rendering.c +++ b/src/rendering/twn_gl_15_rendering.c @@ -1,5 +1,6 @@ #include "twn_rendering_c.h" #include "twn_util.h" +#include "twn_util_c.h" #include "twn_config.h" #include "twn_engine_context_c.h" #include "twn_text_c.h" @@ -464,3 +465,152 @@ void finally_draw_text(FontData const *font_data, size_t get_text_payload_size(void) { return sizeof (ElementIndexedQuadWithoutColor); } + +static void load_cubemap_side(const char *path, GLenum target) { + SDL_Surface *surface = textures_load_surface(path); + /* TODO: sanity check whether all of them have same dimensions? */ + glTexImage2D(target, + 0, + GL_RGBA8, + surface->w, surface->h, + 0, + surface->format->BytesPerPixel == 4 ? GL_RGBA : GL_RGB, + GL_UNSIGNED_BYTE, + surface->pixels); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + SDL_free(surface->pixels); + SDL_FreeSurface(surface); +} + +void finally_render_skybox(char *paths) { + static GLuint cubemap = 0; + static char *paths_cache = NULL; + + bool loading_needed = false; + + /* drop it */ + if (!paths_cache || (SDL_strcmp(paths_cache, paths) != 0)) { + if (cubemap) + glDeleteTextures(1, &cubemap); + glGenTextures(1, &cubemap); + if (paths_cache) + SDL_free(paths_cache); + paths_cache = paths; + loading_needed = true; + } + + Matrix4 camera_look_at_matrix_solipsist = camera_look_at_matrix; + camera_look_at_matrix_solipsist.row[3].x = 0; + camera_look_at_matrix_solipsist.row[3].y = 0; + camera_look_at_matrix_solipsist.row[3].z = 0; + + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(&camera_look_at_matrix_solipsist.row[0].x); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_CUBE_MAP); + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); + + /* note: assumes that space pipeline is applied already */ + glDisable(GL_ALPHA_TEST); + glDepthMask(GL_TRUE); + + if (loading_needed) { + /* load all the sides */ + char *expanded = expand_asterisk(paths, "up"); + load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Y); + SDL_free(expanded); + + expanded = expand_asterisk(paths, "down"); + load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y); + SDL_free(expanded); + + expanded = expand_asterisk(paths, "east"); + load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_X); + SDL_free(expanded); + + expanded = expand_asterisk(paths, "north"); + load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_POSITIVE_Z); + SDL_free(expanded); + + expanded = expand_asterisk(paths, "west"); + load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_X); + SDL_free(expanded); + + expanded = expand_asterisk(paths, "south"); + load_cubemap_side(expanded, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); + SDL_free(expanded); + } + + /* TODO: use lists at the very least */ + /* TODO: figure out which coordinates to use to not have issues with far z */ + + glBegin(GL_QUADS); { + /* up */ + glTexCoord3f(50.f, 50.f, 50.f); + glVertex3f(50.f, 50.f, 50.f); + glTexCoord3f(-50.f, 50.f, 50.f); + glVertex3f(-50.f, 50.f, 50.f); + glTexCoord3f(-50.f, 50.f, -50.f); + glVertex3f(-50.f, 50.f, -50.f); + glTexCoord3f(50.f, 50.f, -50.f); + glVertex3f(50.f, 50.f, -50.f); + + /* down */ + glTexCoord3f(50.f, -50.f, 50.f); + glVertex3f(50.f, -50.f, 50.f); + glTexCoord3f(50.f, -50.f, -50.f); + glVertex3f(50.f, -50.f, -50.f); + glTexCoord3f(-50.f, -50.f, -50.f); + glVertex3f(-50.f, -50.f, -50.f); + glTexCoord3f(-50.f, -50.f, 50.f); + glVertex3f(-50.f, -50.f, 50.f); + + /* east */ + glTexCoord3f(50.f, -50.f, 50.f); + glVertex3f(50.f, -50.f, 50.f); + glTexCoord3f(50.f, 50.f, 50.f); + glVertex3f(50.f, 50.f, 50.f); + glTexCoord3f(50.f, 50.f, -50.f); + glVertex3f(50.f, 50.f, -50.f); + glTexCoord3f(50.f, -50.f, -50.f); + glVertex3f(50.f, -50.f, -50.f); + + /* west */ + glTexCoord3f(-50.f, -50.f, 50.f); + glVertex3f(-50.f, -50.f, 50.f); + glTexCoord3f(-50.f, -50.f, -50.f); + glVertex3f(-50.f, -50.f, -50.f); + glTexCoord3f(-50.f, 50.f, -50.f); + glVertex3f(-50.f, 50.f, -50.f); + glTexCoord3f(-50.f, 50.f, 50.f); + glVertex3f(-50.f, 50.f, 50.f); + + /* north */ + glTexCoord3f(-50.f, -50.f, 50.f); + glVertex3f(-50.f, -50.f, 50.f); + glTexCoord3f(-50.f, 50.f, 50.f); + glVertex3f(-50.f, 50.f, 50.f); + glTexCoord3f(50.f, 50.f, 50.f); + glVertex3f(50.f, 50.f, 50.f); + glTexCoord3f(50.f, -50.f, 50.f); + glVertex3f(50.f, -50.f, 50.f); + + /* south */ + glTexCoord3f(-50.f, -50.f, -50.f); + glVertex3f(-50.f, -50.f, -50.f); + glTexCoord3f(50.f, -50.f, -50.f); + glVertex3f(50.f, -50.f, -50.f); + glTexCoord3f(50.f, 50.f, -50.f); + glVertex3f(50.f, 50.f, -50.f); + glTexCoord3f(-50.f, 50.f, -50.f); + glVertex3f(-50.f, 50.f, -50.f); + } glEnd(); + + glDisable(GL_TEXTURE_CUBE_MAP); +} diff --git a/src/rendering/twn_gl_any_rendering.c b/src/rendering/twn_gl_any_rendering.c index be74346..0af4320 100644 --- a/src/rendering/twn_gl_any_rendering.c +++ b/src/rendering/twn_gl_any_rendering.c @@ -70,6 +70,7 @@ void clear_draw_buffer(void) { (1.0f / 255) * 230, (1.0f / 255) * 230, 1); + /* TODO: don't clear color when skybox is applied? */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); diff --git a/src/rendering/twn_rendering.c b/src/rendering/twn_rendering.c index e88acf3..a2cf0c8 100644 --- a/src/rendering/twn_rendering.c +++ b/src/rendering/twn_rendering.c @@ -135,6 +135,7 @@ void render(void) { clear_draw_buffer(); render_space(); + render_skybox(); /* after space, as to use depth buffer for early rejection */ render_2d(); swap_buffers(); } diff --git a/src/rendering/twn_rendering_c.h b/src/rendering/twn_rendering_c.h index d99a4fc..19f886f 100644 --- a/src/rendering/twn_rendering_c.h +++ b/src/rendering/twn_rendering_c.h @@ -219,4 +219,8 @@ void finally_draw_text(FontData const *font_data, Color color, VertexBuffer buffer); +void render_skybox(void); + +void finally_render_skybox(char *paths_in_use); + #endif diff --git a/src/rendering/twn_skybox.c b/src/rendering/twn_skybox.c new file mode 100644 index 0000000..94a719c --- /dev/null +++ b/src/rendering/twn_skybox.c @@ -0,0 +1,26 @@ +#include "twn_rendering.h" +#include "twn_rendering_c.h" + +#include + +char *paths_in_use; + +void push_skybox(const char *paths) { + if (paths_in_use && SDL_strcmp(paths, paths_in_use) == 0) + return; + + if (paths_in_use) + SDL_free(paths_in_use); + + paths_in_use = SDL_strdup(paths); +} + + +void render_skybox(void) { + if (!paths_in_use) + return; + + /* note: ownership of 'paths_in_use' goes there */ + finally_render_skybox(paths_in_use); + paths_in_use = NULL; +} diff --git a/src/twn_textures.c b/src/twn_textures.c index 9c26c36..4dfbd5d 100644 --- a/src/twn_textures.c +++ b/src/twn_textures.c @@ -42,7 +42,7 @@ static int load_eof_callback(void *user) { return context->position == context->size; } -static SDL_Surface *image_to_surface(const char *path) { +SDL_Surface *textures_load_surface(const char *path) { SDL_RWops *handle = PHYSFSRWOPS_openRead(path); if (handle == NULL) goto ERR_CANNOT_OPEN_FILE; @@ -359,7 +359,7 @@ static TextureKey textures_load(TextureCache *cache, const char *path) { if (i >= 0) return (TextureKey){ (uint16_t)i }; - SDL_Surface *surface = image_to_surface(path); + SDL_Surface *surface = textures_load_surface(path); Texture new_texture = { .data = surface, .mode = infer_texture_mode(surface), diff --git a/src/twn_textures_c.h b/src/twn_textures_c.h index 36867dc..c3e2e63 100644 --- a/src/twn_textures_c.h +++ b/src/twn_textures_c.h @@ -89,4 +89,8 @@ size_t textures_get_num_atlases(const TextureCache *cache); /* TODO: should recieve texture_cache, get_key optimization cache should be cleared some other way */ void textures_reset_state(void); +/* uncached low-level loading */ +/* warn: surface->pixels must be freed along side the surface itself */ +SDL_Surface *textures_load_surface(const char *path); + #endif diff --git a/src/twn_util.c b/src/twn_util.c index 10f14fc..bf2b30a 100644 --- a/src/twn_util.c +++ b/src/twn_util.c @@ -253,3 +253,20 @@ bool repeat_ftimer(float *value, float at) { } return false; } + +/* TODO: handle utf8 */ +char *expand_asterisk(const char *mask, const char *to) { + const char *offset = SDL_strchr(mask, '*'); + if (!offset) { + CRY("Invalid path", "Asterisk should be given."); + return NULL; + } + size_t const mask_len = SDL_strlen(mask); + size_t const to_len = SDL_strlen(to); + char *str = SDL_malloc(mask_len + to_len); /* NULL included, replacing the original asterisk */ + SDL_memcpy(str, mask, offset - mask); + SDL_memcpy(str + (offset - mask), to, to_len); + SDL_memcpy(str + (offset - mask) + to_len, offset + 1, mask_len - (offset - mask)); + str[mask_len + to_len] = '\0'; + return str; +} diff --git a/src/twn_util_c.h b/src/twn_util_c.h new file mode 100644 index 0000000..0aceed8 --- /dev/null +++ b/src/twn_util_c.h @@ -0,0 +1,7 @@ +#ifndef TWN_UTIL_C_H +#define TWN_UTIL_C_H + +/* note: you must free the returned string */ +char *expand_asterisk(const char *mask, const char *to); + +#endif