skunkworks-c/src/gsa.c

235 lines
5.5 KiB
C

#include "color32.h"
#include "error.h"
#include "gl.h"
#include "image8.h"
#include "shader.h"
#include "types.h"
#include <gl/gl.h>
#include <string.h>
#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(); */
}