From f2e672f84d8cd45971c415c67d69237d09a8033a Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 24 May 2025 19:17:27 +0200 Subject: changed to sdl3 and added linux/cross-compilation --- Makefile | 294 ++++++++++++++++++++++++++++++++++++++------- include/glamac_events.h | 11 +- include/glamac_render.h | 13 +- include/glamac_view.h | 11 +- include/glamacdef.h | 1 + src/glamac/glamac.c | 43 +++---- src/glamac/glamac_events.c | 84 ++++++------- src/glamac/glamac_render.c | 194 +++++++++++++++++++++--------- src/glamac/glamac_view.c | 19 +-- 9 files changed, 450 insertions(+), 220 deletions(-) diff --git a/Makefile b/Makefile index 904806c..69b9f44 100644 --- a/Makefile +++ b/Makefile @@ -1,67 +1,269 @@ +# Simple Makefile for glamac - SDL3 version +# Supports: Arch Linux native, Windows cross-compilation CC=gcc -# Base Directories +MINGW_CC=x86_64-w64-mingw32-gcc + +# Directories SRCDIR=src BINDIR=bin +BINDIR_WIN=bin/win INCDIR=include -RESDIR=res + +# SDL3 paths for cross-compilation +CROSS_WIN_SDL3_PREFIX ?= /usr/x86_64-w64-mingw32 +CROSS_WIN_SDL3_INCLUDE ?= $(CROSS_WIN_SDL3_PREFIX)/include +CROSS_WIN_SDL3_LIB ?= $(CROSS_WIN_SDL3_PREFIX)/lib + +# DLL cache directory +DLL_CACHE_DIR = $(HOME)/.cache/glamac-dlls # Common flags -CFLAGS=-I$(INCDIR) -O2 -march=native -flto #-ffast-math +CFLAGS_BASE=-I$(INCDIR) -O2 -flto +CFLAGS_NATIVE=$(CFLAGS_BASE) -march=native +CFLAGS_CROSS=$(CFLAGS_BASE) -I$(CROSS_WIN_SDL3_INCLUDE) -# Resource compiler for Windows -WINDRES=windres +# OS Detection +ifeq ($(OS),Windows_NT) + # Windows host + EXE_EXT=.exe + MKDIR=mkdir + RM=del /Q + RMDIR=rmdir /s /q + SDL3_LDFLAGS=-lSDL3 -lSDL3_ttf -mwindows + NATIVE_CC=$(CC) + NATIVE_CFLAGS=$(CFLAGS_BASE) + NATIVE_LDFLAGS=$(SDL3_LDFLAGS) + NATIVE_EXT=.exe +else + # Linux host (Arch) + EXE_EXT= + MKDIR=mkdir -p + RM=rm -f + RMDIR=rm -rf + SDL3_LDFLAGS=$(shell pkg-config --cflags --libs sdl3 SDL3_ttf 2>/dev/null || echo -lSDL3 -lSDL3_ttf) -lm + NATIVE_CC=$(CC) + NATIVE_CFLAGS=$(CFLAGS_NATIVE) + NATIVE_LDFLAGS=$(SDL3_LDFLAGS) + NATIVE_EXT= + # Cross-compilation flags + CROSS_LDFLAGS=-L$(CROSS_WIN_SDL3_LIB) -lmingw32 -lSDL3 -lSDL3_ttf -mwindows -static-libgcc +endif -# Resource file definitions -RESOURCE_FILE=glamac.rc # Your resource script file with icon definitions -RESOURCE_OBJ=$(BINDIR)/glamac_res.o # The compiled resource object file +# Source files +GLAMAC_SRC_LIST=$(SRCDIR)/glamac/glamac.c \ + $(SRCDIR)/glamac/glamac_view.c \ + $(SRCDIR)/glamac/glamac_render.c \ + $(SRCDIR)/glamac/glamac_events.c \ + $(SRCDIR)/glamac/glass_data.c + +GLAMAC_SRC=$(wildcard $(GLAMAC_SRC_LIST)) +EXPECTED_GLAMAC_FILES=5 +FOUND_GLAMAC_FILES=$(words $(GLAMAC_SRC)) -# glautils GLA_SRCS=$(wildcard $(SRCDIR)/glautils/*.c) -GLA_EXES=$(patsubst $(SRCDIR)/glautils/%.c, $(BINDIR)/%.exe, $(GLA_SRCS)) - -# glamac -GLAMAC_SRC=$(SRCDIR)/glamac/glamac.c \ - $(SRCDIR)/glamac/glamac_view.c \ - $(SRCDIR)/glamac/glamac_render.c \ - $(SRCDIR)/glamac/glamac_events.c \ - $(SRCDIR)/glamac/glass_data.c - -# SDL2 Flags -SDL2_CFLAGS=-I$(USERPROFILE)/scoop/apps/sdl2/current/include/SDl2 -I$(USERPROFILE)/scoop/apps/sdl2-ttf/current/include/SDL2_ttf -O2 -march=native -flto -s #-ffast-math -SDL2_LDFLAGS=-L$(USERPROFILE)/scoop/apps/sdl2/current/lib -L$(USERPROFILE)/scoop/apps/sdl2-ttf/current/lib -lSDL2main -lSDL2 -lSDL2_ttf -mwindows -flto -SDL2_DLL_SRC=$(USERPROFILE)/scoop/apps/sdl2/current/lib/SDL2.dll -SDL2_tff_DLL_SRC=$(USERPROFILE)/scoop/apps/sdl2-ttf/current/lib/SDL2_ttf.dll -SDL2_DLL_DEST=$(BINDIR) - -# Setup target +GLA_EXES_NATIVE=$(patsubst $(SRCDIR)/glautils/%.c, $(BINDIR)/%$(NATIVE_EXT), $(GLA_SRCS)) +GLA_EXES_WIN=$(patsubst $(SRCDIR)/glautils/%.c, $(BINDIR_WIN)/%.exe, $(GLA_SRCS)) + +# Setup targets setup: - mkdir -p $(BINDIR) + $(MKDIR) $(BINDIR) + +setup-cross: + $(MKDIR) $(BINDIR) $(BINDIR_WIN) + +# Check source files +check-files: + @echo "Checking for glamac source files..." + @echo "Expected $(EXPECTED_GLAMAC_FILES) files, found $(FOUND_GLAMAC_FILES)" + @if [ $(FOUND_GLAMAC_FILES) -ne $(EXPECTED_GLAMAC_FILES) ]; then \ + echo "ERROR: Missing glamac source files!"; \ + exit 1; \ + fi + @echo "All glamac source files found." + +# Default: build for current platform +all: check-files setup glamac glautils + +# Native compilation +glamac: check-files $(BINDIR)/glamac$(NATIVE_EXT) +glautils: $(GLA_EXES_NATIVE) + +$(BINDIR)/glamac$(NATIVE_EXT): $(GLAMAC_SRC) + @echo "Compiling glamac..." + $(NATIVE_CC) $^ $(NATIVE_CFLAGS) $(NATIVE_LDFLAGS) -o $@ + +$(BINDIR)/%$(NATIVE_EXT): $(SRCDIR)/glautils/%.c + $(NATIVE_CC) $< $(NATIVE_CFLAGS) -o $@ -all: glautils glamac sdl2 structure +# Windows cross-compilation (Linux only) +ifeq ($(OS),Windows_NT) +# Windows host - no cross-compilation needed +glamac-win all-win: + @echo "Cross-compilation not needed on Windows. Use 'make all' instead." -glautils: $(GLA_EXES) -$(BINDIR)/%.exe: $(SRCDIR)/glautils/%.c - $(CC) $< $(CFLAGS) -o $@ +install-sdl3-cross download-dlls install-dlls copy-dlls-win: + @echo "Cross-compilation operations not available on Windows host." -# Compile resource file -$(RESOURCE_OBJ): $(RESOURCE_FILE) - $(WINDRES) -i $< -o $@ +else +# Linux host - cross-compilation available -# Link glamac with resources -glamac: $(BINDIR)/glamac.exe -$(BINDIR)/glamac.exe: $(GLAMAC_SRC) $(RESOURCE_OBJ) - $(CC) $^ $(CFLAGS) $(SDL2_CFLAGS) $(SDL2_LDFLAGS) -o $@ +# Check cross-compilation dependencies +check-cross-deps: + @echo "Checking cross-compilation dependencies..." + @which $(MINGW_CC) >/dev/null 2>&1 || (echo "ERROR: $(MINGW_CC) not found. Install with: sudo pacman -S mingw-w64-gcc" && exit 1) + @test -f $(CROSS_WIN_SDL3_INCLUDE)/SDL3/SDL.h || (echo "ERROR: SDL3 headers not found. Run 'make install-sdl3-cross'" && exit 1) + @test -f $(CROSS_WIN_SDL3_LIB)/libSDL3.dll.a || (echo "ERROR: SDL3 libraries not found. Run 'make install-sdl3-cross'" && exit 1) + @echo "Cross-compilation dependencies OK" -sdl2: - cp $(SDL2_DLL_SRC) $(SDL2_DLL_DEST) - cp $(SDL2_tff_DLL_SRC) $(SDL2_DLL_DEST) +# Windows targets +glamac-win: check-files check-cross-deps setup-cross $(BINDIR_WIN)/glamac.exe copy-dlls-win +all-win: glamac-win $(GLA_EXES_WIN) +$(BINDIR_WIN)/glamac.exe: $(GLAMAC_SRC) + @echo "Cross-compiling glamac for Windows..." + $(MINGW_CC) $^ $(CFLAGS_CROSS) $(CROSS_LDFLAGS) -o $@ + +$(BINDIR_WIN)/%.exe: $(SRCDIR)/glautils/%.c + $(MINGW_CC) $< $(CFLAGS_CROSS) -static-libgcc -o $@ + +# DLL Management + +# Download DLLs to cache (only once) +download-dlls: + @echo "Downloading SDL3 DLLs to cache..." + @$(MKDIR) $(DLL_CACHE_DIR) + + @if [ ! -f "$(DLL_CACHE_DIR)/SDL3.dll" ]; then \ + echo "Downloading SDL3.dll..."; \ + cd $(DLL_CACHE_DIR) && \ + wget -q https://github.com/libsdl-org/SDL/releases/download/release-3.2.10/SDL3-3.2.10-win32-x64.zip && \ + unzip -j SDL3-3.2.10-win32-x64.zip SDL3.dll && \ + rm SDL3-3.2.10-win32-x64.zip; \ + else \ + echo "SDL3.dll already cached"; \ + fi + + @if [ ! -f "$(DLL_CACHE_DIR)/SDL3_ttf.dll" ]; then \ + echo "Downloading SDL3_ttf.dll..."; \ + cd $(DLL_CACHE_DIR) && \ + wget -q https://github.com/libsdl-org/SDL_ttf/releases/download/release-3.2.2/SDL3_ttf-3.2.2-win32-x64.zip && \ + unzip -j SDL3_ttf-3.2.2-win32-x64.zip SDL3_ttf.dll && \ + rm SDL3_ttf-3.2.2-win32-x64.zip; \ + else \ + echo "SDL3_ttf.dll already cached"; \ + fi + + @echo "DLLs cached in $(DLL_CACHE_DIR)/" + +# Install DLLs to system location (optional, for system-wide access) +install-dlls: download-dlls + @echo "Installing DLLs to system location..." + sudo cp $(DLL_CACHE_DIR)/SDL3.dll $(CROSS_WIN_SDL3_PREFIX)/bin/ 2>/dev/null || \ + (sudo mkdir -p $(CROSS_WIN_SDL3_PREFIX)/bin && sudo cp $(DLL_CACHE_DIR)/SDL3.dll $(CROSS_WIN_SDL3_PREFIX)/bin/) + sudo cp $(DLL_CACHE_DIR)/SDL3_ttf.dll $(CROSS_WIN_SDL3_PREFIX)/bin/ + @echo "DLLs installed to $(CROSS_WIN_SDL3_PREFIX)/bin/" + +# Copy DLLs to Windows build directory +copy-dlls-win: download-dlls + @echo "Copying DLLs for Windows distribution..." + @$(MKDIR) $(BINDIR_WIN) + cp $(DLL_CACHE_DIR)/SDL3.dll $(BINDIR_WIN)/ + cp $(DLL_CACHE_DIR)/SDL3_ttf.dll $(BINDIR_WIN)/ + @echo "" + @echo "Windows distribution ready in $(BINDIR_WIN)/" + @ls -la $(BINDIR_WIN)/ + @echo "" + @echo "Copy the entire $(BINDIR_WIN)/ directory to your Windows machine." + +# Install SDL3 for cross-compilation +install-sdl3-cross: + @echo "Installing SDL3 development libraries for MinGW cross-compilation..." + @echo "Latest versions: SDL3 3.2.10, SDL3_ttf 3.2.2" + @read -p "Continue? [y/N] " confirm && [ "$$confirm" = "y" ] || exit 1 + + @which wget >/dev/null 2>&1 || (echo "ERROR: wget not found. Install with: sudo pacman -S wget" && exit 1) + @which $(MINGW_CC) >/dev/null 2>&1 || (echo "ERROR: MinGW not found. Install with: sudo pacman -S mingw-w64-gcc" && exit 1) + + sudo mkdir -p $(CROSS_WIN_SDL3_PREFIX)/include $(CROSS_WIN_SDL3_PREFIX)/lib + + @echo "Downloading SDL3 development libraries..." + cd /tmp && \ + wget -q https://github.com/libsdl-org/SDL/releases/download/release-3.2.10/SDL3-devel-3.2.10-mingw.tar.gz && \ + wget -q https://github.com/libsdl-org/SDL_ttf/releases/download/release-3.2.2/SDL3_ttf-devel-3.2.2-mingw.tar.gz && \ + tar -xzf SDL3-devel-3.2.10-mingw.tar.gz && \ + tar -xzf SDL3_ttf-devel-3.2.2-mingw.tar.gz && \ + sudo cp -r SDL3-3.2.10/x86_64-w64-mingw32/include/* $(CROSS_WIN_SDL3_PREFIX)/include/ && \ + sudo cp -r SDL3-3.2.10/x86_64-w64-mingw32/lib/* $(CROSS_WIN_SDL3_PREFIX)/lib/ && \ + sudo cp -r SDL3_ttf-3.2.2/x86_64-w64-mingw32/include/* $(CROSS_WIN_SDL3_PREFIX)/include/ && \ + sudo cp -r SDL3_ttf-3.2.2/x86_64-w64-mingw32/lib/* $(CROSS_WIN_SDL3_PREFIX)/lib/ && \ + rm -rf SDL3-3.2.10* SDL3_ttf-3.2.2* + + @echo "SDL3 cross-compilation libraries installed successfully!" + +endif + +# Arch Linux SDL3 installation +install-sdl3-arch: + @echo "Installing SDL3 on Arch Linux..." + sudo pacman -S sdl3 + @echo "Installing SDL3_ttf from AUR (using yay)..." + yay -S sdl3_ttf + @echo "SDL3 installation complete!" + +# Clean targets clean: - rm -f $(BINDIR)/* - rm -f structure.txt +ifeq ($(OS),Windows_NT) + @if exist $(BINDIR) $(RMDIR) $(BINDIR) +else + $(RMDIR) $(BINDIR) 2>/dev/null || true +endif + +clean-dlls: +ifneq ($(OS),Windows_NT) + $(RMDIR) $(DLL_CACHE_DIR) 2>/dev/null || true + @echo "DLL cache cleared" +else + @echo "DLL cache operations not available on Windows" +endif rebuild: clean all -# Generate project structure -structure: - @powershell -Command "(Get-Item .).Name | Set-Content structure.txt; (tree /a /f | Select-Object -Skip 3) | Add-Content structure.txt" +# Help +help: + @echo "GlaMaC Build System - SDL3" + @echo "" + @echo "Native targets (any platform):" + @echo " all - Build for current platform" + @echo " glamac - Build glamac only" + @echo " glautils - Build utilities only" + @echo " clean - Clean build artifacts" + @echo " rebuild - Clean and rebuild" + @echo "" +ifeq ($(OS),Windows_NT) + @echo "Windows host - use native targets above" +else + @echo "Cross-compilation targets (Arch Linux → Windows):" + @echo " glamac-win - Build glamac for Windows (includes DLLs)" + @echo " all-win - Build everything for Windows" + @echo "" + @echo "Setup and maintenance:" + @echo " install-sdl3-arch - Install SDL3 on Arch Linux" + @echo " install-sdl3-cross - Install SDL3 for cross-compilation" + @echo " download-dlls - Download Windows DLLs to cache" + @echo " install-dlls - Install DLLs to system location" + @echo " copy-dlls-win - Copy DLLs to Windows build directory" + @echo " clean-dlls - Clear DLL cache" + @echo " check-cross-deps - Check cross-compilation setup" +endif + @echo "" + @echo "Quick start:" +ifeq ($(OS),Windows_NT) + @echo " 1. Install SDL3: (install SDL3 development libraries)" + @echo " 2. make all" +else + @echo " 1. sudo pacman -S mingw-w64-gcc # Install cross-compiler" + @echo " 2. make install-sdl3-cross # Install SDL3 for Windows" + @echo " 3. make glamac-win # Build for Windows (auto-downloads DLLs)" +endif + +.PHONY: all setup setup-cross glamac glautils glamac-win all-win check-files check-cross-deps download-dlls install-dlls copy-dlls-win install-sdl3-cross install-sdl3-arch clean clean-dlls rebuild help diff --git a/include/glamac_events.h b/include/glamac_events.h index 47ecb74..c4145c0 100644 --- a/include/glamac_events.h +++ b/include/glamac_events.h @@ -1,19 +1,10 @@ /** * glamac_events.h - header file from glamac_events.c. - * - * Copyright (C) 2025 https://optics-design.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * See the COPYING file for the full license text. */ #ifndef GLAMAC_EVENTS_H #define GLAMAC_EVENTS_H -#include +#include #include "glamacdef.h" #include "glamac_view.h" diff --git a/include/glamac_render.h b/include/glamac_render.h index df609c3..f18d53f 100644 --- a/include/glamac_render.h +++ b/include/glamac_render.h @@ -1,20 +1,11 @@ /** * glamac_render.h - header file from glamac_render.c. - * - * Copyright (C) 2025 https://optics-design.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * See the COPYING file for the full license text. */ #ifndef GLAMAC_RENDER_H #define GLAMAC_RENDER_H -#include -#include +#include +#include #include "glamacdef.h" #include "glamac_view.h" diff --git a/include/glamac_view.h b/include/glamac_view.h index b6846ad..8f0b984 100644 --- a/include/glamac_view.h +++ b/include/glamac_view.h @@ -1,19 +1,10 @@ /** * glamac_view.h - header file from glamac_view.c. - * - * Copyright (C) 2025 https://optics-design.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * See the COPYING file for the full license text. */ #ifndef GLAMAC_VIEW_H #define GLAMAC_VIEW_H -#include +#include #include "glamacdef.h" // Constants for view diff --git a/include/glamacdef.h b/include/glamacdef.h index 13fffbf..563df70 100644 --- a/include/glamacdef.h +++ b/include/glamacdef.h @@ -15,6 +15,7 @@ #include #include +#include /* Type definitions for consistent sizing across platforms. Idea taken from https://nullprogram.com/blog/2023/10/08/ (archive link: ) */ typedef uint8_t u8; typedef char16_t c16; diff --git a/src/glamac/glamac.c b/src/glamac/glamac.c index d176403..b834dbc 100644 --- a/src/glamac/glamac.c +++ b/src/glamac/glamac.c @@ -1,17 +1,8 @@ /** * glamac.c - main source file for the GlaMaC. - * - * Copyright (C) 2025 https://optics-design.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * See the COPYING file for the full license text. */ -#include -#include +#include +#include #include #include "glamacdef.h" // Type definitions #include "glass_data.h" // Glass catalog @@ -31,23 +22,22 @@ int main(int argc, char* argv[]) { SDL_Renderer* renderer = NULL; FontSet fonts = {0}; - // Initialize SDL2 - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - printf("SDL2 could not initialize! SDL_Error: %s\n", SDL_GetError()); + // Initialize SDL3 + if (!SDL_Init(SDL_INIT_VIDEO)) { + printf("SDL3 could not initialize! SDL_Error: %s\n", SDL_GetError()); return 1; } - // Initialize SDL_ttf - if (TTF_Init() < 0) { - printf("SDL_ttf could not initialize! TTF_Error: %s\n", TTF_GetError()); + // Initialize SDL3_ttf + if (!TTF_Init()) { + printf("SDL3_ttf could not initialize! SDL_Error: %s\n", SDL_GetError()); SDL_Quit(); return 1; } - // Create window with SDL2 - window = SDL_CreateWindow("GlaMaC", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - INITIAL_WIDTH, INITIAL_HEIGHT, - SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + // Create window with SDL3 + window = SDL_CreateWindow("GlaMaC", INITIAL_WIDTH, INITIAL_HEIGHT, + SDL_WINDOW_RESIZABLE); if (window == NULL) { printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); TTF_Quit(); @@ -56,7 +46,7 @@ int main(int argc, char* argv[]) { } // Create renderer with hardware acceleration and vsync - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + renderer = SDL_CreateRenderer(window, NULL); if (renderer == NULL) { printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); SDL_DestroyWindow(window); @@ -65,6 +55,9 @@ int main(int argc, char* argv[]) { return 1; } + // Enable vsync + SDL_SetRenderVSync(renderer, 1); + // Load fonts if (!load_fonts(&fonts)) { SDL_DestroyRenderer(renderer); @@ -93,12 +86,12 @@ int main(int argc, char* argv[]) { b32 dragging = 0; // Enable text input - SDL_StartTextInput(); + SDL_StartTextInput(window); // Main loop while (!quit) { // Handle events on queue - while (SDL_PollEvent(&e) != 0) { + while (SDL_PollEvent(&e)) { process_events(&e, &view, window, &lastMouseX, &lastMouseY, &dragging, &quit); } @@ -107,7 +100,7 @@ int main(int argc, char* argv[]) { } // Stop text input - SDL_StopTextInput(); + SDL_StopTextInput(window); // Clean up resources free_fonts(&fonts); diff --git a/src/glamac/glamac_events.c b/src/glamac/glamac_events.c index 29b7232..e5c706c 100644 --- a/src/glamac/glamac_events.c +++ b/src/glamac/glamac_events.c @@ -1,22 +1,13 @@ /** * glamac_events.c - source file detailing keyboard and mouse events used in GlaMaC. - * - * Copyright (C) 2025 https://optics-design.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * See the COPYING file for the full license text. */ -#include +#include #include "glamac_view.h" // Process key event b32 process_key_event(SDL_KeyboardEvent *key, ViewState *view, SDL_Window *window, b32 *quit) { - switch (key->keysym.sym) { - case SDLK_g: + switch (key->key) { + case SDLK_G: // First key in sequence view->gKeyPressed = 1; // Store the time when 'g' was pressed @@ -28,7 +19,7 @@ b32 process_key_event(SDL_KeyboardEvent *key, ViewState *view, SDL_Window *windo // Check if this is part of "g?" sequence (with shift for '?') if (view->gKeyPressed && (SDL_GetTicks() - view->gKeyTime < 1000)) { // If Shift is held (for '?' on most layouts) or it's a direct '?' key - if ((key->keysym.mod & KMOD_SHIFT) || key->keysym.sym == SDLK_QUESTION) { + if ((key->mod & SDL_KMOD_SHIFT) || key->key == SDLK_QUESTION) { view->showHelp = !view->showHelp; } view->gKeyPressed = 0; @@ -48,7 +39,7 @@ b32 process_key_event(SDL_KeyboardEvent *key, ViewState *view, SDL_Window *windo view->gKeyPressed = 0; return 1; - case SDLK_q: + case SDLK_Q: if (view->showHelp) { view->showHelp = 0; } else { @@ -72,38 +63,38 @@ b32 process_key_event(SDL_KeyboardEvent *key, ViewState *view, SDL_Window *windo view->gKeyPressed = 0; // Reset g key state return 1; - case SDLK_r: + case SDLK_R: // Reset view reset_view(view); view->gKeyPressed = 0; // Reset g key state return 1; - case SDLK_f: + case SDLK_F: // Toggle fullscreen toggle_fullscreen(window); view->gKeyPressed = 0; // Reset g key state return 1; // Vim-like navigation - case SDLK_h: + case SDLK_H: // Move left view->offsetX += PAN_STEP; view->gKeyPressed = 0; // Reset g key state return 1; - case SDLK_l: + case SDLK_L: // Move right view->offsetX -= PAN_STEP; view->gKeyPressed = 0; // Reset g key state return 1; - case SDLK_k: + case SDLK_K: // Move up view->offsetY -= PAN_STEP; view->gKeyPressed = 0; // Reset g key state return 1; - case SDLK_j: + case SDLK_J: // Move down view->offsetY += PAN_STEP; view->gKeyPressed = 0; // Reset g key state @@ -115,15 +106,15 @@ b32 process_key_event(SDL_KeyboardEvent *key, ViewState *view, SDL_Window *windo // Process mouse button event b32 process_mouse_button(SDL_MouseButtonEvent *button, ViewState *view, i32 *lastMouseX, i32 *lastMouseY, b32 *dragging) { - i32 mouseX, mouseY; + f32 mouseX, mouseY; switch (button->button) { case SDL_BUTTON_LEFT: - if (button->type == SDL_MOUSEBUTTONDOWN) { + if (button->type == SDL_EVENT_MOUSE_BUTTON_DOWN) { SDL_GetMouseState(&mouseX, &mouseY); // Check if click is near a glass point - i32 nearestGlass = find_nearest_glass(mouseX, mouseY, view, 15); // 15 pixels max distance + i32 nearestGlass = find_nearest_glass((i32)mouseX, (i32)mouseY, view, 15); // 15 pixels max distance if (nearestGlass >= 0) { view->selectedGlass = nearestGlass; // Don't start dragging when selecting a glass @@ -132,11 +123,11 @@ b32 process_mouse_button(SDL_MouseButtonEvent *button, ViewState *view, i32 *las view->selectedGlass = -1; // Start dragging for panning *dragging = 1; - *lastMouseX = mouseX; - *lastMouseY = mouseY; + *lastMouseX = (i32)mouseX; + *lastMouseY = (i32)mouseY; } return 1; - } else if (button->type == SDL_MOUSEBUTTONUP) { + } else if (button->type == SDL_EVENT_MOUSE_BUTTON_UP) { *dragging = 0; return 1; } @@ -150,21 +141,21 @@ b32 process_mouse_button(SDL_MouseButtonEvent *button, ViewState *view, i32 *las b32 process_mouse_motion(SDL_MouseMotionEvent *motion, ViewState *view, i32 *lastMouseX, i32 *lastMouseY, b32 dragging) { if (dragging) { // Get current mouse position - i32 mouseX, mouseY; + f32 mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); // Calculate normalized delta const i32 padding = (i32)(view->windowWidth * PADDING_PERCENT); - const f32 dx = (f32)(mouseX - *lastMouseX) / (view->windowWidth - 2 * padding); - const f32 dy = (f32)(mouseY - *lastMouseY) / (view->windowHeight - 2 * padding); + const f32 dx = (mouseX - *lastMouseX) / (view->windowWidth - 2 * padding); + const f32 dy = (mouseY - *lastMouseY) / (view->windowHeight - 2 * padding); // Update offset - inverted movement for natural feel view->offsetX += dx; view->offsetY -= dy; // Update last mouse position - *lastMouseX = mouseX; - *lastMouseY = mouseY; + *lastMouseX = (i32)mouseX; + *lastMouseY = (i32)mouseY; return 1; } @@ -174,11 +165,10 @@ b32 process_mouse_motion(SDL_MouseMotionEvent *motion, ViewState *view, i32 *las // Process window event b32 process_window_event(SDL_WindowEvent *window_event, ViewState *view) { - switch (window_event->event) { - case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_SIZE_CHANGED: - view->windowWidth = window_event->data1; - view->windowHeight = window_event->data2; + switch (window_event->type) { + case SDL_EVENT_WINDOW_RESIZED: + view->windowWidth = (i32)window_event->data1; + view->windowHeight = (i32)window_event->data2; return 1; } @@ -189,29 +179,31 @@ b32 process_window_event(SDL_WindowEvent *window_event, ViewState *view) { b32 process_events(SDL_Event *event, ViewState *view, SDL_Window *window, i32 *lastMouseX, i32 *lastMouseY, b32 *dragging, b32 *quit) { switch (event->type) { - case SDL_QUIT: + case SDL_EVENT_QUIT: *quit = 1; return 1; - case SDL_KEYDOWN: + case SDL_EVENT_KEY_DOWN: return process_key_event(&event->key, view, window, quit); - case SDL_MOUSEWHEEL: + case SDL_EVENT_MOUSE_WHEEL: // Get mouse position for centered zoom - i32 mouseX, mouseY; + f32 mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); - handle_mouse_wheel_zoom(event->wheel.y, mouseX, mouseY, view); + handle_mouse_wheel_zoom((i32)event->wheel.y, (i32)mouseX, (i32)mouseY, view); return 1; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: return process_mouse_button(&event->button, view, lastMouseX, lastMouseY, dragging); - case SDL_MOUSEMOTION: + case SDL_EVENT_MOUSE_MOTION: return process_mouse_motion(&event->motion, view, lastMouseX, lastMouseY, *dragging); - case SDL_WINDOWEVENT: - return process_window_event(&event->window, view); + case SDL_EVENT_WINDOW_RESIZED: + view->windowWidth = (i32)event->window.data1; + view->windowHeight = (i32)event->window.data2; + return 1; } return 0; diff --git a/src/glamac/glamac_render.c b/src/glamac/glamac_render.c index a39a670..619a6e0 100644 --- a/src/glamac/glamac_render.c +++ b/src/glamac/glamac_render.c @@ -1,18 +1,11 @@ /** - * glamac_render.c - source file dealing with the rendering of GlaMaC using SDL2. - * - * Copyright (C) 2025 https://optics-design.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * See the COPYING file for the full license text. + * glamac_render.c - source file dealing with the rendering of GlaMaC using SDL3. */ #include #include #include +#include +#include #include "glamac_render.h" #include "glass_data.h" @@ -33,7 +26,7 @@ typedef struct { static CachedText textCache[MAX_TEXT_CACHE] = {0}; static i32 cacheCount = 0; -// Function to draw text using SDL_ttf with caching for improved performance +// Function to draw text using SDL3_ttf with caching for improved performance void draw_text(SDL_Renderer *renderer, TTF_Font *font, const char *text, i32 x, i32 y, SDL_Color color) { // Check if we already have this text cached for (i32 i = 0; i < cacheCount; i++) { @@ -48,29 +41,29 @@ void draw_text(SDL_Renderer *renderer, TTF_Font *font, const char *text, i32 x, entry->color.a == color.a) { // Use the cached texture - SDL_Rect rect = {x, y, entry->width, entry->height}; - SDL_RenderCopy(renderer, entry->texture, NULL, &rect); + SDL_FRect rect = {(f32)x, (f32)y, (f32)entry->width, (f32)entry->height}; + SDL_RenderTexture(renderer, entry->texture, NULL, &rect); return; } } // Text not in cache, create a new texture - SDL_Surface *surface = TTF_RenderText_Blended(font, text, color); + SDL_Surface *surface = TTF_RenderText_Blended(font, text, 0, color); if (!surface) { - printf("TTF_RenderText_Blended failed: %s\n", TTF_GetError()); + printf("TTF_RenderText_Blended failed: %s\n", SDL_GetError()); return; } SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface); if (!texture) { printf("SDL_CreateTextureFromSurface failed: %s\n", SDL_GetError()); - SDL_FreeSurface(surface); + SDL_DestroySurface(surface); return; } // Draw the text - SDL_Rect rect = {x, y, surface->w, surface->h}; - SDL_RenderCopy(renderer, texture, NULL, &rect); + SDL_FRect rect = {(f32)x, (f32)y, (f32)surface->w, (f32)surface->h}; + SDL_RenderTexture(renderer, texture, NULL, &rect); // Add to cache if there is space if (cacheCount < MAX_TEXT_CACHE) { @@ -90,21 +83,11 @@ void draw_text(SDL_Renderer *renderer, TTF_Font *font, const char *text, i32 x, SDL_DestroyTexture(texture); } - SDL_FreeSurface(surface); + SDL_DestroySurface(surface); } -// Clear the text cache - should be called on shutdown -void clear_text_cache(void) { - for (i32 i = 0; i < cacheCount; i++) { - if (textCache[i].texture) { - SDL_DestroyTexture(textCache[i].texture); - textCache[i].texture = NULL; - } - } - cacheCount = 0; -} -// Function to draw a filled circle using SDL2's primitive functions +// Function to draw a filled circle using SDL3's primitive functions void draw_filled_circle(SDL_Renderer *renderer, i32 centerX, i32 centerY, i32 radius) { // Draw a filled circle using a series of horizontal lines // This is significantly faster than the pixel-by-pixel approach @@ -113,10 +96,10 @@ void draw_filled_circle(SDL_Renderer *renderer, i32 centerX, i32 centerY, i32 ra i32 x_width = (i32)sqrtf((float)(radius * radius - y * y)); // Draw a horizontal line from left to right edge of the circle - SDL_RenderDrawLine( + SDL_RenderLine( renderer, - centerX - x_width, centerY + y, - centerX + x_width, centerY + y + (f32)(centerX - x_width), (f32)(centerY + y), + (f32)(centerX + x_width), (f32)(centerY + y) ); } } @@ -130,12 +113,12 @@ void draw_axes(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *titleFont, cons // X-axis SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderDrawLine(renderer, padding, view->windowHeight - padding, - view->windowWidth - padding, view->windowHeight - padding); + SDL_RenderLine(renderer, (f32)padding, (f32)(view->windowHeight - padding), + (f32)(view->windowWidth - padding), (f32)(view->windowHeight - padding)); // Y-axis - SDL_RenderDrawLine(renderer, padding, padding, - padding, view->windowHeight - padding); + SDL_RenderLine(renderer, (f32)padding, (f32)padding, + (f32)padding, (f32)(view->windowHeight - padding)); // Calculate visible range based on current view f32 visibleMinAbbe, visibleMaxAbbe, visibleMinRI, visibleMaxRI; @@ -148,7 +131,8 @@ void draw_axes(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *titleFont, cons f32 value = visibleMaxAbbe - i * (visibleMaxAbbe - visibleMinAbbe) / 5; i32 x = padding + i * (view->windowWidth - 2 * padding) / 5; - SDL_RenderDrawLine(renderer, x, view->windowHeight - padding, x, view->windowHeight - padding + 5); + SDL_RenderLine(renderer, (f32)x, (f32)(view->windowHeight - padding), + (f32)x, (f32)(view->windowHeight - padding + 5)); sprintf(label, "%.1f", value); draw_text(renderer, font, label, x - 15, view->windowHeight - padding + 10, black); } @@ -158,7 +142,7 @@ void draw_axes(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *titleFont, cons f32 value = visibleMinRI + i * (visibleMaxRI - visibleMinRI) / 5; i32 y = view->windowHeight - padding - i * (view->windowHeight - 2 * padding) / 5; - SDL_RenderDrawLine(renderer, padding - 5, y, padding, y); + SDL_RenderLine(renderer, (f32)(padding - 5), (f32)y, (f32)padding, (f32)y); sprintf(label, "%.3f", value); draw_text(renderer, font, label, padding - 50, y - 10, black); } @@ -178,6 +162,7 @@ void draw_axes(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *titleFont, cons // Draw the closing parenthesis draw_text(renderer, titleFont, ")", padding + 141, padding - 35, black); } + // Function to draw a grid based on visible data range void draw_grid(SDL_Renderer *renderer, const ViewState* view) { const i32 padding = (i32)(view->windowWidth * PADDING_PERCENT); @@ -208,7 +193,8 @@ void draw_grid(SDL_Renderer *renderer, const ViewState* view) { data_to_screen_coords(x, visibleMinRI, view, &screenX, &screenY); if (screenX >= padding && screenX <= view->windowWidth - padding) { - SDL_RenderDrawLine(renderer, screenX, padding, screenX, view->windowHeight - padding); + SDL_RenderLine(renderer, (f32)screenX, (f32)padding, + (f32)screenX, (f32)(view->windowHeight - padding)); } } @@ -218,7 +204,8 @@ void draw_grid(SDL_Renderer *renderer, const ViewState* view) { data_to_screen_coords(visibleMinAbbe, y, view, &screenX, &screenY); if (screenY >= padding && screenY <= view->windowHeight - padding) { - SDL_RenderDrawLine(renderer, padding, screenY, view->windowWidth - padding, screenY); + SDL_RenderLine(renderer, (f32)padding, (f32)screenY, + (f32)(view->windowWidth - padding), (f32)screenY); } } } @@ -289,14 +276,14 @@ void draw_glass_properties(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *tit } // Draw background with slight transparency - SDL_Rect windowRect = {windowX, windowY, windowWidth, windowHeight}; + SDL_FRect windowRect = {(f32)windowX, (f32)windowY, (f32)windowWidth, (f32)windowHeight}; SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(renderer, 245, 245, 245, 235); SDL_RenderFillRect(renderer, &windowRect); // Draw border SDL_SetRenderDrawColor(renderer, 40, 40, 40, 255); - SDL_RenderDrawRect(renderer, &windowRect); + SDL_RenderRect(renderer, &windowRect); // Draw glass name as title SDL_Color darkBlue = {0, 0, 120, 255}; @@ -326,14 +313,14 @@ void draw_help_window(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *titleFon i32 x = (view->windowWidth - width) / 2; i32 y = (view->windowHeight - height) / 2; - SDL_Rect helpRect = {x, y, width, height}; + SDL_FRect helpRect = {(f32)x, (f32)y, (f32)width, (f32)height}; SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(renderer, 245, 245, 245, 230); SDL_RenderFillRect(renderer, &helpRect); // Draw border SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderDrawRect(renderer, &helpRect); + SDL_RenderRect(renderer, &helpRect); // Draw help title SDL_Color black = {0, 0, 0, 255}; @@ -390,7 +377,7 @@ void render(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *titleFont, TTF_Fon } // Add a small hint about help in the corner - draw_text(renderer, labelFont, "Press g? for help", 10, 0.975*view->windowHeight, black); + draw_text(renderer, labelFont, "Press g? for help", 10, (i32)(0.975*view->windowHeight), black); // Draw help window if toggled if (view->showHelp) { @@ -403,27 +390,104 @@ void render(SDL_Renderer *renderer, TTF_Font *font, TTF_Font *titleFont, TTF_Fon // Font management +// Helper function to try loading a font with fallbacks +static TTF_Font* try_load_font_from_paths(const char** fontNames, i32 numFonts, i32 size) { + TTF_Font* font = NULL; + + // Try all font paths + for (i32 i = 0; i < numFonts; i++) { + font = TTF_OpenFont(fontNames[i], size); + if (font) { + printf("Successfully loaded font: %s (size %d)\n", fontNames[i], size); + return font; + } + } + + // If all specific paths fail, try some generic system approaches + #ifndef _WIN32 + // Try to find any sans-serif font using common naming patterns + const char* genericFonts[] = { + "/usr/share/fonts/truetype/droid/DroidSans.ttf", + "/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf", + "/usr/share/fonts/TTF/DroidSans.ttf", + "/usr/share/fonts/noto/NotoSans-Regular.ttf", + "/usr/share/fonts/google-noto/NotoSans-Regular.ttf", + }; + + const i32 numGeneric = sizeof(genericFonts) / sizeof(genericFonts[0]); + for (i32 i = 0; i < numGeneric; i++) { + font = TTF_OpenFont(genericFonts[i], size); + if (font) { + printf("Successfully loaded generic font: %s (size %d)\n", genericFonts[i], size); + return font; + } + } + #endif + + return NULL; +} + // Load all required fonts b32 load_fonts(FontSet *fonts) { - fonts->regular = TTF_OpenFont("C:\\Windows\\Fonts\\arial.ttf", 14); + // Common font names to try, in order of preference + const char* fontNames[] = { + #ifdef _WIN32 + "C:\\Windows\\Fonts\\arial.ttf", + "C:\\Windows\\Fonts\\tahoma.ttf", + "C:\\Windows\\Fonts\\verdana.ttf", + "C:\\Windows\\Fonts\\calibri.ttf", + #else + // Ubuntu/Debian paths + "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", + "/usr/share/fonts/truetype/freefont/FreeSans.ttf", + // Arch Linux paths + "/usr/share/fonts/TTF/DejaVuSans.ttf", + "/usr/share/fonts/TTF/LiberationSans-Regular.ttf", + "/usr/share/fonts/gnu-free/FreeSans.ttf", + // Fedora/CentOS paths + "/usr/share/fonts/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/liberation/LiberationSans-Regular.ttf", + // OpenSUSE paths + "/usr/share/fonts/truetype/DejaVuSans.ttf", + // Alternative common locations + "/usr/share/fonts/TTF/arial.ttf", + "/usr/share/fonts/truetype/msttcorefonts/arial.ttf", + "/System/Library/Fonts/Arial.ttf", // macOS + // Try local fonts directory + "./fonts/DejaVuSans.ttf", + "./DejaVuSans.ttf", + #endif + }; + + const i32 numFonts = sizeof(fontNames) / sizeof(fontNames[0]); + i32 fontSizes[] = {14, 18, 12}; // regular, title, label + + // Load regular font + fonts->regular = try_load_font_from_paths(fontNames, numFonts, fontSizes[0]); if (!fonts->regular) { - printf("Failed to load regular font! TTF_Error: %s\n", TTF_GetError()); + printf("Failed to load any regular font!\n"); + printf("SDL_Error: %s\n", SDL_GetError()); + #ifndef _WIN32 + printf("Suggestion: Install fonts with: sudo apt install fonts-dejavu-core fonts-liberation (Ubuntu/Debian)\n"); + printf(" sudo pacman -S ttf-dejavu ttf-liberation (Arch)\n"); + printf(" sudo dnf install dejavu-sans-fonts liberation-fonts (Fedora)\n"); + #endif return 0; } - fonts->title = TTF_OpenFont("C:\\Windows\\Fonts\\arial.ttf", 18); + // Load title font (try larger size first, fallback to regular font) + fonts->title = try_load_font_from_paths(fontNames, numFonts, fontSizes[1]); if (!fonts->title) { - printf("Failed to load title font! TTF_Error: %s\n", TTF_GetError()); - TTF_CloseFont(fonts->regular); - return 0; + printf("Warning: Could not load title font, using regular font\n"); + fonts->title = fonts->regular; // Use the same font } - fonts->label = TTF_OpenFont("C:\\Windows\\Fonts\\arial.ttf", 12); + // Load label font (try smaller size first, fallback to regular font) + fonts->label = try_load_font_from_paths(fontNames, numFonts, fontSizes[2]); if (!fonts->label) { - printf("Failed to load label font! TTF_Error: %s\n", TTF_GetError()); - TTF_CloseFont(fonts->title); - TTF_CloseFont(fonts->regular); - return 0; + printf("Warning: Could not load label font, using regular font\n"); + fonts->label = fonts->regular; // Use the same font } return 1; @@ -431,7 +495,19 @@ b32 load_fonts(FontSet *fonts) { // Free all fonts void free_fonts(FontSet *fonts) { + // Only close fonts that are different from regular font if (fonts->regular) TTF_CloseFont(fonts->regular); - if (fonts->title) TTF_CloseFont(fonts->title); - if (fonts->label) TTF_CloseFont(fonts->label); + if (fonts->title && fonts->title != fonts->regular) TTF_CloseFont(fonts->title); + if (fonts->label && fonts->label != fonts->regular) TTF_CloseFont(fonts->label); +} + +// Clear text cache +void clear_text_cache(void) { + for (i32 i = 0; i < cacheCount; i++) { + if (textCache[i].texture) { + SDL_DestroyTexture(textCache[i].texture); + textCache[i].texture = NULL; + } + } + cacheCount = 0; } diff --git a/src/glamac/glamac_view.c b/src/glamac/glamac_view.c index 3078ae8..22d6401 100644 --- a/src/glamac/glamac_view.c +++ b/src/glamac/glamac_view.c @@ -1,16 +1,8 @@ /** * glamac_view.c - Source file dealing with view states, filtering, zooming etc. of GlaMaC. - * - * Copyright (C) 2025 https://optics-design.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * See the COPYING file for the full license text. */ #include +#include #include "glamac_view.h" #include "glass_data.h" @@ -103,11 +95,12 @@ void handle_mouse_wheel_zoom(i32 wheelY, i32 mouseX, i32 mouseY, ViewState* view // Toggle fullscreen void toggle_fullscreen(SDL_Window* window) { - const u32 flags = SDL_GetWindowFlags(window); - if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { - SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + bool isFullscreen = SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN; + + if (!isFullscreen) { + SDL_SetWindowFullscreen(window, true); } else { - SDL_SetWindowFullscreen(window, 0); + SDL_SetWindowFullscreen(window, false); } } -- cgit v1.2.3