src/shader.c

Tue, 23 Jan 2024 21:34:12 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 23 Jan 2024 21:34:12 +0100
changeset 29
1d001eb694dc
parent 16
c5dde81b6fb2
child 40
6c438be1a1fd
permissions
-rw-r--r--

bring first scene graph to live

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * Copyright 2023 Mike Becker. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "ascension/shader.h"
#include "ascension/files.h"
#include "ascension/error.h"

#include <GL/glew.h>
#include <string.h>

AscShaderFont ASC_SHADER_FONT;


AscShader asc_shader_compile(unsigned int type,
                             char const *code,
                             int length) {
    GLuint id = glCreateShader(type);
    if (id == 0) {
        asc_error("glCreateShader failed");
        return (AscShader) {0};
    }

    GLint success;
    glShaderSource(id, 1, &code, &length);
    glCompileShader(id);
    glGetShaderiv(id, GL_COMPILE_STATUS, &success);
    if (success) {
        asc_dprintf("Shader %u compiled", id);
        return (AscShader) {id};
    } else {
        char *log = malloc(1024);
        glGetShaderInfoLog(id, 1024, NULL, log);
        glDeleteShader(id);
        asc_error(log);
        free(log);
        return (AscShader) {0};
    }
}

AscShader asc_shader_compilef(unsigned int type,
                              char const *filename) {
    asc_file code = asc_file_mmap_rdonly(filename);
    if (code.ptr == NULL) {
        asc_error("Mapping shader file into memory failed");
        return (AscShader) {0};
    }
    AscShader ret = asc_shader_compile(type, code.ptr, code.length);
    asc_file_unmap(code);
    return ret;
}

AscShaderProgram asc_shader_link(AscShader vertex,
                                 AscShader fragment) {
    if (vertex.id == 0 || fragment.id == 0) {
        asc_dprintf("Skip linking shader program - shaders have not been loaded correctly.");
        return (AscShaderProgram) {0};
    }

    GLint success;
    GLint id = glCreateProgram();
    if (id <= 0) {
        asc_error("glCreateProgram failed");
        return (AscShaderProgram) {0};
    }
    glAttachShader(id, vertex.id);
    glAttachShader(id, fragment.id);
    glLinkProgram(id);
    glGetProgramiv(id, GL_LINK_STATUS, &success);
    glDetachShader(id, vertex.id);
    glDetachShader(id, fragment.id);
    if (success) {
        asc_dprintf("Shader Program %u linked (vtf: %u, frag: %u)", id, vertex.id, fragment.id);
        AscShaderProgram prog;
        prog.id = id;
        prog.model = glGetUniformLocation(id, "model");
        prog.view = glGetUniformLocation(id, "view");
        prog.projection = glGetUniformLocation(id, "projection");
        return prog;
    } else {
        char *log = malloc(1024);
        glGetProgramInfoLog(id, 1024, NULL, log);
        glDeleteShader(id);
        asc_error(log);
        free(log);
        return (AscShaderProgram) {0};
    }
}

void asc_shader_destroy(AscShader shader) {
    if (shader.id > 0) {
        asc_dprintf("Delete Shader %u", shader.id);
        glDeleteShader(shader.id);
    }
    shader.id = 0;
}

void asc_shader_program_destroy(AscShaderProgram program) {
    if (program.id > 0) {
        asc_dprintf("Delete Shader Program %u", program.id);
        glDeleteProgram(program.id);
    }
    program.id = 0;
}

static AscShaderProgram asc_shader_compile_link_discard(
        char const *vtxName, char const *fragName) {
    AscShader font_vtx = asc_shader_compilef(GL_VERTEX_SHADER, vtxName);
    AscShader font_frag = asc_shader_compilef(GL_FRAGMENT_SHADER, fragName);
    AscShaderProgram prog = asc_shader_link(font_vtx, font_frag);
    asc_shader_destroy(font_vtx);
    asc_shader_destroy(font_frag);
    return prog;
}

void asc_shader_initialize_predefined(void) {
    ASC_SHADER_FONT.base = asc_shader_compile_link_discard("shader/font_vtx.glsl", "shader/font_frag.glsl");
    ASC_SHADER_FONT.surface = glGetUniformLocation(ASC_SHADER_FONT.base.id, "surface");
}

void asc_shader_destroy_predefined(void) {
    asc_shader_program_destroy(ASC_SHADER_FONT.base);
}

mercurial