From 062067a033bec9d016784b11656e39add248fa0a Mon Sep 17 00:00:00 2001 From: DaniTheSkunk <> Date: Sat, 31 Dec 2022 11:14:57 +0000 Subject: [PATCH] gsa is rendering texture'ish now --- README.md | 15 ++++ build.bat | 2 +- examples/gsa_simple.c | 16 ++++ gfx.png | Bin 0 -> 20482 bytes include/color8.h | 8 ++ include/gsa.h | 56 +++++++++++++ include/image8.h | 20 +++++ include/shader.h | 24 ++++++ include/skunkworks.h | 1 + include/types.h | 4 + include/window.h | 2 +- meson.build | 15 +++- src/gsa.c | 185 ++++++++++++++++++++++++++++++++++++++++++ src/image32.c | 2 +- src/image8.c | 111 +++++++++++++++++++++++++ src/shader.c | 60 ++++++++++++++ src/skunkworks.h | 9 ++ src/test.c | 12 ++- src/window.c | 21 +++-- 19 files changed, 545 insertions(+), 18 deletions(-) create mode 100644 examples/gsa_simple.c create mode 100644 gfx.png create mode 100644 include/color8.h create mode 100644 include/gsa.h create mode 100644 include/image8.h create mode 100644 include/shader.h create mode 100644 src/gsa.c create mode 100644 src/image8.c create mode 100644 src/shader.c diff --git a/README.md b/README.md index 7105676..9456e30 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,18 @@ function order: - static functions(ones that don't take object as parameter) - empty line - methods(ones that do take object as parameter) + +## game skunk advance stuffs + +do lots automagic... +magic main function within the header? +autocalling update and init function. +texture loading compile time? parse directory, make a variable for each (player.png -> tex_player), and a loading function that will load all of them. + +### game skunk advance specs +8-bit colour, but user changeable palette(realtime) +tilesize 16x16 +screensize 304x176 (19x11 tiles) +multiple tilesets... or singular big tileset? the latter... could be a nice simplification... maybe 65536 tiles, a 4096x4096 pixels texture +4 tilemaps, 1024x1024 each, tileset offsets?, rotation and other effects +256 sprites (using tileset) diff --git a/build.bat b/build.bat index 3bbe4a1..cbae06f 100644 --- a/build.bat +++ b/build.bat @@ -2,5 +2,5 @@ REM cd build && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -GNinja .. && ninja && copy compile_commands.json .. && skunkworks.exe -cd build && meson compile && copy compile_commands.json .. && skunktest.exe +cd build && meson compile && copy compile_commands.json .. && cd .. && build\gsa.exe diff --git a/examples/gsa_simple.c b/examples/gsa_simple.c new file mode 100644 index 0000000..a8b6c7d --- /dev/null +++ b/examples/gsa_simple.c @@ -0,0 +1,16 @@ +#include + +void init() { + sprites[0].tile = 2; + sprites[0].x = 10; + sprites[0].y = 10; + + sprites[1].tile = 3; + sprites[1].x = 10; + sprites[1].y = 100; +} + +void tick() { + sprites[0].x += 1; + sprites[1].x += 2; +} diff --git a/gfx.png b/gfx.png new file mode 100644 index 0000000000000000000000000000000000000000..0491d1ac1bf8b9c484a4b4e7f3df3a49a8d43964 GIT binary patch literal 20482 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 X?0Ct)=W<>@F;TB|zH5tDhaLV0pI$Tp literal 0 HcmV?d00001 diff --git a/include/color8.h b/include/color8.h new file mode 100644 index 0000000..3cda90c --- /dev/null +++ b/include/color8.h @@ -0,0 +1,8 @@ +#ifndef GUARD_025B7F5FAD7E029F9A2F84062CDA4F53 +#define GUARD_025B7F5FAD7E029F9A2F84062CDA4F53 + +#include "types.h" + +typedef u8 sw_color8; + +#endif /* GUARD_025B7F5FAD7E029F9A2F84062CDA4F53 */ diff --git a/include/gsa.h b/include/gsa.h new file mode 100644 index 0000000..6a03cd9 --- /dev/null +++ b/include/gsa.h @@ -0,0 +1,56 @@ +/************************************************************************/ +/* ________ ___________ __ */ +/* / _____/_____ _____ ____ / _____/ | ____ __ ____ | | __ */ +/* / \ ___\__ \ / \_/ __ \ \_____ \| |/ / | \/ \| |/ / */ +/* \ \_\ \/ __ \| Y Y \ ___/ / \ <| | / | \ < */ +/* \______ (____ /__|_| /\___ >_______ /__|_ \____/|___| /__|_ \ */ +/* \/ \/ \/ \/ \/ \/ \/ \/ */ +/* _____ .___ */ +/* / _ \ __| _/__ _______ ____ ____ ____ */ +/* / /_\ \ / __ |\ \/ /\__ \ / \_/ ___\/ __ \ */ +/* / | \/ /_/ | \ / / __ \| | \ \__\ ___/ */ +/* \____|__ /\____ | \_/ (____ /___| /\___ >___ > */ +/* \/ \/ \/ \/ \/ \/ */ +/************************************************************************/ + +#ifndef GUARD_73FF49EF137A66E6AAD3A8A1BCF2F2DE +#define GUARD_73FF49EF137A66E6AAD3A8A1BCF2F2DE + +#include "image8.h" +#ifndef GSA_NOMAIN +#include "embed_gfx.h" +#endif + +#include "skunkworks.h" +#include "vec2i.h" +#include "window.h" + +struct gsa_sprite { + u16 tile; + i32 x, y; +}; + +#define MAX_SPRITES 256 + +extern struct gsa_sprite sprites[MAX_SPRITES]; +extern struct sw_image8 *_gfx; + +int gsa_main(int argc, char *argv[]); + +/* to be implemented in game */ + +void init(); +void tick(); + +#ifndef GSA_NOMAIN +int main(int argc, char *argv[]) { + _gfx = sw_image8_load_png_data(___gfx_png, ___gfx_png_len); + gsa_main(argc, argv); + + return 0; +} +#endif + +void _gsa_tick(); + +#endif /* GUARD_73FF49EF137A66E6AAD3A8A1BCF2F2DE */ diff --git a/include/image8.h b/include/image8.h new file mode 100644 index 0000000..3956d3c --- /dev/null +++ b/include/image8.h @@ -0,0 +1,20 @@ +#ifndef GUARD_6AEC99B12E1F76DC4E50DC199E93CDB5 +#define GUARD_6AEC99B12E1F76DC4E50DC199E93CDB5 + +#include "color8.h" +#include "vec2i.h" + +struct sw_image8 { + struct sw_vec2i size; + sw_color8 *_data; +}; + +struct sw_image8 *sw_image8_create(struct sw_vec2i size); +void sw_image8_destroy(struct sw_image8 *image); + +struct sw_image8 *sw_image8_load_png(char *path); +struct sw_image8 *sw_image8_load_png_data(u8 *data, u32 data_len); + +sw_color8 sw_image8_get(struct sw_image8 *image, struct sw_vec2i pos); + +#endif /* GUARD_6AEC99B12E1F76DC4E50DC199E93CDB5 */ diff --git a/include/shader.h b/include/shader.h new file mode 100644 index 0000000..e48b7a9 --- /dev/null +++ b/include/shader.h @@ -0,0 +1,24 @@ +#ifndef GUARD_2AF8C38E79755453C7B276BABE0DA7AE +#define GUARD_2AF8C38E79755453C7B276BABE0DA7AE + +#include "types.h" + +struct sw_shader { + i32 _shader; +}; + +struct sw_shaderprogram { + i32 _program; +}; + +#define SW_SHADER_VERTEX 1 +#define SW_SHADER_FRAGMENT 2 + +struct sw_shader sw_shader_create(char const *source, i32 type); + +struct sw_shaderprogram +sw_shaderprogram_create(char const *vertex, char const *fragment); + +void sw_shaderprogram_use(struct sw_shaderprogram program); + +#endif /* GUARD_2AF8C38E79755453C7B276BABE0DA7AE */ diff --git a/include/skunkworks.h b/include/skunkworks.h index a32bb5d..31c687d 100644 --- a/include/skunkworks.h +++ b/include/skunkworks.h @@ -5,6 +5,7 @@ #include "error.h" #include "file.h" #include "image32.h" +#include "image8.h" #include "types.h" #include "vec2i.h" #include "window.h" diff --git a/include/types.h b/include/types.h index e1b0d7d..487df85 100644 --- a/include/types.h +++ b/include/types.h @@ -11,5 +11,9 @@ typedef signed long long i64; typedef unsigned long long u64; typedef float f32; typedef double f64; +typedef i8 bool; + +#define true 1 +#define false 0 #endif /* GUARD_649E63003BEAE79ECA2B813C4E131C9A */ diff --git a/include/window.h b/include/window.h index a09213e..33f5532 100644 --- a/include/window.h +++ b/include/window.h @@ -13,6 +13,6 @@ struct sw_window { struct sw_window *sw_window_create(struct sw_vec2i size, char *title); -void sw_window_run(struct sw_window *window); +void sw_window_run(struct sw_window *window, void (*callback)()); #endif /* GUARD_F247452E0BF1EC9CD9131C2A6FD281CA */ diff --git a/meson.build b/meson.build index 6b062c3..250da70 100644 --- a/meson.build +++ b/meson.build @@ -43,18 +43,29 @@ skunk_sources = [ 'src/color32.c', 'src/error.c', 'src/file.c', + 'src/gsa.c', 'src/image32.c', + 'src/image8.c', + 'src/shader.c', 'src/skunkworks.c', - 'src/test.c', 'src/vec2i.c', 'src/window.c' ] +xxd = find_program('xxd') +embed_gfx = custom_target('embed-gfx', input: ['gfx.png'], output: ['embed_gfx.h'], + command: [xxd, '-i', '@INPUT@', '@OUTPUT@']) + add_project_arguments('-D_CRT_SECURE_NO_WARNINGS', language : 'c') +add_project_arguments('-Wall', language : 'c') +add_project_arguments('-Wextra', language : 'c') +add_project_arguments('-Werror', language : 'c') if host_machine.system() == 'emscripten' executable('skunktest', skunk_sources, include_directories: 'include', dependencies: deps, link_args: ['-lglfw', '-lGL', '-s', 'USE_GLFW=3'], name_suffix: 'html') else - executable('skunktest', skunk_sources, include_directories: 'include', dependencies: deps) + lib = static_library('skunkworks', skunk_sources, include_directories: 'include', dependencies: deps) + executable('skunktest', 'src/test.c', link_with: lib, include_directories: 'include', dependencies: deps) + executable('gsa', 'examples/gsa_simple.c', embed_gfx, link_with: lib, include_directories: 'include', dependencies: deps) endif \ No newline at end of file diff --git a/src/gsa.c b/src/gsa.c new file mode 100644 index 0000000..fa93b0d --- /dev/null +++ b/src/gsa.c @@ -0,0 +1,185 @@ +#include "error.h" +#include "gl.h" +#include "image8.h" +#include "shader.h" +#include +#define GSA_NOMAIN +#include "gsa.h" + +struct gsa_sprite sprites[256]; + +struct sw_image8 *_gfx; +struct sw_window *_win; + +static char *vert_source = "#version 450\n\ +in vec2 pos;\ +in vec2 tex_coord;\ +layout(location = 0) 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 450\n\ +layout(location = 0) in vec2 tex_coord;\ +uniform sampler2D tex;\ +out vec4 color;\ +void main(){\ +float r = texture(tex, tex_coord).r;\ +if(r > 0)\ +color = vec4(0.9, 0.2, 0.1, 1.0);\ +}\ +"; + +static struct sw_shaderprogram program; + +static u32 vbo, vao; + +#define MAX_RENDER_VERTS 60 + +struct render_vert { + f32 x, y, tx, ty; +}; + +static i32 next_render_vert; +static struct render_vert render_verts[MAX_RENDER_VERTS * 4]; + +int gsa_main(int argc, char *argv[]) { + (void)argc; + (void)argv; + u32 tex; + struct sw_image8 *img; + + 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); + sw_shaderprogram_use(program); + + img = sw_image8_load_png("gfx.png"); + 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_RED, + 4096, + 4096, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + img->_data + ); + sw_image8_destroy(img); + + glGenBuffers(1, &vao); + glBindVertexArray(vao); + + 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") + ); + + init(); + sw_window_run(_win, _gsa_tick); + + return 0; +} + +static void rect(f32 x, f32 y, f32 w, f32 h, i16 tile) { + f32 tx, ty, ts; + + tx = ((tile % 256) * 16.f) / 4096.f; + ty = ((tile / 256) * 16.f) / 4096.f; + ts = 1.f / 256.f; + + 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 + ); + } + + sw_log("tx %f | ty %f | ts %f", tx, ty, ts); + + 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; + + render_verts[next_render_vert].x = x + w; + render_verts[next_render_vert].y = y; + render_verts[next_render_vert].tx = tx + ts; + render_verts[next_render_vert].ty = ty; + ++next_render_vert; + + render_verts[next_render_vert].x = x; + render_verts[next_render_vert].y = y + h; + render_verts[next_render_vert].tx = tx; + render_verts[next_render_vert].ty = ty + ts; + ++next_render_vert; + + render_verts[next_render_vert].x = x + w; + render_verts[next_render_vert].y = y; + render_verts[next_render_vert].tx = tx + ts; + render_verts[next_render_vert].ty = ty; + ++next_render_vert; + + render_verts[next_render_vert].x = x; + render_verts[next_render_vert].y = y + h; + render_verts[next_render_vert].tx = tx; + render_verts[next_render_vert].ty = ty + ts; + ++next_render_vert; + + render_verts[next_render_vert].x = x + w; + render_verts[next_render_vert].y = y + h; + render_verts[next_render_vert].tx = tx + ts; + render_verts[next_render_vert].ty = ty + ts; + ++next_render_vert; +} + +void _gsa_tick() { + i32 i; + + tick(); + + next_render_vert = 0; + /* glBegin(GL_TRIANGLES); */ + for(i = 0; i < MAX_SPRITES; ++i) { + if(sprites[i].tile > 0) { + rect(sprites[i].x, sprites[i].y, 16, 16, sprites[i].tile); + } + } + + glBindVertexArray(vao); + glBufferData( + GL_ARRAY_BUFFER, + sizeof(struct render_vert) * (next_render_vert), + render_verts, + GL_DYNAMIC_DRAW + ); + glDrawArrays(GL_TRIANGLES, 0, next_render_vert); + /* glEnd(); */ +} diff --git a/src/image32.c b/src/image32.c index 7a6ba33..47af531 100644 --- a/src/image32.c +++ b/src/image32.c @@ -43,7 +43,7 @@ struct sw_image32 *sw_image32_load_png_data(u8 *data, u32 data_len) { u32 width, height; u8 color_type, bit_depth; u8 **row_pointers; - i32 i; + u32 i; buf = malloc(sizeof(struct sw_filebuffer)); buf->_data = data; diff --git a/src/image8.c b/src/image8.c new file mode 100644 index 0000000..804be36 --- /dev/null +++ b/src/image8.c @@ -0,0 +1,111 @@ +#include "image8.h" + +#include + +#include "error.h" +#include "file.h" +#include "png.h" +#include "vec2i.h" + +void png_read_fn(png_structp png, png_bytep out, png_size_t count); + +struct sw_image8 *sw_image8_create(struct sw_vec2i size) { + struct sw_image8 *image; + + image = malloc(sizeof(struct sw_image8)); + image->_data = malloc(sizeof(sw_color8) * size.x * size.y); + image->size = size; + + return image; +} + +void sw_image8_destroy(struct sw_image8 *image) { + free(image->_data); + free(image); +} + +struct sw_image8 *sw_image8_load_png(char *path) { + u32 size; + u8 *data; + struct sw_image8 *image; + + data = sw_file_load(path, &size); + image = sw_image8_load_png_data(data, size); + free(data); + return image; +} + +struct sw_image8 *sw_image8_load_png_data(u8 *data, u32 data_len) { + struct sw_image8 *img; + struct sw_filebuffer *buf; + png_structp png; + png_infop info; + u32 width, height; + u8 color_type, bit_depth; + u8 **row_pointers; + u32 i; + + buf = malloc(sizeof(struct sw_filebuffer)); + buf->_data = data; + buf->pos = 0; + buf->size = data_len; + + if(png_sig_cmp(data, 0, 8)) { + sw_error("File isn't recognised as a PNG file"); + } + + /* TODO: add error handles? <_< */ + png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + info = png_create_info_struct(png); + png_set_read_fn(png, buf, png_read_fn); + png_read_info(png, info); + + width = png_get_image_width(png, info); + height = png_get_image_height(png, info); + color_type = png_get_color_type(png, info); + bit_depth = png_get_bit_depth(png, info); + + sw_log( + "loading image of size %ux%u, color_type %u, bit_depth %u", + width, + height, + color_type, + bit_depth + ); + + if(color_type != PNG_COLOR_TYPE_PALETTE) { + sw_error("image8 can only load palette files"); + } + + if(bit_depth != 8) { + sw_error("image32 can currently only load 8 bit files"); + } + + img = sw_image8_create(sw_vec2i(width, height)); + + row_pointers = malloc(sizeof(u8 *) * height); + for(i = 0; i < height; ++i) { + row_pointers[i] = (u8 *)(img->_data + width * i); + } + png_read_image(png, row_pointers); + + free(row_pointers); + free(buf); + + /* TODO: cleanup of png structs? */ + + return img; +} + +sw_color8 sw_image8_get(struct sw_image8 *image, struct sw_vec2i pos) { + return image->_data[pos.x + pos.y * image->size.x]; +} + +/* private */ + +void png_read_fn(png_structp png, png_bytep out, png_size_t count) { + struct sw_filebuffer *buf; + + buf = png_get_io_ptr(png); + sw_filebuffer_read(buf, out, count); +} diff --git a/src/shader.c b/src/shader.c new file mode 100644 index 0000000..487778f --- /dev/null +++ b/src/shader.c @@ -0,0 +1,60 @@ +#include "shader.h" + +#include + +#include "error.h" +#include "gl.h" + +struct sw_shader sw_shader_create(char const *source, i32 type) { + struct sw_shader shader; + i32 gltype; + i32 length; + i32 ret; + + switch(type) { + case SW_SHADER_VERTEX: + gltype = GL_VERTEX_SHADER; + break; + case SW_SHADER_FRAGMENT: + gltype = GL_FRAGMENT_SHADER; + break; + default: + gltype = 0; + sw_error("unknown shader type"); + } + + shader._shader = glCreateShader(gltype); + length = strlen(source); + glShaderSource(shader._shader, 1, &source, &length); + glCompileShader(shader._shader); + + glGetShaderiv(shader._shader, GL_COMPILE_STATUS, &ret); + if(!ret) { + char str[256]; + i32 len; + + glGetShaderInfoLog(shader._shader, 256, &len, str); + sw_error("Shader Compile Error: %s", str); + } + + return shader; +} + +struct sw_shaderprogram +sw_shaderprogram_create(char const *vertex, char const *fragment) { + struct sw_shaderprogram program; + struct sw_shader v, f; + + v = sw_shader_create(vertex, SW_SHADER_VERTEX); + f = sw_shader_create(fragment, SW_SHADER_FRAGMENT); + program._program = glCreateProgram(); + glAttachShader(program._program, v._shader); + glAttachShader(program._program, f._shader); + glLinkProgram(program._program); + + return program; +} + +void sw_shaderprogram_use(struct sw_shaderprogram program) { + glUseProgram(program._program); +} diff --git a/src/skunkworks.h b/src/skunkworks.h index ead3db9..06433c3 100644 --- a/src/skunkworks.h +++ b/src/skunkworks.h @@ -1,3 +1,12 @@ +/***************************************************************************/ +/* ___________ __ __ */ +/* / _____/ | ____ __ ____ | | ____ _ _____________| | __ ______ */ +/* \_____ \| |/ / | \/ \| |/ /\ \/ \/ / _ \_ __ \ |/ / / ___/ */ +/* / \ <| | / | \ < \ ( <_> ) | \/ < \___ \ */ +/* /_______ /__|_ \____/|___| /__|_ \ \/\_/ \____/|__| |__|_ \/____ > */ +/* \/ \/ \/ \/ \/ \/ */ +/***************************************************************************/ + #ifndef GUARD_BAEE408B8F416CA55711305ABAF9CE6C #define GUARD_BAEE408B8F416CA55711305ABAF9CE6C diff --git a/src/test.c b/src/test.c index d65a6e6..2936610 100644 --- a/src/test.c +++ b/src/test.c @@ -14,13 +14,17 @@ void tick(); int main(int argc, char *argv[]) { struct sw_image32 *img; - sw_init(); - printf("hello world\n"); - win = sw_window_create(sw_vec2i(640, 480), "Skunkworks"); + (void)argc; + (void)argv; + sw_init(); + win = sw_window_create(sw_vec2i(640, 480), "Skunkworks"); img = sw_image32_load_png("d:/art/pfp.png"); sw_debug("%08X", sw_image32_get(img, sw_vec2i(10, 10))); + sw_window_run(win, tick); - sw_window_run(win); return 0; } + +void tick() { +} diff --git a/src/window.c b/src/window.c index 555e5ba..1db09b1 100644 --- a/src/window.c +++ b/src/window.c @@ -4,8 +4,9 @@ #include "gl.h" -void tick(); -struct sw_window *tick_window; +void _tick(); +struct sw_window *_tick_window; +void (*_tick_fn)(); struct sw_window *sw_window_create(struct sw_vec2i size, char *title) { struct sw_window *win; @@ -29,21 +30,23 @@ struct sw_window *sw_window_create(struct sw_vec2i size, char *title) { return win; } -void sw_window_run(struct sw_window *window) { - tick_window = window; +void sw_window_run(struct sw_window *window, void (*callback)()) { + _tick_window = window; + _tick_fn = callback; #ifdef __EMSCRIPTEN__ - emscripten_set_main_loop(tick, 60, 1); + emscripten_set_main_loop(_tick, 60, 1); #else while(!glfwWindowShouldClose(window->_window)) { - tick(); + _tick(); } #endif } /* private functions */ -void tick() { - glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(tick_window->_window); +void _tick() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + _tick_fn(); + glfwSwapBuffers(_tick_window->_window); glfwPollEvents(); }