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/app.c')

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 <isogfx/app.h>
+#include <isogfx/isogfx.h>
+
+#include <gfx/gfx.h>
+#include <gfx/gfx_app.h>
+#include <gfx/render_backend.h>
+#include <gfx/renderer.h>
+#include <gfx/scene.h>
+#include <gfx/util/geometry.h>
+#include <gfx/util/shader.h>
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+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