#include "color32.h" #include "error.h" #include "gl.h" #include "image8.h" #include "renderer.h" #include "shader.h" #include "skip.h" #include "types.h" #include "vertex_buffer.h" #include "window.h" #include #include #define GSA_NOMAIN #include "gsa.h" #include "gsa_input.h" struct gsa_sprite sprites[256]; struct sw_image8 *_gfx; struct sw_window *_win; static struct sw_shaderprogram program; static u32 vbo, vao; struct render_vert { f32 x, y, tx, ty; }; sw_color32 palette[GSA_PALETTE_SIZE]; static f32 palette_gl[1024]; static u32 tex; #define GSA_LOOP_STACK_SIZE 16 static bool (*loop_stack[GSA_LOOP_STACK_SIZE])(); static i8 loop_stack_i; static struct sw_vertex_buffer *vertex_buffer; int gsa_main(int argc, char *argv[]) { (void)argc; (void)argv; i32 max_components; u32 size; u8 *data, *frag_data, *vert_data; sw_log("Initialising GameSkunkAdvance v0.0"); sw_init(argc, argv); sw_log("Grab data"); data = sw_skip_get(sw_skip_self, "gfx.png", &size); _gfx = sw_image8_load_png_data(data, size); vertex_buffer = sw_vertex_buffer_create(sizeof(struct render_vert)); memset(loop_stack, 0, sizeof(loop_stack)); loop_stack_i = -1; _win = sw_window_create(sw_vec2i(304, 176), "Game Skunk Advance v0.0", 0); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_components); sw_log("GL_MAX_VERTEX_UNIFORM_COMPONENTS: %i", max_components); glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &max_components); sw_log("GL_NUM_PROGRAM_BINARY_FORMATS: %i", max_components); frag_data = sw_skip_get_string(sw_skip_self, "gsa_frag.glsl"); vert_data = sw_skip_get_string(sw_skip_self, "gsa_vert.glsl"); program = sw_shaderprogram_create(vert_data, 0, frag_data, 0, false); memcpy(palette, _gfx->palette, sizeof(_gfx->palette)); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, 4096, 4096, 0, GL_RED, GL_UNSIGNED_BYTE, _gfx->_data ); sw_log("setup gsa vao"); glGenVertexArrays(1, &vao); glBindVertexArray(vao); sw_log("setup gsa vbo"); glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glVertexAttribPointer( glGetAttribLocation(program._program, "pos"), 2, GL_FLOAT, GL_FALSE, sizeof(struct render_vert), 0 ); glVertexAttribPointer( glGetAttribLocation(program._program, "tex_coord"), 2, GL_FLOAT, GL_FALSE, sizeof(struct render_vert), (void *)(2 * sizeof(float)) ); glEnableVertexAttribArray(glGetAttribLocation(program._program, "pos")); glEnableVertexAttribArray(glGetAttribLocation(program._program, "tex_coord") ); glBindVertexArray(0); sw_log("gsa setup done"); init(); sw_window_add_renderer(_win, sw_renderer_create(0, 0, 0), _gsa_tick); sw_window_run(_win); return 0; } void gsa_copy_palette_to(sw_color32 *dst) { memcpy(dst, palette, sizeof(palette)); } void gsa_copy_palette_from(sw_color32 *src) { memcpy(palette, src, sizeof(palette)); } void gsa_run_loop(bool (*loopfun)()) { ++loop_stack_i; if(loop_stack_i >= GSA_LOOP_STACK_SIZE) { sw_error("exceeded loop stack size"); } loop_stack[loop_stack_i] = loopfun; } static void add_render_vert(f32 x, f32 y, f32 tx, f32 ty) { struct render_vert v; v.x = x; v.y = y; v.tx = tx; v.ty = ty; sw_vertex_buffer_add(vertex_buffer, &v); } static void rect(f32 x, f32 y, f32 w, f32 h, i16 tile, bool half) { f32 tx, ty, ts; f32 tilesize = half ? 8.f : 16.f; tx = ((tile % 256) * tilesize) / 4096.f; ty = ((tile / 256) * tilesize) / 4096.f; ts = 1.f / (4096.f / tilesize); add_render_vert(x, y, tx, ty); add_render_vert(x + w, y, tx + ts, ty); add_render_vert(x, y + h, tx, ty + ts); add_render_vert(x + w, y, tx + ts, ty); add_render_vert(x, y + h, tx, ty + ts); add_render_vert(x + w, y + h, tx + ts, ty + ts); } static void update_palette_gl() { int i; for(i = 0; i < 256; ++i) { palette_gl[i * 4 + 0] = sw_color32_get_rf(palette[i]); palette_gl[i * 4 + 1] = sw_color32_get_gf(palette[i]); palette_gl[i * 4 + 2] = sw_color32_get_bf(palette[i]); palette_gl[i * 4 + 3] = sw_color32_get_af(palette[i]); } } void _gsa_tick() { i32 i, x, y, startx, starty, endx, endy, tcmult, tilesize; _gsa_input_tick(); if(loop_stack_i == -1) { tick(); } else { if(!loop_stack[loop_stack_i]()) { --loop_stack_i; } } sw_vertex_buffer_clear(vertex_buffer); for(i = 0; i < MAX_TILEMAPS; ++i) { tcmult = maps[i].half_tile ? 2 : 1; tilesize = maps[i].half_tile ? 8 : 16; startx = maps[i].scrollx / tilesize; starty = maps[i].scrolly / tilesize; endx = i32_min(TILEMAP_MAX_SIZE, startx + 20 * tcmult); endy = i32_min(TILEMAP_MAX_SIZE, starty + 12 * tcmult); startx = i32_max(0, startx); starty = i32_max(0, starty); for(x = startx; x <= endx; ++x) { for(y = starty; y <= endy; ++y) { u16 tile = maps[i].tiles[x][y]; if(tile) { rect( x * tilesize - maps[i].scrollx, y * tilesize - maps[i].scrolly, tilesize, tilesize, tile, maps[i].half_tile ); } } } } for(i = 0; i < MAX_SPRITES; ++i) { if(sprites[i].tile > 0) { rect(sprites[i].x, sprites[i].y, 16, 16, sprites[i].tile, false); } } glClearColor( sw_color32_get_rf(palette[0]), sw_color32_get_gf(palette[0]), sw_color32_get_bf(palette[0]), sw_color32_get_af(palette[0]) ); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindVertexArray(vao); sw_shaderprogram_use(program); glBindTexture(GL_TEXTURE_2D, tex); /* TODO: only do when palette changed */ update_palette_gl(); glUniform4fv( glGetUniformLocation(program._program, "palette"), 256, palette_gl ); glBufferData( GL_ARRAY_BUFFER, sizeof(struct render_vert) * vertex_buffer->elem_count, vertex_buffer->data, GL_DYNAMIC_DRAW ); glDrawArrays(GL_TRIANGLES, 0, vertex_buffer->elem_count); glBindVertexArray(0); /* glEnd(); */ }