#include "color32.h" #include "error.h" #include "gl.h" #include "image8.h" #include "shader.h" #include "types.h" #include #include #define GSA_NOMAIN #include "gsa.h" #include "gsa_input.h" struct gsa_sprite sprites[256]; struct gsa_map maps[MAX_TILEMAPS]; struct sw_image8 *_gfx; struct sw_window *_win; static char *vert_source = "#version 300 es\n\ precision highp float;\ in vec2 pos;\ in vec2 tex_coord;\ out vec2 out_tex_coord;\ void main() {\ gl_Position = vec4((pos / vec2(152, -88)) - vec2(1, -1), 0.f, 1.f);\ out_tex_coord = tex_coord;\ }\ "; static char *frag_source = "#version 300 es\n\ precision highp float;\ in vec2 out_tex_coord;\ uniform sampler2D tex;\ uniform vec4 palette[256];\ out vec4 color;\ void main(){\ int r = int(texture(tex, out_tex_coord).r * 255.f);\ if(r > 0)\ color = palette[r];\ else discard;\ }\ "; static struct sw_shaderprogram program; static u32 vbo, vao; #define MAX_RENDER_VERTS 10000 struct render_vert { f32 x, y, tx, ty; }; static i32 next_render_vert; static struct render_vert render_verts[MAX_RENDER_VERTS * 4]; static sw_color32 palette[256]; static f32 palette_gl[1024]; static u32 tex; int gsa_main(int argc, char *argv[]) { (void)argc; (void)argv; i32 max_components; sw_log("Initialising GameSkunkAdvance v0.0"); _win = sw_window_create(sw_vec2i(304, 176), "Game Skunk Advance v0.0"); program = sw_shaderprogram_create(vert_source, frag_source); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_components); sw_log("GL_MAX_VERTEX_UNIFORM_COMPONENTS: %i", max_components); memcpy(palette, _gfx->palette, sizeof(_gfx->palette)); sw_debug("%08X", _gfx->palette[1]); 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_run(_win, _gsa_tick); return 0; } static void add_render_vert(f32 x, f32 y, f32 tx, f32 ty) { render_verts[next_render_vert].x = x; render_verts[next_render_vert].y = y; render_verts[next_render_vert].tx = tx; render_verts[next_render_vert].ty = ty; ++next_render_vert; } 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); if(next_render_vert >= MAX_RENDER_VERTS) { sw_error( "trying to draw more than the current max of %i vertices in a " "frame", MAX_RENDER_VERTS ); } 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(); tick(); next_render_vert = 0; 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) * (next_render_vert), render_verts, GL_DYNAMIC_DRAW ); glDrawArrays(GL_TRIANGLES, 0, next_render_vert); glBindVertexArray(0); /* glEnd(); */ }