shithub: m8c

Download patch

ref: e11f4056d9188a2124a8dfb4dc2f95b5f196963c
parent: 6aa48d6e0f993dd4adc35aaa5a41b220e0652cc7
author: laamaa <jonne.kokkonen@gmail.com>
date: Wed Sep 10 04:42:50 EDT 2025

modularize log overlay system, move implementations to dedicated file and simplify render path integration

--- a/src/common.h
+++ b/src/common.h
@@ -2,6 +2,12 @@
 #define COMMON_H_
 #include "config.h"
 
+// On MacOS TARGET_OS_IOS is defined as 0, so make sure that it's consistent on other platforms as
+// well
+#ifndef TARGET_OS_IOS
+#define TARGET_OS_IOS 0
+#endif
+
 enum app_state { QUIT, INITIALIZE, WAIT_FOR_DEVICE, RUN };
 
 struct app_context {
--- a/src/input.c
+++ b/src/input.c
@@ -6,6 +6,7 @@
 #include "backends/m8.h"
 #include "common.h"
 #include "render.h"
+#include "log_overlay.h"
 #include <SDL3/SDL.h>
 
 static unsigned char keyjazz_enabled = 0;
@@ -184,13 +185,15 @@
     return;
   }
   if (event->key.key == SDLK_ESCAPE) {
-    display_keyjazz_overlay(toggle_input_keyjazz(), keyjazz_base_octave, keyjazz_velocity);
+    if (ctx->app_state == RUN) {
+      display_keyjazz_overlay(toggle_input_keyjazz(), keyjazz_base_octave, keyjazz_velocity);
+    }
     return;
   }
 
   // Toggle in-app log overlay using config-defined key
   if (event->key.scancode == ctx->conf.key_toggle_log) {
-    renderer_toggle_log_overlay();
+    log_overlay_toggle();
     return;
   }
 
--- a/src/main.c
+++ b/src/main.c
@@ -19,13 +19,8 @@
 #include "config.h"
 #include "gamepads.h"
 #include "render.h"
+#include "log_overlay.h"
 
-// On MacOS TARGET_OS_IOS is defined as 0, so make sure that it's consistent on other platforms as
-// well
-#ifndef TARGET_OS_IOS
-#define TARGET_OS_IOS 0
-#endif
-
 static void do_wait_for_device(struct app_context *ctx) {
   static Uint64 ticks_poll_device = 0;
   static int screensaver_initialized = 0;
@@ -151,7 +146,7 @@
   char *config_filename = NULL;
 
   // Initialize in-app log capture/overlay
-  renderer_log_init();
+  log_overlay_init();
 
 #ifndef NDEBUG
   // Show debug messages in the application log
--- a/src/render.c
+++ b/src/render.c
@@ -9,6 +9,7 @@
 #include "command.h"
 #include "config.h"
 #include "fx_cube.h"
+#include "log_overlay.h"
 #include "settings.h"
 
 #include "fonts/fonts.h"
@@ -19,7 +20,6 @@
 static SDL_Renderer *rend;
 static SDL_Texture *main_texture;
 static SDL_Texture *hd_texture = NULL;
-static SDL_Texture *log_texture = NULL;
 static SDL_Color global_background_color = (SDL_Color){.r = 0x00, .g = 0x00, .b = 0x00, .a = 0x00};
 static SDL_RendererLogicalPresentation window_scaling_mode = SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
 static SDL_ScaleMode texture_scaling_mode = SDL_SCALEMODE_NEAREST;
@@ -32,21 +32,8 @@
 static int text_offset_y = 0;
 static int waveform_max_height = 24;
 
-// Log overlay state
-static int log_overlay_visible = 0;
-static int log_overlay_needs_redraw = 0;
+// Log overlay moved to log_overlay.c
 
-// Log buffer configuration
-#define LOG_BUFFER_MAX_LINES 512
-#define LOG_LINE_MAX_CHARS 256
-static char log_lines[LOG_BUFFER_MAX_LINES][LOG_LINE_MAX_CHARS];
-static int log_line_start = 0; // index of the oldest line
-static int log_line_count = 0; // number of valid lines
-
-// Previous SDL log output forwarding
-static SDL_LogOutputFunction prev_log_output_fn = NULL;
-static void *prev_log_output_userdata = NULL;
-
 static int texture_width = 320;
 static int texture_height = 240;
 static int hd_texture_width, hd_texture_height = 0;
@@ -144,163 +131,14 @@
   inline_font_initialize(fonts_get(index));
 }
 
-// Append a formatted line to the circular log buffer
-static void log_buffer_append_line(const char *line) {
-  if (line[0] == '\0') {
-    return;
-  }
-  const int index = (log_line_start + log_line_count) % LOG_BUFFER_MAX_LINES;
-  SDL_strlcpy(log_lines[index], line, LOG_LINE_MAX_CHARS);
-  if (log_line_count < LOG_BUFFER_MAX_LINES) {
-    log_line_count++;
-  } else {
-    log_line_start = (log_line_start + 1) % LOG_BUFFER_MAX_LINES;
-  }
-  log_overlay_needs_redraw = 1;
-}
+// Log overlay API wrappers
+void renderer_log_init(void) { log_overlay_init(); }
 
-// SDL log output function that mirrors to our in-app buffer in addition to the default handler
-static void sdl_log_capture(void *userdata, int category, SDL_LogPriority priority,
-                            const char *message) {
-  (void)userdata;
-  (void)category;
-  (void)priority;
-
-  char formatted[LOG_LINE_MAX_CHARS];
-  SDL_snprintf(formatted, sizeof(formatted), ">%s", message ? message : "");
-
-  // Copy the formatted message into our buffer
-  log_buffer_append_line(formatted);
-
-  // Forward to the previous output function so messages still hit the console
-  if (prev_log_output_fn != NULL) {
-    prev_log_output_fn(prev_log_output_userdata, category, priority, message);
-  }
-}
-
-void renderer_log_init(void) {
-  // Preserve the existing output function and install our capture wrapper
-  SDL_GetLogOutputFunction(&prev_log_output_fn, &prev_log_output_userdata);
-  SDL_SetLogOutputFunction(sdl_log_capture, NULL);
-}
-
 void renderer_toggle_log_overlay(void) {
-  log_overlay_visible = !log_overlay_visible;
-  // Force redraw next present
+  log_overlay_toggle();
   dirty = 1;
-  log_overlay_needs_redraw = 1;
 }
 
-// Render the log buffer into a texture for the overlay display
-static void render_log_overlay_texture(void) {
-  if (!log_overlay_visible) {
-    return;
-  }
-  if (log_texture == NULL) {
-    log_texture = SDL_CreateTexture(rend, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET,
-                                    texture_width, texture_height);
-    if (log_texture == NULL) {
-      SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Couldn't create log texture: %s", SDL_GetError());
-      return;
-    }
-    // Ensure overlay blends and scales consistently with the main texture
-    SDL_SetTextureBlendMode(log_texture, SDL_BLENDMODE_BLEND);
-    SDL_SetTextureScaleMode(log_texture, texture_scaling_mode);
-  }
-
-  if (!log_overlay_needs_redraw) {
-    return;
-  }
-  log_overlay_needs_redraw = 0;
-
-  SDL_Texture *prev_target = SDL_GetRenderTarget(rend);
-  SDL_SetRenderTarget(rend, log_texture);
-
-  // Semi-transparent background rectangle
-  SDL_SetRenderDrawColor(rend, 0, 0, 0, 220);
-  SDL_RenderClear(rend);
-
-  // Use a small font to fit more lines
-  const int prev_font_mode = font_mode;
-  inline_font_close();
-  const struct inline_font *font_small = fonts_get(0);
-  inline_font_initialize(font_small);
-
-  const int line_height = font_small->glyph_y + 1;
-  const int margin_x = 2;
-  const int margin_y = 1;
-  const int usable_width = texture_width - (margin_x * 2);
-  const int cols = SDL_max(1, usable_width / (font_small->glyph_x + 1));
-
-  // Compute how many text rows fit
-  const int max_rows = (texture_height - margin_y * 2) / line_height;
-  int rows_needed = max_rows;
-
-  // Determine start line and character offset so the overlay shows the most recent rows
-  const int newest_idx =
-      (log_line_start + log_line_count - 1 + LOG_BUFFER_MAX_LINES) % LOG_BUFFER_MAX_LINES;
-  int start_idx = log_line_start;
-  size_t start_char_offset = 0;
-
-  if (log_line_count > 0) {
-    for (int n = 0; n < log_line_count && rows_needed > 0; n++) {
-      const int idx = (newest_idx - n + LOG_BUFFER_MAX_LINES) % LOG_BUFFER_MAX_LINES;
-      const size_t len = SDL_strlen(log_lines[idx]);
-      const int rows_for_line = SDL_max(1, (int)((len + cols - 1) / cols));
-      if (rows_for_line >= rows_needed) {
-        int offset = (int)len - rows_needed * cols;
-        if (offset < 0) {
-          offset = 0;
-        }
-        start_idx = idx;
-        start_char_offset = (size_t)offset;
-        break;
-      }
-      rows_needed -= rows_for_line;
-      start_idx = idx;
-      start_char_offset = 0;
-    }
-  }
-
-  // Render forward from the computed start to the newest
-  if (log_line_count > 0) {
-    int y = 1;
-    int cur = start_idx;
-    const int last = newest_idx;
-    size_t offset = start_char_offset;
-    while (1) {
-      const char *s = log_lines[cur];
-      const size_t len = SDL_strlen(s);
-      for (size_t pos = offset; pos < len && y < texture_height;) {
-        const Uint32 bg = 0xFFFFFF;
-        const Uint32 fg = 0xFFFFFF;
-        const size_t remaining = len - pos;
-        size_t take = (size_t)cols < remaining ? (size_t)cols : remaining;
-        char buf[LOG_LINE_MAX_CHARS];
-        if (take >= sizeof(buf)) {
-          take = sizeof(buf) - 1;
-        }
-        SDL_memcpy(buf, s + pos, take);
-        buf[take] = '\0';
-        inprint(rend, buf, margin_x, y, fg, bg);
-        y += line_height;
-        pos += take;
-      }
-      if (cur == last || y >= texture_height) {
-        break;
-      }
-      cur = (cur + 1) % LOG_BUFFER_MAX_LINES;
-      offset = 0;
-    }
-  }
-
-  // Restore previous font
-  inline_font_close();
-  inline_font_initialize(fonts_get(prev_font_mode));
-
-  SDL_SetRenderTarget(rend, prev_target);
-}
-
 static void check_and_adjust_window_and_texture_size(const int new_width, const int new_height) {
 
   if (texture_width == new_width && texture_height == new_height) {
@@ -328,11 +166,8 @@
     SDL_DestroyTexture(main_texture);
   }
 
-  // Drop log texture so it can be recreated with the correct size
-  if (log_texture != NULL) {
-    SDL_DestroyTexture(log_texture);
-    log_texture = NULL;
-  }
+  // Notify log overlay to drop its cached texture so it can be recreated with the new size
+  log_overlay_invalidate();
 
   main_texture = SDL_CreateTexture(rend, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET,
                                    texture_width, texture_height);
@@ -385,9 +220,7 @@
   if (hd_texture != NULL) {
     SDL_DestroyTexture(hd_texture);
   }
-  if (log_texture != NULL) {
-    SDL_DestroyTexture(log_texture);
-  }
+  log_overlay_destroy();
   SDL_DestroyRenderer(rend);
   SDL_DestroyWindow(win);
 }
@@ -644,16 +477,8 @@
 
   if (conf->integer_scaling) {
     SDL_SetRenderTarget(rend, main_texture);
-    // Ensure the log overlay is up to date, then composite it if visible before present
-    if (log_overlay_visible) {
-      render_log_overlay_texture();
-      if (log_texture) {
-        if (!SDL_RenderTexture(rend, log_texture, NULL, NULL)) {
-          SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Couldn't render log overlay texture to HD texture: %s",
-                        SDL_GetError());
-        }
-      }
-    }
+    // Render log overlay (composites if visible)
+    log_overlay_render(rend, texture_width, texture_height, texture_scaling_mode, font_mode);
 
     // Settings overlay composited last
     if (settings_is_open()) {
@@ -701,16 +526,8 @@
                       SDL_GetError());
     }
 
-    // Ensure the log overlay is up to date, then composite it if visible before present
-    if (log_overlay_visible) {
-      render_log_overlay_texture();
-      if (log_texture) {
-        if (!SDL_RenderTexture(rend, log_texture, NULL, NULL)) {
-          SDL_LogCritical(SDL_LOG_CATEGORY_RENDER, "Couldn't render log overlay texture to HD texture: %s",
-                        SDL_GetError());
-        }
-      }
-    }
+    // Render log overlay (composites if visible)
+    log_overlay_render(rend, texture_width, texture_height, texture_scaling_mode, font_mode);
 
     // Settings overlay composited last
     if (settings_is_open()) {
--- a/src/render.h
+++ b/src/render.h
@@ -27,10 +27,6 @@
 
 void show_error_message(const char *message);
 
-// Log overlay controls
-void renderer_log_init(void);
-void renderer_toggle_log_overlay(void);
-
 int screensaver_init(void);
 void screensaver_draw(void);
 void screensaver_destroy(void);
--