From 91c024d42e54c3db70fa9693525c0dc2b5e775fc Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 6 Aug 2025 16:24:05 +0200 Subject: last version with windows --- include/glamac/graphics/glamac_view.h | 12 ++- src/glamac/glamac.c | 70 +++--------------- src/glamac/glamac_render.c | 56 ++++++++++++-- src/glamac/glamac_view.c | 134 +++++++++++++++++++++++++++++++++- 4 files changed, 200 insertions(+), 72 deletions(-) diff --git a/include/glamac/graphics/glamac_view.h b/include/glamac/graphics/glamac_view.h index a15aaf1..c7b00d9 100644 --- a/include/glamac/graphics/glamac_view.h +++ b/include/glamac/graphics/glamac_view.h @@ -8,8 +8,8 @@ #include "../core/glamacdef.h" // Constants for view -#define MIN_PADDING 15 // Minimum padding in pixels (reduced for small windows) -#define MAX_PADDING_PERCENT 0.06f // Maximum padding as percentage of window size (increased for responsiveness) +#define MIN_PADDING 20 // Minimum padding in pixels +#define MAX_PADDING_PERCENT 0.04f // Maximum padding as percentage of window size #define PAN_STEP 0.05f // Step size for keyboard panning #define ZOOM_FACTOR 1.2f // Zoom factor for zoom operations #define MIN_ZOOM 0.5f // Minimum zoom level @@ -59,6 +59,7 @@ typedef struct { u32 gKeyTime; // Time when 'g' was pressed for sequence timing i32 selectedGlass; // Index of selected glass (-1 if none) b32 viewDirty; // Flag to track if view needs re-rendering + u32 forceRenderFrames; // Number of additional frames to force rendering (for transitions) // Tight clustering data TightCluster* tightClusters; // Array of tight clusters @@ -79,6 +80,13 @@ static inline i32 get_adaptive_padding(const ViewState* view) { return padding > MIN_PADDING ? padding : MIN_PADDING; } +// Helper function to calculate adaptive padding for specific dimensions +static inline i32 get_adaptive_padding_for_size(i32 windowWidth, i32 windowHeight) { + (void)windowHeight; // Suppress unused parameter warning + i32 padding = (i32)(windowWidth * MAX_PADDING_PERCENT); + return padding > MIN_PADDING ? padding : MIN_PADDING; +} + // Convert glass data to screen coordinates with zoom and offset static inline void data_to_screen_coords(f32 abbeNumber, f32 refractiveIndex, const ViewState* view, i32 *x, i32 *y) { diff --git a/src/glamac/glamac.c b/src/glamac/glamac.c index a26c7e6..7f361ab 100644 --- a/src/glamac/glamac.c +++ b/src/glamac/glamac.c @@ -36,9 +36,9 @@ b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) { } // Hysteresis parameters - reduced for better responsiveness - const f32 threshold = 0.15f; // 15% change threshold (more sensitive for fullscreen) - const u32 minReloadInterval = 50; // Minimum 50ms between font reloads (faster response) - const u32 maxPendingTime = 300; // Maximum time to wait for pending reload + 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 u32 currentTime = SDL_GetTicks(); @@ -48,20 +48,13 @@ b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) { b32 significantChange = (widthDiff > (i32)(view->windowWidth * threshold) || heightDiff > (i32)(view->windowHeight * threshold)); - // Detect major changes (like fullscreen transitions) - force immediate reload - b32 majorChange = (widthDiff > 200 || heightDiff > 200 || - (lastWidth > 0 && lastHeight > 0 && - (abs(view->windowWidth - lastWidth) > (view->windowWidth / 2) || - abs(view->windowHeight - lastHeight) > (view->windowHeight / 2)))); - - if (significantChange || majorChange) { + if (significantChange) { // Update pending dimensions pendingWidth = view->windowWidth; pendingHeight = view->windowHeight; - // For major changes, force immediate reload regardless of timing - // For normal changes, check if enough time has passed since last reload - if (majorChange || currentTime - lastReloadTime >= minReloadInterval) { + // 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", lastWidth, lastHeight, view->windowWidth, view->windowHeight); @@ -111,7 +104,10 @@ b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) { pendingWidth = pendingHeight = 0; // Clear pending state // Mark view as dirty to re-render with new fonts - mark_view_dirty(view); + // Only if not in the middle of forced rendering (e.g., from reset_view) + if (view->forceRenderFrames == 0) { + mark_view_dirty(view); + } if (is_debug_mode()) { printf("Fonts successfully reloaded for window size: %dx%d\n", @@ -146,52 +142,6 @@ b32 reload_fonts_if_needed(FontSet *fonts, ViewState *view, f32 dpi) { return 1; } -// Force font reload (for fullscreen transitions and other critical updates) -b32 force_font_reload(FontSet *fonts, ViewState *view, f32 dpi) { - if (!fonts || !view) { - printf("Error: Invalid parameters for forced font reload\n"); - return 0; - } - - if (is_debug_mode()) { - printf("Force reloading fonts for window size: %dx%d\n", - view->windowWidth, view->windowHeight); - } - - // Clear text cache first - clear_text_cache(); - - // Store current fonts as backup - FontSet backup_fonts = *fonts; - - // Try to reload with new size - if (!load_adaptive_fonts(fonts, view->windowWidth, view->windowHeight, dpi)) { - printf("Error: Failed to force reload fonts, restoring backup\n"); - - // Restore backup fonts - *fonts = backup_fonts; - return 0; - } - - // Free backup fonts if new loading succeeded - if (backup_fonts.regular != fonts->regular && backup_fonts.regular) { - TTF_CloseFont(backup_fonts.regular); - } - if (backup_fonts.title != fonts->title && backup_fonts.title) { - TTF_CloseFont(backup_fonts.title); - } - if (backup_fonts.label != fonts->label && backup_fonts.label) { - TTF_CloseFont(backup_fonts.label); - } - if (backup_fonts.axis != fonts->axis && backup_fonts.axis) { - TTF_CloseFont(backup_fonts.axis); - } - if (backup_fonts.label_bold != fonts->label_bold && backup_fonts.label_bold) { - TTF_CloseFont(backup_fonts.label_bold); - } - - return 1; -} // Initial window dimensions #define INITIAL_WIDTH 800 diff --git a/src/glamac/glamac_render.c b/src/glamac/glamac_render.c index 9743e7f..c375754 100644 --- a/src/glamac/glamac_render.c +++ b/src/glamac/glamac_render.c @@ -366,6 +366,16 @@ void draw_axes(SDL_Renderer *renderer, const FontSet *fonts, const ViewState* vi f32 visibleMinAbbe, visibleMaxAbbe, visibleMinRI, visibleMaxRI; get_visible_data_range(view, &visibleMinAbbe, &visibleMaxAbbe, &visibleMinRI, &visibleMaxRI); + if (is_debug_mode() && view->forceRenderFrames > 0) { + printf("Visible range: Abbe(%.2f-%.2f) RI(%.4f-%.4f), zoom=%.2f, offset=(%.2f,%.2f), window=%dx%d\n", + visibleMinAbbe, visibleMaxAbbe, visibleMinRI, visibleMaxRI, + view->zoomLevel, view->offsetX, view->offsetY, view->windowWidth, view->windowHeight); + printf("Full range: Abbe(%.2f-%.2f) RI(%.4f-%.4f)\n", + view->minAbbe, view->maxAbbe, view->minRI, view->maxRI); + printf("Plot area bounds: x=%d to %d, y=%d to %d\n", + padding, view->windowWidth - padding, padding, view->windowHeight - padding); + } + // Validate the visible range - fallback to full range if invalid if (!isfinite(visibleMinAbbe) || !isfinite(visibleMaxAbbe) || !isfinite(visibleMinRI) || !isfinite(visibleMaxRI) || @@ -413,14 +423,28 @@ void draw_axes(SDL_Renderer *renderer, const FontSet *fonts, const ViewState* vi } // Move the bottom-most number up slightly to avoid overlap with X-axis labels i32 yOffset = (i == 0) ? -15 : -8; - // Adaptive positioning based on window size - i32 axisLabelOffset = (view->windowWidth < 600) ? padding - 35 : padding - 45; + // More conservative positioning to prevent cut-off + i32 axisLabelOffset; + if (view->windowWidth < 500) { + axisLabelOffset = padding - 30; // Very small windows - stay closer to axis + } else if (view->windowWidth < 700) { + axisLabelOffset = padding - 35; // Medium windows + } else { + axisLabelOffset = padding - 45; // Large windows + } draw_text_direct(renderer, axisFont, buffer, axisLabelOffset, y + yOffset, black); } // Axis titles with subscripts - using regular font (2pt smaller than title) - // Adaptive positioning based on window size - i32 abbeNumberY = (view->windowHeight < 500) ? view->windowHeight - 25 : view->windowHeight - 35; + // More adaptive positioning to avoid collision with horizontal axis + i32 abbeNumberY; + if (view->windowHeight < 400) { + abbeNumberY = view->windowHeight - 20; // Very small windows + } else if (view->windowHeight < 600) { + abbeNumberY = view->windowHeight - 30; // Medium windows + } else { + abbeNumberY = view->windowHeight - 35; // Large windows + } draw_text(renderer, fonts->regular, "Abbe Number (Vd)", view->windowWidth/2 - 80, abbeNumberY, black); // Vertical text for Y-axis (simplified) @@ -533,7 +557,20 @@ void draw_glass_points(SDL_Renderer *renderer, const FontSet *fonts, const ViewS } // Debug output if enabled - if (is_debug_mode()) { + if (is_debug_mode() && view->forceRenderFrames > 0) { + printf("Rendering: %u/%u glasses visible, %u labels drawn (zoom: %.2f)\n", + visibleCount, glassCount, labelCount, view->zoomLevel); + + // Show coordinates of first few glasses for debugging + for (u32 i = 0; i < 3 && i < glassCount; i++) { + const Glass* glass = get_glass(i); + if (!glass) continue; + i32 x, y; + data_to_screen_coords(glass->abbeNumber, glass->refractiveIndex, view, &x, &y); + printf(" Glass %u (%.2f, %.4f) -> screen (%d, %d)\n", + i, glass->abbeNumber, glass->refractiveIndex, x, y); + } + } else if (is_debug_mode()) { static u32 lastReportTime = 0; u32 currentTime = SDL_GetTicks(); if (currentTime - lastReportTime > 1000) { // Report every second @@ -732,11 +769,16 @@ void render(SDL_Renderer *renderer, const FontSet *fonts, ViewState* view) { printf("Error: Invalid fonts for render\n"); return; } - // Only render if view is dirty (needs update) - if (!view->viewDirty) { + // Only render if view is dirty (needs update) or forced rendering is active + if (!view->viewDirty && view->forceRenderFrames == 0) { return; } + // Decrement forced rendering counter + if (view->forceRenderFrames > 0) { + view->forceRenderFrames--; + } + // Clear screen SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderClear(renderer); diff --git a/src/glamac/glamac_view.c b/src/glamac/glamac_view.c index 35c5806..12c96fd 100644 --- a/src/glamac/glamac_view.c +++ b/src/glamac/glamac_view.c @@ -25,6 +25,7 @@ void init_view_state(ViewState* view, i32 windowWidth, i32 windowHeight) { view->gKeyTime = 0; view->selectedGlass = -1; // No glass selected initially view->viewDirty = 1; // Initial render needed + view->forceRenderFrames = 0; // No forced rendering initially // Initialize tight clustering data view->tightClusters = NULL; @@ -61,6 +62,12 @@ void get_visible_data_range(const ViewState* view, f32 *visibleMinAbbe, f32 *vis screen_to_data_coords(view->windowWidth - padding, view->windowHeight - padding, view, &bottomRightAbbe, &bottomRightRI); + if (is_debug_mode() && view->forceRenderFrames > 0) { + printf("Screen corners: top-left(%d,%d) -> data(%.2f,%.4f), bottom-right(%d,%d) -> data(%.2f,%.4f)\n", + padding, padding, topLeftAbbe, topLeftRI, + view->windowWidth - padding, view->windowHeight - padding, bottomRightAbbe, bottomRightRI); + } + // NOTE: With flipped axis, topLeftAbbe is now the maximum and bottomRightAbbe is minimum *visibleMaxAbbe = topLeftAbbe; *visibleMinAbbe = bottomRightAbbe; @@ -130,31 +137,114 @@ void handle_mouse_wheel_zoom(i32 wheelY, i32 mouseX, i32 mouseY, ViewState* view void toggle_fullscreen(SDL_Window* window, ViewState* view) { if (!window || !view) return; + // Store original windowed size for restoration + static i32 windowedWidth = 800; // Default windowed size + static i32 windowedHeight = 600; + bool isFullscreen = SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN; if (!isFullscreen) { + // Store current windowed size before going fullscreen + windowedWidth = view->windowWidth; + windowedHeight = view->windowHeight; + // Entering fullscreen SDL_SetWindowFullscreen(window, true); } else { - // Exiting fullscreen + // Exiting fullscreen - restore original windowed size SDL_SetWindowFullscreen(window, false); + + if (is_debug_mode()) { + printf("Restoring window size to %dx%d\n", windowedWidth, windowedHeight); + } + + SDL_SetWindowSize(window, windowedWidth, windowedHeight); + + // Also center the window for better behavior + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); } - // Wait a bit longer for the window system to process the state change - SDL_Delay(100); + // Wait longer for the window system to process the state change + SDL_Delay(200); // Get updated window dimensions after fullscreen toggle i32 newWidth, newHeight; SDL_GetWindowSize(window, &newWidth, &newHeight); + // If we're exiting fullscreen and the size didn't change, force it + if (isFullscreen && (newWidth != windowedWidth || newHeight != windowedHeight)) { + if (is_debug_mode()) { + printf("Window size restoration failed (%dx%d != %dx%d), forcing update\n", + newWidth, newHeight, windowedWidth, windowedHeight); + } + + // Try multiple times with delays + for (int attempt = 0; attempt < 3; attempt++) { + SDL_SetWindowSize(window, windowedWidth, windowedHeight); + SDL_Delay(100); + SDL_GetWindowSize(window, &newWidth, &newHeight); + + if (newWidth == windowedWidth && newHeight == windowedHeight) { + if (is_debug_mode()) { + printf("Window size restoration succeeded on attempt %d\n", attempt + 1); + } + break; + } + } + + // Final fallback - force the view state to match reality + if (newWidth != windowedWidth || newHeight != windowedHeight) { + if (is_debug_mode()) { + printf("Window size restoration failed completely, forcing view state update\n"); + } + } + } + // Validate new dimensions if (newWidth > 0 && newHeight > 0) { + if (is_debug_mode()) { + printf("Fullscreen toggle: %s, size: %dx%d -> %dx%d, zoom=%.2f, offset=(%.2f,%.2f)\n", + isFullscreen ? "OFF" : "ON", + view->windowWidth, view->windowHeight, newWidth, newHeight, + view->zoomLevel, view->offsetX, view->offsetY); + } + + // Calculate the ratio of plotting areas to adjust zoom/offset + i32 oldPadding = get_adaptive_padding_for_size(view->windowWidth, view->windowHeight); + i32 newPadding = get_adaptive_padding_for_size(newWidth, newHeight); + i32 oldPlotWidth = view->windowWidth - 2 * oldPadding; + i32 oldPlotHeight = view->windowHeight - 2 * oldPadding; + i32 newPlotWidth = newWidth - 2 * newPadding; + i32 newPlotHeight = newHeight - 2 * newPadding; + + // If plotting area changed significantly, reset zoom/offset to prevent partial view + f32 plotRatioX = (f32)newPlotWidth / (f32)oldPlotWidth; + f32 plotRatioY = (f32)newPlotHeight / (f32)oldPlotHeight; + + if (is_debug_mode()) { + printf("Plot area change: %dx%d -> %dx%d (ratio: %.2fx%.2f)\n", + oldPlotWidth, oldPlotHeight, newPlotWidth, newPlotHeight, plotRatioX, plotRatioY); + } + + // Reset view if plot area changes dramatically (more than 50% difference) + if (plotRatioX < 0.5f || plotRatioX > 2.0f || plotRatioY < 0.5f || plotRatioY > 2.0f) { + if (is_debug_mode()) { + printf("Dramatic plot area change detected, resetting zoom/offset\n"); + } + view->zoomLevel = 1.0f; + view->offsetX = 0.0f; + view->offsetY = 0.0f; + } + view->windowWidth = newWidth; view->windowHeight = newHeight; // Force a complete refresh after fullscreen toggle mark_view_dirty(view); + // Force rendering for several frames to ensure proper transition + view->forceRenderFrames = 3; + if (is_debug_mode()) { printf("Fullscreen toggled: %s, new size: %dx%d\n", isFullscreen ? "OFF" : "ON", newWidth, newHeight); @@ -167,13 +257,51 @@ void toggle_fullscreen(SDL_Window* window, ViewState* view) { // Reset view to default void reset_view(ViewState* view) { + if (is_debug_mode()) { + printf("Reset view: zoom=%.2f, offsetX=%.2f, offsetY=%.2f, window=%dx%d\n", + view->zoomLevel, view->offsetX, view->offsetY, view->windowWidth, view->windowHeight); + printf("Data bounds before reset: Abbe(%.2f-%.2f) RI(%.4f-%.4f)\n", + view->minAbbe, view->maxAbbe, view->minRI, view->maxRI); + } + view->zoomLevel = 1.0f; view->offsetX = 0.0f; view->offsetY = 0.0f; view->selectedGlass = -1; + // Recalculate data bounds to ensure they're correct + find_glass_data_range(&view->minAbbe, &view->maxAbbe, &view->minRI, &view->maxRI); + + // Test coordinate transformation for debugging + if (is_debug_mode()) { + i32 padding = get_adaptive_padding(view); + printf("Padding: %d, plot area: %dx%d\n", + padding, view->windowWidth - 2*padding, view->windowHeight - 2*padding); + + // Test transformation of center point + f32 centerAbbe = (view->minAbbe + view->maxAbbe) / 2.0f; + f32 centerRI = (view->minRI + view->maxRI) / 2.0f; + i32 centerX, centerY; + data_to_screen_coords(centerAbbe, centerRI, view, ¢erX, ¢erY); + printf("Center glass (%.2f, %.4f) maps to screen (%d, %d)\n", + centerAbbe, centerRI, centerX, centerY); + + // Expected center should be around (windowWidth/2, windowHeight/2) + printf("Expected center: (%d, %d)\n", view->windowWidth/2, view->windowHeight/2); + } + // Force complete refresh - this ensures fonts and layout are recalculated mark_view_dirty(view); + + // Force rendering for several frames to ensure proper reset after transitions + view->forceRenderFrames = 3; + + if (is_debug_mode()) { + printf("Reset view complete: zoom=%.2f, offsetX=%.2f, offsetY=%.2f\n", + view->zoomLevel, view->offsetX, view->offsetY); + printf("Data bounds after reset: Abbe(%.2f-%.2f) RI(%.4f-%.4f)\n", + view->minAbbe, view->maxAbbe, view->minRI, view->maxRI); + } } // Helper function to calculate string length for name comparison -- cgit v1.2.3