summaryrefslogtreecommitdiff
path: root/gfx-iso/src/app.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx-iso/src/app.c')
-rw-r--r--gfx-iso/src/app.c198
1 files changed, 198 insertions, 0 deletions
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 @@
1#include <isogfx/app.h>
2#include <isogfx/isogfx.h>
3
4#include <gfx/gfx.h>
5#include <gfx/gfx_app.h>
6#include <gfx/render_backend.h>
7#include <gfx/renderer.h>
8#include <gfx/scene.h>
9#include <gfx/util/geometry.h>
10#include <gfx/util/shader.h>
11
12#include <assert.h>
13#include <stdbool.h>
14#include <stdlib.h>
15
16static const int SCREEN_WIDTH = 1408;
17static const int SCREEN_HEIGHT = 960;
18static const int MAX_FPS = 60;
19
20typedef struct AppState {
21 Gfx* gfx;
22 IsoGfx* iso;
23 IsoGfxApp* app;
24 Texture* screen_texture;
25 Scene* scene;
26} AppState;
27
28typedef struct GfxAppState {
29 AppState state;
30} GfxAppState;
31
32static bool init(GfxAppState* gfx_app_state, int argc, const char** argv) {
33 assert(gfx_app_state);
34 AppState* state = &gfx_app_state->state;
35
36 IsoGfxApp* app = state->app;
37
38 if (!(state->iso = isogfx_new(&(IsoGfxDesc){
39 .screen_width = SCREEN_WIDTH, .screen_height = SCREEN_HEIGHT}))) {
40 goto cleanup;
41 }
42
43 if (!(*app->init)(app->state, state->iso, argc, argv)) {
44 goto cleanup;
45 }
46
47 // Apply pixel scaling if requested by the app.
48 int texture_width, texture_height;
49 if (app->pixel_scale > 1) {
50 texture_width = SCREEN_WIDTH / app->pixel_scale;
51 texture_height = SCREEN_HEIGHT / app->pixel_scale;
52 isogfx_resize(state->iso, texture_width, texture_height);
53 } else {
54 texture_width = SCREEN_WIDTH;
55 texture_height = SCREEN_HEIGHT;
56 }
57
58 if (!(state->gfx = gfx_init())) {
59 goto cleanup;
60 }
61 RenderBackend* render_backend = gfx_get_render_backend(state->gfx);
62
63 if (!(state->screen_texture = gfx_make_texture(
64 render_backend, &(TextureDesc){
65 .width = texture_width,
66 .height = texture_height,
67 .dimension = Texture2D,
68 .format = TextureSRGBA8,
69 .filtering = NearestFiltering,
70 .wrap = ClampToEdge,
71 .mipmaps = false}))) {
72 goto cleanup;
73 }
74
75 ShaderProgram* shader = gfx_make_view_texture_shader(render_backend);
76 if (!shader) {
77 goto cleanup;
78 }
79
80 Geometry* geometry = gfx_make_quad_11(render_backend);
81 if (!geometry) {
82 goto cleanup;
83 }
84
85 MaterialDesc material_desc = (MaterialDesc){.num_uniforms = 1};
86 material_desc.uniforms[0] = (ShaderUniform){
87 .type = UniformTexture,
88 .value.texture = state->screen_texture,
89 .name = sstring_make("Texture")};
90 Material* material = gfx_make_material(&material_desc);
91 if (!material) {
92 return false;
93 }
94
95 const MeshDesc mesh_desc =
96 (MeshDesc){.geometry = geometry, .material = material, .shader = shader};
97 Mesh* mesh = gfx_make_mesh(&mesh_desc);
98 if (!mesh) {
99 goto cleanup;
100 }
101
102 SceneObject* object =
103 gfx_make_object(&(ObjectDesc){.num_meshes = 1, .meshes = {mesh}});
104 if (!object) {
105 goto cleanup;
106 }
107
108 state->scene = gfx_make_scene();
109 SceneNode* node = gfx_make_object_node(object);
110 SceneNode* root = gfx_get_scene_root(state->scene);
111 gfx_set_node_parent(node, root);
112
113 return true;
114
115cleanup:
116 if (state->gfx) {
117 gfx_destroy(&state->gfx);
118 }
119 free(state);
120 return false;
121}
122
123static void shutdown(GfxAppState* gfx_app_state) {
124 assert(gfx_app_state);
125 AppState* state = &gfx_app_state->state;
126
127 if (state->app) {
128 assert(state->iso);
129 (*state->app->shutdown)(state->app->state, state->iso);
130 }
131
132 isogfx_del(&state->iso);
133 gfx_destroy(&state->gfx);
134}
135
136static void update(GfxAppState* gfx_app_state, double t, double dt) {
137 assert(gfx_app_state);
138 AppState* state = &gfx_app_state->state;
139
140 isogfx_update(state->iso, t);
141
142 assert(state->app->update);
143 (*state->app->update)(state->app->state, state->iso, t, dt);
144}
145
146static void render(GfxAppState* gfx_app_state) {
147 assert(gfx_app_state);
148 AppState* state = &gfx_app_state->state;
149
150 assert(state->app->render);
151 (*state->app->render)(state->app->state, state->iso);
152
153 const Pixel* screen = isogfx_get_screen_buffer(state->iso);
154 assert(screen);
155 gfx_update_texture(
156 state->screen_texture, &(TextureDataDesc){.pixels = screen});
157
158 RenderBackend* render_backend = gfx_get_render_backend(state->gfx);
159 Renderer* renderer = gfx_get_renderer(state->gfx);
160
161 gfx_start_frame(render_backend);
162 gfx_render_scene(
163 renderer, &(RenderSceneParams){
164 .mode = RenderDefault, .scene = state->scene, .camera = 0});
165 gfx_end_frame(render_backend);
166}
167
168static void resize(GfxAppState* gfx_app_state, int width, int height) {
169 assert(gfx_app_state);
170 AppState* state = &gfx_app_state->state;
171
172 RenderBackend* render_backend = gfx_get_render_backend(state->gfx);
173 gfx_set_viewport(render_backend, width, height);
174}
175
176void iso_run(int argc, const char** argv, IsoGfxApp* app) {
177 GfxAppState app_state = {
178 .state = (AppState){
179 .app = app,
180 }
181 };
182 gfx_app_run(
183 &(GfxAppDesc){
184 .argc = argc,
185 .argv = argv,
186 .width = SCREEN_WIDTH,
187 .height = SCREEN_HEIGHT,
188 .max_fps = MAX_FPS,
189 .update_delta_time = MAX_FPS > 0 ? 1.0 / (double)MAX_FPS : 0.0,
190 .title = "Isometric Renderer",
191 .app_state = &app_state},
192 &(GfxAppCallbacks){
193 .init = init,
194 .update = update,
195 .render = render,
196 .resize = resize,
197 .shutdown = shutdown});
198}