221 lines
4.9 KiB
C
221 lines
4.9 KiB
C
|
#include "gl_util.h"
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <assert.h>
|
||
|
#include <gio/gio.h>
|
||
|
#include <gmodule.h>
|
||
|
#include <gdk/gdk.h>
|
||
|
|
||
|
void gl_util_check_error(const char *file, int line)
|
||
|
{
|
||
|
GLenum error = glGetError();
|
||
|
|
||
|
const char *name;
|
||
|
switch (error) {
|
||
|
case GL_NO_ERROR:
|
||
|
return; // no error
|
||
|
case GL_INVALID_ENUM:
|
||
|
name = "GL_INVALID_ENUM";
|
||
|
break;
|
||
|
case GL_INVALID_VALUE:
|
||
|
name = "GL_INVALID_VALUE";
|
||
|
break;
|
||
|
case GL_INVALID_OPERATION:
|
||
|
name = "GL_INVALID_OPERATION";
|
||
|
break;
|
||
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||
|
name = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
||
|
break;
|
||
|
case GL_OUT_OF_MEMORY:
|
||
|
name = "GL_OUT_OF_MEMORY";
|
||
|
break;
|
||
|
default:
|
||
|
name = "UNKNOWN ERROR!";
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
printf("GL error at %s:%d - %s\n", file, line, name);
|
||
|
|
||
|
// raise(SIGTRAP);
|
||
|
}
|
||
|
|
||
|
GLuint
|
||
|
gl_util_load_shader(const char *resource, GLenum type, const char **extra_sources, size_t num_extra)
|
||
|
{
|
||
|
GdkGLContext *context = gdk_gl_context_get_current();
|
||
|
assert(context);
|
||
|
|
||
|
GLuint shader = glCreateShader(type);
|
||
|
if (shader == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
GBytes *bytes = g_resources_lookup_data(resource, 0, NULL);
|
||
|
if (!bytes) {
|
||
|
printf("Failed to load shader resource %s\n", resource);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Build #define for OpenGL context information
|
||
|
gboolean is_es = gdk_gl_context_get_use_es(context);
|
||
|
int major, minor;
|
||
|
gdk_gl_context_get_version(context, &major, &minor);
|
||
|
char context_info_buf[128];
|
||
|
snprintf(context_info_buf, 128, "#define %s\n#define GL_%d\n#define GL_%d_%d\n", is_es ? "GL_ES" : "GL_NO_ES", major, major, minor);
|
||
|
|
||
|
gsize glib_size = 0;
|
||
|
const GLchar *source = g_bytes_get_data(bytes, &glib_size);
|
||
|
if (glib_size == 0 || glib_size > INT_MAX) {
|
||
|
printf("Invalid size for resource\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const GLchar **sources = malloc((num_extra + 1) * sizeof(GLchar *));
|
||
|
GLint *sizes = malloc((num_extra + 1) * sizeof(GLint));
|
||
|
|
||
|
for (size_t i = 0; i < num_extra; ++i) {
|
||
|
sources[i] = extra_sources[i];
|
||
|
sizes[i] = -1;
|
||
|
}
|
||
|
sources[num_extra] = source;
|
||
|
sizes[num_extra] = glib_size;
|
||
|
|
||
|
glShaderSource(shader, num_extra + 1, sources, sizes);
|
||
|
glCompileShader(shader);
|
||
|
check_gl();
|
||
|
|
||
|
free(sources);
|
||
|
free(sizes);
|
||
|
|
||
|
g_bytes_unref(bytes);
|
||
|
|
||
|
// Check compile status
|
||
|
GLint success;
|
||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||
|
if (success == GL_FALSE) {
|
||
|
printf("Shader compilation failed for %s\n", resource);
|
||
|
|
||
|
glDeleteShader(shader);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
GLint log_length;
|
||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
|
||
|
if (log_length > 0) {
|
||
|
char *log = malloc(sizeof(char) * log_length);
|
||
|
glGetShaderInfoLog(shader, log_length - 1, &log_length, log);
|
||
|
|
||
|
printf("Shader %s log: %s\n", resource, log);
|
||
|
free(log);
|
||
|
|
||
|
glDeleteShader(shader);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return shader;
|
||
|
}
|
||
|
|
||
|
GLuint
|
||
|
gl_util_link_program(GLuint *shaders, size_t num_shaders)
|
||
|
{
|
||
|
GLuint program = glCreateProgram();
|
||
|
|
||
|
for (size_t i = 0; i < num_shaders; ++i) {
|
||
|
glAttachShader(program, shaders[i]);
|
||
|
}
|
||
|
|
||
|
glLinkProgram(program);
|
||
|
check_gl();
|
||
|
|
||
|
GLint success;
|
||
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||
|
if (success == GL_FALSE) {
|
||
|
printf("Program linking failed\n");
|
||
|
}
|
||
|
|
||
|
GLint log_length;
|
||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
|
||
|
if (log_length > 0) {
|
||
|
char *log = malloc(sizeof(char) * log_length);
|
||
|
glGetProgramInfoLog(program, log_length - 1, &log_length, log);
|
||
|
|
||
|
printf("Program log: %s\n", log);
|
||
|
free(log);
|
||
|
}
|
||
|
check_gl();
|
||
|
|
||
|
return program;
|
||
|
}
|
||
|
|
||
|
static const GLfloat quad_data[] = {
|
||
|
// Vertices
|
||
|
-1, -1,
|
||
|
1, -1,
|
||
|
-1, 1,
|
||
|
1, 1,
|
||
|
// Texcoords
|
||
|
0, 0,
|
||
|
1, 0,
|
||
|
0, 1,
|
||
|
1, 1,
|
||
|
};
|
||
|
|
||
|
GLuint gl_util_new_quad()
|
||
|
{
|
||
|
GdkGLContext *context = gdk_gl_context_get_current();
|
||
|
assert(context);
|
||
|
|
||
|
if (gdk_gl_context_get_use_es(context)) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
GLuint buffer;
|
||
|
glGenBuffers(1, &buffer);
|
||
|
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);
|
||
|
check_gl();
|
||
|
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
|
check_gl();
|
||
|
|
||
|
return buffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gl_util_bind_quad(GLuint buffer)
|
||
|
{
|
||
|
GdkGLContext *context = gdk_gl_context_get_current();
|
||
|
assert(context);
|
||
|
|
||
|
if (gdk_gl_context_get_use_es(context)) {
|
||
|
glVertexAttribPointer(GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, 0, 0, quad_data);
|
||
|
check_gl();
|
||
|
glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE);
|
||
|
check_gl();
|
||
|
|
||
|
glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, 0, 0, quad_data + 8);
|
||
|
check_gl();
|
||
|
glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE);
|
||
|
check_gl();
|
||
|
} else {
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||
|
check_gl();
|
||
|
|
||
|
glVertexAttribPointer(GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||
|
glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE);
|
||
|
check_gl();
|
||
|
|
||
|
glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, (void*) (8 * sizeof(float)));
|
||
|
glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE);
|
||
|
check_gl();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gl_util_draw_quad(GLuint buffer)
|
||
|
{
|
||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||
|
check_gl();
|
||
|
}
|