diff options
author | admin <admin@optics-design.com> | 2025-08-15 20:53:56 +0200 |
---|---|---|
committer | admin <admin@optics-design.com> | 2025-08-15 20:53:56 +0200 |
commit | 9acbbbfbca5e8049b200d344027ee1199db262c3 (patch) | |
tree | 2ede5dc4f04d04a8ea940544f07e42a8cb183f2c /src | |
parent | 91c024d42e54c3db70fa9693525c0dc2b5e775fc (diff) |
Diffstat (limited to 'src')
-rw-r--r-- | src/glamac/glamac.c | 57 | ||||
-rw-r--r-- | src/glamac/glamac_render.c | 355 | ||||
-rw-r--r-- | src/glamac/glamac_view.c | 3 |
3 files changed, 229 insertions, 186 deletions
diff --git a/src/glamac/glamac.c b/src/glamac/glamac.c index 7f361ab..c2ba13d 100644 --- a/src/glamac/glamac.c +++ b/src/glamac/glamac.c @@ -14,13 +14,14 @@ extern b32 process_events(SDL_Event *event, ViewState *view, SDL_Window *window,
i32 *lastMouseX, i32 *lastMouseY, b32 *dragging, b32 *quit);
-// Function to reload fonts on window resize with improved error handling and hysteresis
+// Function to reload fonts on window resize with improved error handling and debounce
b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) {
static i32 lastWidth = 0;
static i32 lastHeight = 0;
static u32 lastReloadTime = 0;
static i32 pendingWidth = 0;
static i32 pendingHeight = 0;
+ static u32 lastSizeChangeTime = 0; // For debounce mechanism
// Validate inputs
if (!fonts || !view) {
@@ -35,28 +36,36 @@ b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) { return 0;
}
- // Hysteresis parameters - reduced for better responsiveness
- const f32 threshold = 0.25f; // 25% change threshold
- const u32 minReloadInterval = 100; // Minimum 100ms between font reloads
- const u32 maxPendingTime = 500; // Maximum time to wait for pending reload
+ // Optimized parameters to reduce excessive reloading
+ const f32 threshold = 0.35f; // 35% change threshold
+ const u32 minReloadInterval = 250; // Minimum 250ms between font reloads
+ const u32 maxPendingTime = 750; // Maximum time to wait for pending reload
+ const u32 debounceTime = 150; // Wait 150ms for window size to stabilize
u32 currentTime = SDL_GetTicks();
- // Check if window size changed significantly
+ // Check if window size changed
i32 widthDiff = abs(view->windowWidth - lastWidth);
i32 heightDiff = abs(view->windowHeight - lastHeight);
- b32 significantChange = (widthDiff > (i32)(view->windowWidth * threshold) ||
- heightDiff > (i32)(view->windowHeight * threshold));
+ b32 sizeChanged = (widthDiff > 0 || heightDiff > 0);
- if (significantChange) {
- // Update pending dimensions
+ // Debounce: Update last change time if size changed
+ if (sizeChanged) {
+ lastSizeChangeTime = currentTime;
pendingWidth = view->windowWidth;
pendingHeight = view->windowHeight;
-
+ }
+
+ // Check if change is significant enough and debounced
+ b32 significantChange = (widthDiff > (i32)(view->windowWidth * threshold) ||
+ heightDiff > (i32)(view->windowHeight * threshold));
+ b32 debounced = (currentTime - lastSizeChangeTime >= debounceTime);
+
+ if (significantChange && debounced) {
// Check if enough time has passed since last reload
if (currentTime - lastReloadTime >= minReloadInterval) {
if (is_debug_mode()) {
- printf("Window size changed significantly: %dx%d -> %dx%d, reloading fonts...\n",
+ printf("Window size changed significantly (debounced): %dx%d -> %dx%d, reloading fonts...\n",
lastWidth, lastHeight, view->windowWidth, view->windowHeight);
}
@@ -101,6 +110,7 @@ b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) { lastWidth = view->windowWidth;
lastHeight = view->windowHeight;
lastReloadTime = currentTime;
+ lastSizeChangeTime = 0; // Reset debounce timer
pendingWidth = pendingHeight = 0; // Clear pending state
// Mark view as dirty to re-render with new fonts
@@ -116,19 +126,28 @@ b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) { } else {
// Can't reload yet due to rate limiting, check if we should force it
if (pendingWidth != 0 && pendingHeight != 0 &&
- currentTime - lastReloadTime >= maxPendingTime) {
+ currentTime - lastReloadTime >= maxPendingTime && debounced) {
if (is_debug_mode()) {
- printf("Forcing delayed font reload after %ums\n", maxPendingTime);
+ printf("Forcing delayed font reload after %ums (debounced)\n", maxPendingTime);
}
- // Recursive call will now pass the time check
- return reload_fonts_if_needed(fonts, view, dpi);
+ // Force reload by temporarily adjusting the time check
+ u32 savedTime = lastReloadTime;
+ lastReloadTime = currentTime - minReloadInterval;
+ b32 result = reload_fonts_if_needed(fonts, view, dpi);
+ if (!result) {
+ lastReloadTime = savedTime; // Restore on failure
+ }
+ return result;
}
// Silently rate limit font reloads
}
} else if (pendingWidth != 0 && pendingHeight != 0 &&
- currentTime - lastReloadTime >= minReloadInterval) {
- // Handle pending resize that wasn't significant enough initially
- // but has been waiting for the rate limit
+ currentTime - lastReloadTime >= minReloadInterval && debounced) {
+ // Handle pending resize that has been debounced but wasn't significant initially
+ if (is_debug_mode()) {
+ printf("Processing debounced pending resize: %dx%d -> %dx%d\n",
+ lastWidth, lastHeight, pendingWidth, pendingHeight);
+ }
view->windowWidth = pendingWidth;
view->windowHeight = pendingHeight;
return reload_fonts_if_needed(fonts, view, dpi);
diff --git a/src/glamac/glamac_render.c b/src/glamac/glamac_render.c index c375754..1398ba9 100644 --- a/src/glamac/glamac_render.c +++ b/src/glamac/glamac_render.c @@ -28,12 +28,10 @@ #define AXIS_LABEL_OFFSET 15
#define AXIS_MARGIN 45
-// Safe font paths (in order of preference)
+// Linux font paths (in order of preference)
static const char* SAFE_FONT_PATHS[] = {
"/usr/share/fonts/TTF/DejaVuSans.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
- "/System/Library/Fonts/Arial.ttf", // macOS
- "C:\\Windows\\Fonts\\arial.ttf", // Windows
"fonts/DejaVuSans.ttf", // Local fallback
"DejaVuSans.ttf", // Current directory
NULL
@@ -42,64 +40,85 @@ static const char* SAFE_FONT_PATHS[] = { static const char* SAFE_BOLD_FONT_PATHS[] = {
"/usr/share/fonts/TTF/DejaVuSans-Bold.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
- "/System/Library/Fonts/Arial Bold.ttf", // macOS
- "C:\\Windows\\Fonts\\arialbd.ttf", // Windows
"fonts/DejaVuSans-Bold.ttf", // Local fallback
"DejaVuSans-Bold.ttf", // Current directory
NULL
};
-// Text rendering cache with LRU eviction
+// Hash-based text cache for O(1) lookup
#define TEXT_CACHE_SIZE 512
#define MAX_TEXT_LENGTH 128
-typedef struct {
+typedef struct CacheEntry {
char text[MAX_TEXT_LENGTH];
SDL_Texture* texture;
i32 width, height;
SDL_Color color;
TTF_Font* font;
u32 last_used_time; // For LRU eviction
- b32 in_use; // Slot availability flag
-} CachedText;
+ struct CacheEntry* next; // For collision chaining
+} CacheEntry;
-static CachedText textCache[TEXT_CACHE_SIZE];
-static i32 cacheSize = 0;
+static CacheEntry* textCache[TEXT_CACHE_SIZE] = {NULL};
static u32 cache_access_counter = 0; // Global counter for LRU
-// Find least recently used cache entry for eviction
-static i32 find_lru_cache_entry(void) {
- i32 lru_index = 0;
- u32 oldest_time = textCache[0].last_used_time;
-
- for (i32 i = 1; i < TEXT_CACHE_SIZE; i++) {
- if (!textCache[i].in_use) {
- return i; // Found empty slot
- }
- if (textCache[i].last_used_time < oldest_time) {
- oldest_time = textCache[i].last_used_time;
- lru_index = i;
- }
+// Simple hash function for cache key
+static inline u32 hash_cache_key(TTF_Font* font, const char* text, SDL_Color color) {
+ u32 hash = 2166136261u; // FNV-1a hash
+ hash ^= (uintptr_t)font;
+ hash *= 16777619u;
+ hash ^= color.r;
+ hash *= 16777619u;
+ hash ^= color.g;
+ hash *= 16777619u;
+ hash ^= color.b;
+ hash *= 16777619u;
+
+ for (const char* p = text; *p; ++p) {
+ hash ^= (u8)*p;
+ hash *= 16777619u;
}
- return lru_index;
+ return hash % TEXT_CACHE_SIZE;
}
-// Evict cache entry and free its resources
-static void evict_cache_entry(i32 index) {
- if (index >= 0 && index < TEXT_CACHE_SIZE && textCache[index].in_use) {
- if (textCache[index].texture) {
- SDL_DestroyTexture(textCache[index].texture);
- textCache[index].texture = NULL;
+// Find and remove least recently used entry from a collision chain
+static void evict_lru_from_chain(CacheEntry** head) {
+ if (!*head) return;
+
+ if (!(*head)->next) {
+ // Only one entry, remove it
+ SDL_DestroyTexture((*head)->texture);
+ free(*head);
+ *head = NULL;
+ return;
+ }
+
+ // Find LRU entry
+ CacheEntry* lru = *head;
+ CacheEntry* lru_prev = NULL;
+ CacheEntry* prev = NULL;
+
+ for (CacheEntry* curr = *head; curr; curr = curr->next) {
+ if (curr->last_used_time < lru->last_used_time) {
+ lru = curr;
+ lru_prev = prev;
}
- textCache[index].in_use = 0;
- textCache[index].text[0] = '\0';
- textCache[index].font = NULL;
- textCache[index].last_used_time = 0;
+ prev = curr;
+ }
+
+ // Remove LRU entry
+ if (lru_prev) {
+ lru_prev->next = lru->next;
+ } else {
+ *head = lru->next;
}
+
+ SDL_DestroyTexture(lru->texture);
+ free(lru);
}
-// Find cached text texture with LRU management
+// O(1) hash-based cached text lookup
static SDL_Texture* get_cached_text(SDL_Renderer* renderer, TTF_Font* font, const char* text, SDL_Color color, i32* width, i32* height) {
if (!renderer || !font || !text || !width || !height) {
return NULL;
@@ -111,32 +130,31 @@ static SDL_Texture* get_cached_text(SDL_Renderer* renderer, TTF_Font* font, cons return NULL;
}
- // Security: Ensure text is properly null-terminated
if (text[text_len] != '\0') {
printf("Warning: Cached text not properly null-terminated\n");
return NULL;
}
cache_access_counter++;
-
- // Search for existing cache entry
- for (i32 i = 0; i < TEXT_CACHE_SIZE; i++) {
- if (textCache[i].in_use &&
- textCache[i].font == font &&
- textCache[i].color.r == color.r &&
- textCache[i].color.g == color.g &&
- textCache[i].color.b == color.b &&
- strcmp(textCache[i].text, text) == 0) {
+ u32 hash = hash_cache_key(font, text, color);
+
+ // Search collision chain for existing entry
+ for (CacheEntry* entry = textCache[hash]; entry; entry = entry->next) {
+ if (entry->font == font &&
+ entry->color.r == color.r &&
+ entry->color.g == color.g &&
+ entry->color.b == color.b &&
+ strcmp(entry->text, text) == 0) {
// Update LRU timestamp
- textCache[i].last_used_time = cache_access_counter;
- *width = textCache[i].width;
- *height = textCache[i].height;
- return textCache[i].texture;
+ entry->last_used_time = cache_access_counter;
+ *width = entry->width;
+ *height = entry->height;
+ return entry->texture;
}
}
- // Create new cached texture
+ // Create new texture
SDL_Surface* surface = TTF_RenderText_Blended(font, text, text_len, color);
if (!surface) {
return NULL;
@@ -148,30 +166,39 @@ static SDL_Texture* get_cached_text(SDL_Renderer* renderer, TTF_Font* font, cons return NULL;
}
- // Find cache slot (either empty or LRU)
- i32 cache_index;
- if (cacheSize < TEXT_CACHE_SIZE) {
- // Use next available slot
- cache_index = cacheSize;
- cacheSize++;
- } else {
- // Cache is full, evict LRU entry
- cache_index = find_lru_cache_entry();
- evict_cache_entry(cache_index);
+ // Count entries in chain - if too many, evict LRU
+ i32 chain_length = 0;
+ for (CacheEntry* entry = textCache[hash]; entry; entry = entry->next) {
+ chain_length++;
+ }
+
+ if (chain_length >= 8) { // Limit chain length
+ evict_lru_from_chain(&textCache[hash]);
+ }
+
+ // Create new cache entry
+ CacheEntry* new_entry = malloc(sizeof(CacheEntry));
+ if (!new_entry) {
+ SDL_DestroyTexture(texture);
+ SDL_DestroySurface(surface);
+ return NULL;
}
// Store in cache with safe string copying
- size_t max_copy = sizeof(textCache[cache_index].text) - 1;
+ size_t max_copy = sizeof(new_entry->text) - 1;
size_t copy_len = (text_len < max_copy) ? text_len : max_copy;
- memcpy(textCache[cache_index].text, text, copy_len);
- textCache[cache_index].text[copy_len] = '\0';
- textCache[cache_index].texture = texture;
- textCache[cache_index].width = surface->w;
- textCache[cache_index].height = surface->h;
- textCache[cache_index].color = color;
- textCache[cache_index].font = font;
- textCache[cache_index].last_used_time = cache_access_counter;
- textCache[cache_index].in_use = 1;
+ memcpy(new_entry->text, text, copy_len);
+ new_entry->text[copy_len] = '\0';
+ new_entry->texture = texture;
+ new_entry->width = surface->w;
+ new_entry->height = surface->h;
+ new_entry->color = color;
+ new_entry->font = font;
+ new_entry->last_used_time = cache_access_counter;
+
+ // Insert at head of collision chain
+ new_entry->next = textCache[hash];
+ textCache[hash] = new_entry;
*width = surface->w;
*height = surface->h;
@@ -182,16 +209,15 @@ static SDL_Texture* get_cached_text(SDL_Renderer* renderer, TTF_Font* font, cons void clear_text_cache(void) {
for (i32 i = 0; i < TEXT_CACHE_SIZE; i++) {
- if (textCache[i].in_use && textCache[i].texture) {
- SDL_DestroyTexture(textCache[i].texture);
- textCache[i].texture = NULL;
+ CacheEntry* entry = textCache[i];
+ while (entry) {
+ CacheEntry* next = entry->next;
+ SDL_DestroyTexture(entry->texture);
+ free(entry);
+ entry = next;
}
- textCache[i].in_use = 0;
- textCache[i].text[0] = '\0';
- textCache[i].font = NULL;
- textCache[i].last_used_time = 0;
+ textCache[i] = NULL;
}
- cacheSize = 0;
cache_access_counter = 0;
}
@@ -295,31 +321,20 @@ static TTF_Font* load_font_safe(const char* const* font_paths, int size) { continue;
}
- // Enhanced security: Check for directory traversal and other unsafe patterns
- if (strstr(path, "..") || strstr(path, "//") ||
- strstr(path, "%2E%2E") || // URL-encoded ..
- strstr(path, "%2F%2F") || // URL-encoded //
- strstr(path, "\\\\") || // Windows double backslash
- strstr(path, "\\.\\")) { // Windows .\ pattern
+ // Security: Check for directory traversal
+ if (strstr(path, "..") || strstr(path, "//")) {
if (is_debug_mode()) {
printf("Warning: Skipping potentially unsafe font path: %s\n", path);
}
continue;
}
- // Additional validation: ensure path is within safe directories
- b32 safe_path = 0;
- if (strncmp(path, "/usr/share/fonts/", 17) == 0 ||
- strncmp(path, "/System/Library/Fonts/", 22) == 0 ||
- strncmp(path, "C:\\Windows\\Fonts\\", 17) == 0 ||
- strncmp(path, "fonts/", 6) == 0 ||
- (strlen(path) < 50 && strchr(path, '/') == NULL)) { // Simple filename only
- safe_path = 1;
- }
-
- if (!safe_path) {
+ // Validate path is in safe directories
+ if (!(strncmp(path, "/usr/share/fonts/", 17) == 0 ||
+ strncmp(path, "fonts/", 6) == 0 ||
+ strchr(path, '/') == NULL)) { // Simple filename only
if (is_debug_mode()) {
- printf("Warning: Font path not in safe directory list: %s\n", path);
+ printf("Warning: Font path not in safe directory: %s\n", path);
}
continue;
}
@@ -805,80 +820,25 @@ void render(SDL_Renderer *renderer, const FontSet *fonts, ViewState* view) { view->viewDirty = 0;
}
-// Font management functions
-b32 load_fonts(FontSet *fonts) {
- if (!fonts) return 0;
-
- // Initialize to NULL for safe cleanup
- fonts->regular = NULL;
- fonts->title = NULL;
- fonts->label = NULL;
- fonts->axis = NULL;
- fonts->label_bold = NULL;
-
- fonts->regular = load_font_safe(SAFE_FONT_PATHS, 16);
- fonts->title = load_font_safe(SAFE_BOLD_FONT_PATHS, 20);
- fonts->label = load_font_safe(SAFE_FONT_PATHS, 11);
- fonts->axis = load_font_safe(SAFE_FONT_PATHS, 8);
- fonts->label_bold = load_font_safe(SAFE_BOLD_FONT_PATHS, 12);
-
- // Debug output to check font loading
- if (is_debug_mode()) {
- printf("Font loading results:\n");
- printf(" Regular font: %s\n", fonts->regular ? "loaded" : "failed");
- printf(" Title/Bold font: %s\n", fonts->title ? "loaded" : "failed");
- printf(" Label font: %s\n", fonts->label ? "loaded" : "failed");
- printf(" Axis font: %s\n", fonts->axis ? "loaded" : "failed");
- printf(" Label bold font: %s\n", fonts->label_bold ? "loaded" : "failed");
- }
-
- // Check if at least one font loaded successfully
- if (!fonts->regular && !fonts->title && !fonts->label) {
- printf("Critical error: No fonts could be loaded\n");
- return 0;
- }
-
- // Use fallbacks if specific fonts failed
- if (!fonts->title && fonts->regular) {
- fonts->title = fonts->regular;
- if (is_debug_mode()) {
- printf("Warning: Using regular font as title font fallback - bold/regular distinction will be lost!\n");
- }
- }
- if (!fonts->label && fonts->regular) {
- fonts->label = fonts->regular;
- if (is_debug_mode()) {
- printf("Warning: Using regular font as label font fallback\n");
- }
- }
- if (!fonts->regular && fonts->title) {
- fonts->regular = fonts->title;
- if (is_debug_mode()) {
- printf("Warning: Using title font as regular font fallback\n");
- }
- }
- if (!fonts->axis && fonts->regular) {
- fonts->axis = fonts->regular;
- if (is_debug_mode()) {
- printf("Warning: Using regular font as axis font fallback\n");
- }
- }
- if (!fonts->label_bold && fonts->title) {
- fonts->label_bold = fonts->title;
- if (is_debug_mode()) {
- printf("Warning: Using title font as label bold font fallback\n");
- }
- } else if (!fonts->label_bold && fonts->label) {
- fonts->label_bold = fonts->label;
- if (is_debug_mode()) {
- printf("Warning: Using label font as label bold font fallback\n");
- }
+// Simplified font fallback system
+static void setup_font_fallbacks(FontSet *fonts) {
+ // Ensure we have at least one base font
+ TTF_Font* base_font = fonts->regular ? fonts->regular :
+ fonts->title ? fonts->title : fonts->label;
+
+ if (!base_font) {
+ return; // Nothing to work with
}
- return (fonts->regular && fonts->title && fonts->label && fonts->axis && fonts->label_bold) ? 1 : 0;
+ // Simple fallback chain - use base font for any missing font
+ if (!fonts->regular) fonts->regular = base_font;
+ if (!fonts->title) fonts->title = base_font;
+ if (!fonts->label) fonts->label = base_font;
+ if (!fonts->axis) fonts->axis = base_font;
+ if (!fonts->label_bold) fonts->label_bold = base_font;
}
-b32 load_adaptive_fonts(FontSet *fonts, i32 windowWidth, i32 windowHeight, f32 dpi) {
+b32 load_adaptive_fonts_OLD_COMPLEX(FontSet *fonts, i32 windowWidth, i32 windowHeight, f32 dpi) {
(void)windowHeight; // Suppress unused parameter warning
if (!fonts) return 0;
@@ -997,6 +957,67 @@ b32 load_adaptive_fonts(FontSet *fonts, i32 windowWidth, i32 windowHeight, f32 d return (fonts->regular && fonts->title && fonts->label && fonts->axis && fonts->label_bold) ? 1 : 0;
}
+// Simplified font loading with adaptive sizing
+b32 load_adaptive_fonts(FontSet *fonts, i32 windowWidth, i32 windowHeight, f32 dpi) {
+ (void)windowHeight; // Suppress unused parameter warning
+
+ if (!fonts) return 0;
+
+ // Validate and use defaults if needed
+ if (windowWidth <= 0 || dpi <= 0) {
+ windowWidth = 800;
+ dpi = 96.0f;
+ }
+
+ // Calculate font sizes with proper validation
+ i32 regularSize = (i32)(16.0f * dpi / 96.0f * windowWidth / 800.0f);
+ i32 titleSize = (i32)(20.0f * dpi / 96.0f * windowWidth / 800.0f);
+ i32 labelSize = (i32)(17.0f * dpi / 96.0f * windowWidth / 800.0f); // +6pt from 11pt
+ i32 axisSize = (i32)(14.0f * dpi / 96.0f * windowWidth / 800.0f); // +6pt from 8pt
+ i32 labelBoldSize = (i32)(18.0f * dpi / 96.0f * windowWidth / 800.0f); // +6pt from 12pt
+
+ // Clamp to safe ranges
+ if (regularSize < 10) regularSize = 10;
+ if (regularSize > 32) regularSize = 32;
+ if (titleSize < 12) titleSize = 12;
+ if (titleSize > 36) titleSize = 36;
+ if (labelSize < 12) labelSize = 12; // Updated minimum for larger labels
+ if (labelSize > 26) labelSize = 26; // Updated maximum for larger labels
+ if (axisSize < 10) axisSize = 10; // Updated minimum for larger axis fonts
+ if (axisSize > 24) axisSize = 24; // Updated maximum for larger axis fonts
+ if (labelBoldSize < 12) labelBoldSize = 12; // Updated minimum for larger bold labels
+ if (labelBoldSize > 26) labelBoldSize = 26; // Updated maximum for larger bold labels
+
+ // Initialize all to NULL
+ fonts->regular = fonts->title = fonts->label = fonts->axis = fonts->label_bold = NULL;
+
+ // Load fonts with calculated sizes
+ fonts->regular = load_font_safe(SAFE_FONT_PATHS, regularSize);
+ fonts->title = load_font_safe(SAFE_BOLD_FONT_PATHS, titleSize);
+ fonts->label = load_font_safe(SAFE_FONT_PATHS, labelSize);
+ fonts->axis = load_font_safe(SAFE_FONT_PATHS, axisSize);
+ fonts->label_bold = load_font_safe(SAFE_BOLD_FONT_PATHS, labelBoldSize);
+
+ // Apply fallback system
+ setup_font_fallbacks(fonts);
+
+ if (is_debug_mode()) {
+ printf("Fonts loaded (sizes: reg=%d, title=%d, label=%d, axis=%d): regular=%s, title=%s, label=%s, axis=%s\n",
+ regularSize, titleSize, labelSize, axisSize,
+ fonts->regular ? "ok" : "fail",
+ fonts->title ? "ok" : "fail",
+ fonts->label ? "ok" : "fail",
+ fonts->axis ? "ok" : "fail");
+ }
+
+ return fonts->regular ? 1 : 0;
+}
+
+// Simple font loading with fixed sizes
+b32 load_fonts(FontSet *fonts) {
+ return load_adaptive_fonts(fonts, 800, 600, 96.0f);
+}
+
void free_fonts(FontSet *fonts) {
if (fonts->regular) {
TTF_CloseFont(fonts->regular);
diff --git a/src/glamac/glamac_view.c b/src/glamac/glamac_view.c index 12c96fd..1fb8395 100644 --- a/src/glamac/glamac_view.c +++ b/src/glamac/glamac_view.c @@ -27,6 +27,9 @@ void init_view_state(ViewState* view, i32 windowWidth, i32 windowHeight) { view->viewDirty = 1; // Initial render needed
view->forceRenderFrames = 0; // No forced rendering initially
+ // Initialize coordinate transformation cache
+ view->transform_cache.valid = 0;
+
// Initialize tight clustering data
view->tightClusters = NULL;
view->tightClusterCount = 0;
|