From adbd2511beec8f1caa1752bdfd755cc2f62ba425 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 9 Mar 2024 08:43:26 -0800 Subject: Make isogfx a library instead of an executable. --- gfx-iso/src/app.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 gfx-iso/src/app.c (limited to 'gfx-iso/src') diff --git a/gfx-iso/src/app.c b/gfx-iso/src/app.c new file mode 100644 index 0000000..079ac96 --- /dev/null +++ b/gfx-iso/src/app.c @@ -0,0 +1,198 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static const int SCREEN_WIDTH = 1408; +static const int SCREEN_HEIGHT = 960; +static const int MAX_FPS = 60; + +typedef struct AppState { + Gfx* gfx; + IsoGfx* iso; + IsoGfxApp* app; + Texture* screen_texture; + Scene* scene; +} AppState; + +typedef struct GfxAppState { + AppState state; +} GfxAppState; + +static bool init(GfxAppState* gfx_app_state, int argc, const char** argv) { + assert(gfx_app_state); + AppState* state = &gfx_app_state->state; + + IsoGfxApp* app = state->app; + + if (!(state->iso = isogfx_new(&(IsoGfxDesc){ + .screen_width = SCREEN_WIDTH, .screen_height = SCREEN_HEIGHT}))) { + goto cleanup; + } + + if (!(*app->init)(app->state, state->iso, argc, argv)) { + goto cleanup; + } + + // Apply pixel scaling if requested by the app. + int texture_width, texture_height; + if (app->pixel_scale > 1) { + texture_width = SCREEN_WIDTH / app->pixel_scale; + texture_height = SCREEN_HEIGHT / app->pixel_scale; + isogfx_resize(state->iso, texture_width, texture_height); + } else { + texture_width = SCREEN_WIDTH; + texture_height = SCREEN_HEIGHT; + } + + if (!(state->gfx = gfx_init())) { + goto cleanup; + } + RenderBackend* render_backend = gfx_get_render_backend(state->gfx); + + if (!(state->screen_texture = gfx_make_texture( + render_backend, &(TextureDesc){ + .width = texture_width, + .height = texture_height, + .dimension = Texture2D, + .format = TextureSRGBA8, + .filtering = NearestFiltering, + .wrap = ClampToEdge, + .mipmaps = false}))) { + goto cleanup; + } + + ShaderProgram* shader = gfx_make_view_texture_shader(render_backend); + if (!shader) { + goto cleanup; + } + + Geometry* geometry = gfx_make_quad_11(render_backend); + if (!geometry) { + goto cleanup; + } + + MaterialDesc material_desc = (MaterialDesc){.num_uniforms = 1}; + material_desc.uniforms[0] = (ShaderUniform){ + .type = UniformTexture, + .value.texture = state->screen_texture, + .name = sstring_make("Texture")}; + Material* material = gfx_make_material(&material_desc); + if (!material) { + return false; + } + + const MeshDesc mesh_desc = + (MeshDesc){.geometry = geometry, .material = material, .shader = shader}; + Mesh* mesh = gfx_make_mesh(&mesh_desc); + if (!mesh) { + goto cleanup; + } + + SceneObject* object = + gfx_make_object(&(ObjectDesc){.num_meshes = 1, .meshes = {mesh}}); + if (!object) { + goto cleanup; + } + + state->scene = gfx_make_scene(); + SceneNode* node = gfx_make_object_node(object); + SceneNode* root = gfx_get_scene_root(state->scene); + gfx_set_node_parent(node, root); + + return true; + +cleanup: + if (state->gfx) { + gfx_destroy(&state->gfx); + } + free(state); + return false; +} + +static void shutdown(GfxAppState* gfx_app_state) { + assert(gfx_app_state); + AppState* state = &gfx_app_state->state; + + if (state->app) { + assert(state->iso); + (*state->app->shutdown)(state->app->state, state->iso); + } + + isogfx_del(&state->iso); + gfx_destroy(&state->gfx); +} + +static void update(GfxAppState* gfx_app_state, double t, double dt) { + assert(gfx_app_state); + AppState* state = &gfx_app_state->state; + + isogfx_update(state->iso, t); + + assert(state->app->update); + (*state->app->update)(state->app->state, state->iso, t, dt); +} + +static void render(GfxAppState* gfx_app_state) { + assert(gfx_app_state); + AppState* state = &gfx_app_state->state; + + assert(state->app->render); + (*state->app->render)(state->app->state, state->iso); + + const Pixel* screen = isogfx_get_screen_buffer(state->iso); + assert(screen); + gfx_update_texture( + state->screen_texture, &(TextureDataDesc){.pixels = screen}); + + RenderBackend* render_backend = gfx_get_render_backend(state->gfx); + Renderer* renderer = gfx_get_renderer(state->gfx); + + gfx_start_frame(render_backend); + gfx_render_scene( + renderer, &(RenderSceneParams){ + .mode = RenderDefault, .scene = state->scene, .camera = 0}); + gfx_end_frame(render_backend); +} + +static void resize(GfxAppState* gfx_app_state, int width, int height) { + assert(gfx_app_state); + AppState* state = &gfx_app_state->state; + + RenderBackend* render_backend = gfx_get_render_backend(state->gfx); + gfx_set_viewport(render_backend, width, height); +} + +void iso_run(int argc, const char** argv, IsoGfxApp* app) { + GfxAppState app_state = { + .state = (AppState){ + .app = app, + } + }; + gfx_app_run( + &(GfxAppDesc){ + .argc = argc, + .argv = argv, + .width = SCREEN_WIDTH, + .height = SCREEN_HEIGHT, + .max_fps = MAX_FPS, + .update_delta_time = MAX_FPS > 0 ? 1.0 / (double)MAX_FPS : 0.0, + .title = "Isometric Renderer", + .app_state = &app_state}, + &(GfxAppCallbacks){ + .init = init, + .update = update, + .render = render, + .resize = resize, + .shutdown = shutdown}); +} -- cgit v1.2.3