universe@0: /* universe@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@0: * Copyright 2023 Mike Becker. All rights reserved. universe@0: * universe@0: * Redistribution and use in source and binary forms, with or without universe@0: * modification, are permitted provided that the following conditions are met: universe@0: * universe@0: * 1. Redistributions of source code must retain the above copyright universe@0: * notice, this list of conditions and the following disclaimer. universe@0: * universe@0: * 2. Redistributions in binary form must reproduce the above copyright universe@0: * notice, this list of conditions and the following disclaimer in the universe@0: * documentation and/or other materials provided with the distribution. universe@0: * universe@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@0: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@0: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@0: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@0: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@0: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@0: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@0: * POSSIBILITY OF SUCH DAMAGE. universe@0: */ universe@0: universe@6: #include "ascension/window.h" universe@7: #include "ascension/context.h" universe@7: #include "ascension/error.h" universe@9: #include "ascension/utils.h" universe@0: universe@6: #include universe@6: universe@0: void asc_window_settings_init_defaults(AscWindowSettings* settings) { universe@3: settings->dimensions.width = 800; universe@3: settings->dimensions.height = 600; universe@0: settings->fullscreen = 0; universe@44: settings->glsettings.depth_size = 24; universe@44: settings->glsettings.vsync = 1; universe@44: settings->glsettings.gl_major_version = 4; universe@44: settings->glsettings.gl_minor_version = 0; universe@0: settings->title = "Ascended Window"; universe@0: } universe@0: universe@7: AscWindow *asc_window_initialize(unsigned int index, AscWindowSettings const *settings) { universe@7: if (index >= ASC_MAX_WINDOWS) { universe@7: asc_error("Maximum number of windows exceeded."); universe@7: return NULL; universe@7: } universe@7: AscWindow *window = &asc_context.windows[index]; universe@7: if (window->id > 0) { universe@7: asc_error("Cannot create window - slot already occupied."); universe@47: asc_dprintf("Tried to create window with index %u twice", index); universe@7: return NULL; universe@7: } universe@47: if (window->ui != NULL) { universe@47: asc_dprintf("Window with index %u has a dangling UI pointer", index); universe@47: asc_scene_node_free(window->ui); universe@47: } universe@7: universe@0: Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; universe@0: flags |= settings->fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE; universe@0: universe@0: window->window = SDL_CreateWindow( universe@0: settings->title, universe@0: SDL_WINDOWPOS_CENTERED, universe@0: SDL_WINDOWPOS_CENTERED, universe@3: settings->dimensions.width, universe@3: settings->dimensions.height, universe@0: flags universe@0: ); universe@0: if (window->window == NULL) { universe@0: asc_error(SDL_GetError()); universe@7: return NULL; universe@0: } universe@0: universe@0: window->id = SDL_GetWindowID(window->window); universe@3: SDL_GetWindowSize(window->window, universe@3: &window->dimensions.width, universe@3: &window->dimensions.height universe@3: ); universe@37: window->resized = true; // count initial sizing as resize universe@0: universe@44: if (asc_gl_context_initialize(&window->glctx, window->window, &settings->glsettings)) { universe@47: window->ui = asc_scene_node_empty(); universe@44: asc_dprintf("Window %u initialized", window->id); universe@44: asc_context.active_window = window; universe@44: return window; universe@44: } else { universe@0: asc_dprintf("Creating GL context failed for window %u", window->id); universe@44: // cleanup on error universe@44: SDL_DestroyWindow(window->window); universe@44: window->window = NULL; universe@44: window->id = 0; universe@44: return NULL; universe@0: } universe@0: } universe@0: universe@7: void asc_window_destroy(AscWindow* window) { universe@7: // safeguard universe@7: if (window->id == 0) return; universe@7: universe@16: // this window cannot be active anymore universe@16: if (asc_context.active_window == window) { universe@16: asc_context.active_window = NULL; universe@16: } universe@16: universe@29: // destroy all scenes universe@47: asc_scene_node_free(window->ui); universe@47: window->ui = NULL; universe@29: universe@44: // release context related data universe@44: asc_gl_context_destroy(&window->glctx); universe@16: universe@44: // destroy window universe@0: if (window->window != NULL) { universe@0: SDL_DestroyWindow(window->window); universe@0: } universe@0: universe@16: // if another window was active, make the other context current again universe@16: if (asc_context.active_window != NULL) { universe@44: asc_gl_context_activate(&asc_context.active_window->glctx); universe@16: } universe@16: universe@0: // clean the data universe@0: asc_dprintf("Window %u and its OpenGL context destroyed.", window->id); universe@0: memset(window, 0, sizeof(AscWindow)); universe@0: } universe@0: universe@37: void asc_window_sync(AscWindow* window) { universe@44: AscWindow *active_window = asc_context.active_window; universe@16: if (window != active_window) { universe@16: asc_window_activate(window); universe@16: } universe@29: universe@47: // Clear the color buffer for the window frame universe@47: int window_width = window->dimensions.width; universe@47: int window_height = window->dimensions.height; universe@47: glViewport(0, 0, window_width, window_height); universe@47: glClear(GL_COLOR_BUFFER_BIT); universe@47: asc_recti viewport = {0, 0, window_width, window_height}; universe@47: universe@29: // Draw the UI universe@47: AscCamera ui_camera; universe@47: asc_camera_ortho(&ui_camera, viewport); universe@47: asc_scene_draw(window->ui, viewport, &ui_camera); universe@29: universe@29: // Swap Buffers universe@29: SDL_GL_SwapWindow(window->window); universe@29: universe@37: // Clear Flags universe@37: window->resized = false; universe@37: universe@16: if (window != active_window) { universe@16: asc_window_activate(active_window); universe@16: } universe@0: } universe@16: universe@44: void asc_window_activate(AscWindow *window) { universe@44: asc_gl_context_activate(&window->glctx); universe@34: asc_context.active_window = (AscWindow *)window; universe@16: }