#include "window/window.h" #include "aliases.h" #include "math/math_utils.h" #include "vector/vec.h" #include #include #include #include #include #include #include u32 index_from_coordinates(window_t *wnd, u32 x, u32 y); i32 denormalise(i32 value, u32 max, u32 abs_half); vec2i_t denormalised_coords(const window_t *wnd, i32 x, i32 y); void set_screen_pixel(window_t *wnd, u32 x, u32 y, colour_t colour); bool init_window(window_t *wnd, u32 width, u32 height, const char *title) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { printf("Failed to initialise SDL: %s\n", SDL_GetError()); return false; } if (width % 2 != 0) { ++width; } if (height % 2 != 0) { ++height; } wnd->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0); if (!(wnd->window)) { printf("Failed to create window: %s\n", SDL_GetError()); close_window(wnd); return false; } wnd->front_buffer = SDL_GetWindowSurface(wnd->window); if (!(wnd->front_buffer)) { printf("Failed to get front buffer: %s\n", SDL_GetError()); close_window(wnd); return false; } wnd->back_buffer = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_ABGR32); if (!(wnd->back_buffer)) { printf("Failed to create back buffer: %s\n", SDL_GetError()); close_window(wnd); return false; } wnd->width = width; wnd->height = height; wnd->half_width = width / 2; wnd->half_height = height / 2; wnd->title = title; return true; } void close_window(window_t *wnd) { if (wnd) { wnd->width = 0; wnd->height = 0; wnd->title = ""; if (wnd->window) { SDL_DestroyWindow(wnd->window); wnd->window = NULL; } if (wnd->back_buffer) { SDL_FreeSurface(wnd->back_buffer); wnd->back_buffer = NULL; } } SDL_Quit(); } void clear_window(window_t *wnd, colour_t colour) { SDL_LockSurface(wnd->back_buffer); u32 *pixels = (u32 *)(wnd->back_buffer->pixels); u32 count = wnd->back_buffer->w * wnd->back_buffer->h; for (u32 i = 0; i < count; ++i) { pixels[i] = colour.colour; } SDL_UnlockSurface(wnd->back_buffer); } void set_pixel(window_t *wnd, i32 x, i32 y, colour_t colour) { vec2i_t coords = denormalised_coords(wnd, x, y); if (coords.x < 0 || coords.y < 0) { return; } SDL_LockSurface(wnd->back_buffer); set_screen_pixel(wnd, (u32)(coords.x), (u32)(coords.y), colour); SDL_UnlockSurface(wnd->back_buffer); } void swap_buffers(window_t *wnd) { SDL_BlitSurface(wnd->back_buffer, NULL, wnd->front_buffer, NULL); SDL_UpdateWindowSurface(wnd->window); } u32 index_from_coordinates(window_t *wnd, u32 x, u32 y) { return y * wnd->width + x; } i32 denormalise(i32 value, u32 max, u32 abs_half) { if (max == 0) { return -1; } i32 normalised_min = -abs_half; i32 normalised_max = abs_half; i32 denormalised = (i32)(((value - normalised_min) * max) / (normalised_max - normalised_min)); if (denormalised < 0 || denormalised >= max) { return -1; } return denormalised; } vec2i_t denormalised_coords(const window_t *wnd, i32 x, i32 y) { i32 screen_x = denormalise(x, wnd->width, wnd->half_width); i32 screen_y = denormalise(-y, wnd->height, wnd->half_height); return (vec2i_t){.x = screen_x, .y = screen_y}; } void set_screen_pixel(window_t *wnd, u32 x, u32 y, colour_t colour) { u32 index = index_from_coordinates(wnd, x, y); u32 *pixels = (u32 *)(wnd->back_buffer->pixels); pixels[index] = colour.colour; } vec3f_t window_to_viewport(window_t *wnd, i32 x, i32 y, vec3f_t viewport) { return (vec3f_t){ .x = x * viewport.x / wnd->width, .y = y * viewport.y / wnd->height, .z = viewport.z, }; } colour_t colour_add_colour(colour_t a, colour_t b) { f32 alpha = clamp((f32)(a.rgba.a + b.rgba.a), 0.0f, (f32)UINT8_MAX); return (colour_t){.rgba.r = a.rgba.r + b.rgba.r, .rgba.g = a.rgba.g + b.rgba.g, .rgba.b = a.rgba.b + b.rgba.b, .rgba.a = (u8)alpha}; } colour_t colour_mul(colour_t colour, f32 scalar) { f32 r = (f32)colour.rgba.r * scalar; r = clamp(r, 0.0f, (f32)UINT8_MAX); f32 g = (f32)colour.rgba.g * scalar; g = clamp(g, 0.0f, (f32)UINT8_MAX); f32 b = (f32)colour.rgba.b * scalar; b = clamp(b, 0.0f, (f32)UINT8_MAX); return (colour_t){.rgba.r = (u8)r, .rgba.g = (u8)g, .rgba.b = (u8)b, .rgba.a = colour.rgba.a}; }