138 lines
4.1 KiB
C
138 lines
4.1 KiB
C
//
|
|
// Created by william on 17/05/24.
|
|
//
|
|
|
|
#include <SDL.h>
|
|
#include "window.h"
|
|
#include "log.h"
|
|
#include "component.h"
|
|
|
|
// A sequential window ID
|
|
static int next_window_id = 1;
|
|
|
|
/**
|
|
* Easy declaration of commonly used component loop. The current component is in the 'component' variable.
|
|
* Put the loop's body between FOR_EACH_COMPONENT and END_FOR_EACH_COMPONENT.
|
|
*/
|
|
#define FOR_EACH_COMPONENT(window) \
|
|
Component *component; \
|
|
LinkedListCursor cursor = window_create_component_cursor(window, &component); \
|
|
while (component != NULL) {
|
|
|
|
#define END_FOR_EACH_COMPONENT \
|
|
component = get_next_component(&cursor); \
|
|
}
|
|
|
|
static inline LinkedListCursor window_create_component_cursor(Window *window, Component **first_component) {
|
|
LinkedListCursor cursor = linked_list_cursor_create(&window->components);
|
|
if (cursor.current != NULL) {
|
|
*first_component = cursor.current->data;
|
|
} else {
|
|
*first_component = NULL;
|
|
}
|
|
|
|
return cursor;
|
|
}
|
|
|
|
static inline Component *get_next_component(LinkedListCursor *cursor) {
|
|
if (!linked_list_cursor_has_next(cursor)) {
|
|
return NULL;
|
|
}
|
|
|
|
LinkedListNode *next_node = linked_list_cursor_next(cursor);
|
|
return next_node->data;
|
|
}
|
|
|
|
Window window_create(char *title, int width, int height, int scale) {
|
|
WindowSdlContext context;
|
|
|
|
int renderer_flags = SDL_RENDERER_ACCELERATED;
|
|
int window_flags = 0;
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
log_error("Couldn't initialize SDL: %s", SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
int actual_width = width * scale;
|
|
int actual_height = height * scale;
|
|
context.window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, actual_width,
|
|
actual_height, window_flags);
|
|
if (!context.window) {
|
|
log_error("Failed to open %d x %d SDL window: %s", actual_width, actual_height, SDL_GetError());
|
|
exit(-1);
|
|
}
|
|
|
|
context.renderer = SDL_CreateRenderer(context.window, -1, renderer_flags);
|
|
if (!context.renderer) {
|
|
log_error("Failed to create renderer: %s", SDL_GetError());
|
|
SDL_DestroyWindow(context.window);
|
|
exit(-1);
|
|
}
|
|
|
|
Window window;
|
|
window.id = next_window_id++;
|
|
window.width = width;
|
|
window.height = height;
|
|
window.scale = scale;
|
|
window.sdl_context = context;
|
|
window.components = linked_list_create(false);
|
|
|
|
return window;
|
|
}
|
|
|
|
SDL_Texture *window_create_texture(Window *window, int access) {
|
|
SDL_Renderer *renderer = window->sdl_context.renderer;
|
|
return SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, access, window->width, window->height);
|
|
}
|
|
|
|
void window_add_component(Window *window, Component *component) {
|
|
LinkedList *components = &window->components;
|
|
linked_list_add(components, component);
|
|
}
|
|
|
|
void window_render_components(Window *window) {
|
|
FOR_EACH_COMPONENT(window)
|
|
component->render(component->ref);
|
|
END_FOR_EACH_COMPONENT
|
|
}
|
|
|
|
void window_render_texture(Window *window, SDL_Texture *texture) {
|
|
SDL_Renderer *renderer = window->sdl_context.renderer;
|
|
SDL_RenderClear(renderer);
|
|
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
|
}
|
|
|
|
void window_present(Window *window) {
|
|
SDL_RenderPresent(window->sdl_context.renderer);
|
|
}
|
|
|
|
void window_destroy(Window *window) {
|
|
FOR_EACH_COMPONENT(window)
|
|
component->destroy(component->ref);
|
|
free(component);
|
|
END_FOR_EACH_COMPONENT
|
|
|
|
SDL_DestroyRenderer(window->sdl_context.renderer);
|
|
SDL_DestroyWindow(window->sdl_context.window);
|
|
}
|
|
|
|
void window_mouse_motion(Window *window, int x, int y) {
|
|
FOR_EACH_COMPONENT(window)
|
|
bool matching = component->mouse_motion(component->ref, x, y);
|
|
if (matching) {
|
|
// If a component has matched, we don't pass the event to the next ones
|
|
// This will prevent, for example, clicking on a UI element behind another one.
|
|
break;
|
|
}
|
|
END_FOR_EACH_COMPONENT
|
|
}
|
|
|
|
void window_mouse_click(Window *window) {
|
|
FOR_EACH_COMPONENT(window)
|
|
bool matching = component->mouse_click(component->ref);
|
|
if (matching) {
|
|
break;
|
|
}
|
|
END_FOR_EACH_COMPONENT
|
|
} |