summaryrefslogtreecommitdiff
path: root/base/state.c
diff options
context:
space:
mode:
authorPeter Fors <peter.fors@mindkiller.com>2025-03-29 20:11:56 +0100
committerPeter Fors <peter.fors@mindkiller.com>2025-03-29 20:11:56 +0100
commitd5486a5af100fb37fac08b60d862ac14943853ce (patch)
treee2206f620745ba49c94f0f29d180587e03bc9fda /base/state.c
parentee4f15400998ca704c6ad8fc537f0d924930fabd (diff)
add base code for windowing and opengl crt-shader.
Diffstat (limited to 'base/state.c')
-rw-r--r--base/state.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/base/state.c b/base/state.c
new file mode 100644
index 0000000..f883d64
--- /dev/null
+++ b/base/state.c
@@ -0,0 +1,134 @@
+
+#define BUFFER_WIDTH 2048
+#define BUFFER_HEIGHT 1024
+#define FPS 50
+#ifdef _WIN32
+ #define SLEEP_MARGIN_NS 330000 // 0.33ms (Windows timing functionality is utter garbage)
+#else
+ #define SLEEP_MARGIN_NS 100000 // 0.1ms
+#endif
+
+#define ONE_SECOND_NS 1000000000
+#define FRAMETIME (ONE_SECOND_NS / FPS)
+
+#define SCREEN_WIDTH 360
+#define SCREEN_HEIGHT 270
+
+uint32_t buffer[BUFFER_WIDTH * BUFFER_HEIGHT] __attribute__((section(".bss"), aligned(4096)));
+uint32_t display_buffer[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((section(".bss"), aligned(4096)));
+
+#ifdef PROFILER
+#define MAX_PROFILING_ENTRIES (64)
+
+struct function_cycles {
+ const char *name;
+ uint64_t cycles;
+ uint32_t count;
+};
+
+struct debug_state {
+ struct function_cycles timings[MAX_PROFILING_ENTRIES];
+};
+#endif
+
+struct state {
+ // Pointers (8-byte aligned)
+ uint32_t *display_buffer;
+ struct { int32_t x, y, w, h; } viewport;
+ int32_t mouse_dx;
+ int32_t mouse_dy;
+ int32_t filter_override; // Manual override: -1 = automatic, 0 = off, 1 = on
+ float filter_frequency; // Frequency in Hz for squarewave toggle
+
+ float contrast;
+ float saturation;
+ float brightness;
+ float tone_data[4];
+
+ // OpenGL Objects
+ GLuint shader_program;
+ GLuint texture;
+ GLuint vao;
+ GLuint vbo;
+ GLuint ebo;
+
+ // Shader Uniforms
+ GLuint uniform_resolution;
+ GLuint uniform_src_image_size;
+ GLuint uniform_brightness;
+ GLuint uniform_tone;
+ GLuint uniform_crt_emulation;
+ GLuint uniform_sampler_location;
+ GLuint uniform_tex_bounds;
+
+ // Rendering & Dynamic Resolution
+ uint32_t screen_width; // for the debugger
+ uint32_t screen_height; // for the debugger
+ uint32_t render_width; // The actual remake resolution (e.g., 360)
+ uint32_t render_height; // The actual remake resolution (e.g., 270)
+ uint32_t render_x; // X position inside BUFFER_WIDTH (to track centering)
+ uint32_t render_y; // Y position inside BUFFER_HEIGHT (to track centering)
+ uint32_t frame_number;
+ size_t total_allocated;
+ bool freewheeling;
+ bool toggle_crt_emulation;
+ bool fullscreen;
+#ifdef PROFILER
+ bool overlay;
+ struct debug_state debug;
+#endif
+};
+
+struct state state;
+
+static struct remake_callbacks *current_part = 0;
+static void render_callback();
+static void audio_callback(int16_t *audio_buffer, size_t frames);
+static void init_callback();
+
+#ifndef PROFILER
+#define PROFILE_NAMED(name)
+#define PROFILE_FUNCTION()
+
+#else
+
+struct profiling_context {
+ uint32_t func_id;
+};
+
+__attribute__((section(".bss")))
+uint8_t debug_line_buffer[MAX_PROFILING_ENTRIES * 256]; // NOTE(peter): for storing all performance strings in an array to print to the debug-output
+
+__attribute__((always_inline, hot))
+static inline uint64_t read_tsc() {
+ unsigned int aux;
+ uint64_t result = __rdtscp(&aux);
+ return result;
+}
+
+__attribute__((always_inline, hot))
+static inline void end_profiling(struct profiling_context *ctx) __attribute__((unused));
+__attribute__((always_inline, hot))
+static inline void end_profiling(struct profiling_context *ctx) {
+ state.debug.timings[ctx->func_id].cycles += read_tsc();
+ state.debug.timings[ctx->func_id].count++;
+}
+
+#define PROFILE_NAMED(name) \
+ uint32_t func_id = __COUNTER__; \
+ if((state).debug.timings[func_id].count == 0) \
+ (state).debug.timings[func_id] = (struct function_cycles){(name), 0, 0}; \
+ (state).debug.timings[func_id].cycles -= read_tsc(); \
+ struct profiling_context ctx __attribute__((cleanup(end_profiling))) = { func_id };
+
+#define PROFILE_FUNCTION() \
+ uint32_t func_id = __COUNTER__; \
+ if((state).debug.timings[func_id].count == 0) \
+ (state).debug.timings[func_id] = (struct function_cycles){__func__, 0, 0}; \
+ (state).debug.timings[func_id].cycles -= read_tsc(); \
+ struct profiling_context ctx __attribute__((cleanup(end_profiling))) = { func_id };
+#endif
+
+
+
+