universe@44: /* universe@44: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@44: * Copyright 2023 Mike Becker. All rights reserved. universe@44: * universe@44: * Redistribution and use in source and binary forms, with or without universe@44: * modification, are permitted provided that the following conditions are met: universe@44: * universe@44: * 1. Redistributions of source code must retain the above copyright universe@44: * notice, this list of conditions and the following disclaimer. universe@44: * universe@44: * 2. Redistributions in binary form must reproduce the above copyright universe@44: * notice, this list of conditions and the following disclaimer in the universe@44: * documentation and/or other materials provided with the distribution. universe@44: * universe@44: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@44: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@44: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@44: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@44: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@44: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@44: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@44: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@44: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@44: * POSSIBILITY OF SUCH DAMAGE. universe@44: */ universe@44: universe@44: #include "ascension/glcontext.h" universe@44: #include "ascension/error.h" universe@44: universe@44: #include universe@44: universe@44: #include universe@44: universe@44: static void asc_gl_debug_callback( universe@44: GLenum source, GLenum type, GLuint id, GLenum severity, universe@44: GLsizei length, const GLchar* message, universe@44: const void* userParam universe@44: ) { universe@44: cxmutstr buf = cx_asprintf( universe@44: "source = %d, id = %u, type = %d, severity= %d, message = %.*s", universe@44: source, id, type, severity, length, message); universe@44: if (type == GL_DEBUG_TYPE_ERROR) { universe@44: asc_error(buf.ptr); universe@44: } else { universe@44: asc_dprintf("GL debug: %.*s", (int)buf.length, buf.ptr); universe@44: } universe@44: cx_strfree(&buf); universe@44: } universe@44: universe@44: static void asc_shader_initialize_predefined(AscGLContext *ctx) { universe@44: AscShaderSprite *sprite = &ctx->shader.sprite; universe@44: sprite->base = asc_shader_easy_compile_and_link("shader/sprite_vtx.glsl", "shader/sprite_frag.glsl"); universe@44: sprite->depth = glGetUniformLocation(sprite->base.id, "depth"); universe@50: sprite->tex = glGetUniformLocation(sprite->base.id, "texture"); universe@44: } universe@44: universe@44: static void asc_shader_destroy_predefined(AscGLContext *ctx) { universe@44: asc_shader_program_destroy(ctx->shader.sprite.base); universe@44: } universe@44: universe@44: bool asc_gl_context_initialize( universe@44: AscGLContext *ctx, universe@44: SDL_Window *window, universe@44: AscGLContextSettings const *settings universe@44: ) { universe@44: SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); universe@44: SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, settings->gl_major_version); universe@44: SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, settings->gl_minor_version); universe@44: SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, settings->depth_size); universe@44: SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); universe@44: ctx->glctx = SDL_GL_CreateContext(window); universe@44: if (ctx->glctx == NULL) return false; universe@44: ctx->window = window; universe@44: universe@44: glewExperimental = GL_TRUE; universe@44: GLenum err = glewInit(); universe@44: if (err == GLEW_OK) { universe@44: SDL_GL_SetSwapInterval(settings->vsync); universe@44: universe@44: glClearColor(0.0f, 0.0f, 0.0f, 1.0f); universe@44: glEnable(GL_DEBUG_OUTPUT); universe@44: glDebugMessageCallback(asc_gl_debug_callback, NULL); universe@44: universe@44: if (!asc_primitives_init(&ctx->primitives)) { universe@44: asc_error("Creating primitive meshes failed"); universe@44: SDL_GL_DeleteContext(ctx->glctx); universe@44: return false; universe@44: } universe@44: universe@44: asc_shader_initialize_predefined(ctx); universe@44: universe@44: return true; universe@44: } else { universe@44: asc_error(glewGetErrorString(err)); universe@44: SDL_GL_DeleteContext(ctx->glctx); universe@44: return false; universe@44: } universe@44: } universe@44: universe@44: void asc_gl_context_destroy(AscGLContext *ctx) { universe@44: if (ctx->glctx == NULL) return; universe@44: SDL_GL_MakeCurrent(ctx->window, ctx->glctx); universe@44: universe@44: asc_shader_destroy_predefined(ctx); universe@44: asc_primitives_destroy(&ctx->primitives); universe@44: universe@44: // destroy the GL context and the window universe@44: SDL_GL_DeleteContext(ctx->glctx); universe@44: ctx->glctx = NULL; universe@44: }