mirror of
https://github.com/Karaka-Management/cOMS.git
synced 2026-01-11 03:08:41 +00:00
459 lines
13 KiB
C++
459 lines
13 KiB
C++
/**
|
|
* Jingga
|
|
*
|
|
* @copyright Jingga
|
|
* @license OMS License 2.0
|
|
* @version 1.0.0
|
|
* @link https://jingga.app
|
|
*/
|
|
#ifndef TOS_GPUAPI_OPENGL_SHADER_UTILS_H
|
|
#define TOS_GPUAPI_OPENGL_SHADER_UTILS_H
|
|
|
|
#include "../../stdlib/Types.h"
|
|
#include "../../memory/RingMemory.h"
|
|
#include "../../log/Log.h"
|
|
#include "../../object/Vertex.h"
|
|
#include "Shader.h"
|
|
#include "Opengl.h"
|
|
#include "../ShaderType.h"
|
|
#include "../GpuAttributeType.h"
|
|
|
|
struct OpenglVertexInputAttributeDescription {
|
|
uint32 location;
|
|
uint32 count;
|
|
int32 format;
|
|
int32 stride;
|
|
void* offset;
|
|
};
|
|
|
|
int32 shader_type_index(ShaderType type)
|
|
{
|
|
switch (type) {
|
|
case SHADER_TYPE_VERTEX:
|
|
return GL_VERTEX_SHADER;
|
|
case SHADER_TYPE_FRAGMENT:
|
|
return GL_FRAGMENT_SHADER;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
// Set value based on uniform location
|
|
inline
|
|
void shader_set_value(uint32 location, bool value)
|
|
{
|
|
glUniform1i(location, (int32) value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_value(uint32 location, int32 value)
|
|
{
|
|
glUniform1i(location, value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_value(uint32 location, f32 value)
|
|
{
|
|
glUniform1f(location, value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_v2(uint32 location, const f32* value)
|
|
{
|
|
glUniform2fv(location, 1, value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_v3(uint32 location, const f32* value)
|
|
{
|
|
glUniform3fv(location, 1, value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_v4(uint32 location, const f32* value)
|
|
{
|
|
glUniform4fv(location, 1, value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_m2(uint32 location, const f32* value)
|
|
{
|
|
glUniformMatrix2fv(location, 1, GL_FALSE, value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_m3(uint32 location, const f32* value)
|
|
{
|
|
glUniformMatrix3fv(location, 1, GL_FALSE, value);
|
|
}
|
|
|
|
inline
|
|
void shader_set_m4(uint32 location, const f32* value)
|
|
{
|
|
glUniformMatrix4fv(location, 1, GL_FALSE, value);
|
|
}
|
|
|
|
inline
|
|
uint32 shader_get_attrib_location(uint32 id, const char* name)
|
|
{
|
|
// By using this you can retreive the shader variable name at a point where and when you know it
|
|
// BUT set values later on in generalized functions without knowing the shader variable name
|
|
// Basically like pointers
|
|
return glGetAttribLocation(id, name);
|
|
}
|
|
|
|
inline
|
|
void shader_check_link_errors(uint32 id, char* log)
|
|
{
|
|
GLint success;
|
|
glGetProgramiv(id, GL_LINK_STATUS, &success);
|
|
if (!success) {
|
|
glGetProgramInfoLog(id, 1024, NULL, log);
|
|
}
|
|
}
|
|
|
|
inline
|
|
void shader_check_compile_errors(uint32 id, char* log)
|
|
{
|
|
GLint success;
|
|
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
|
|
if (!success) {
|
|
glGetShaderInfoLog(id, 1024, NULL, log);
|
|
}
|
|
}
|
|
|
|
int32 shader_program_optimize(const char* input, char* output)
|
|
{
|
|
const char* read_ptr = input;
|
|
char* write_ptr = output;
|
|
bool in_string = false;
|
|
|
|
while (*read_ptr) {
|
|
// Remove leading whitespace
|
|
while (*read_ptr == ' ' || *read_ptr == '\t' || is_eol(read_ptr)) {
|
|
++read_ptr;
|
|
}
|
|
|
|
if (write_ptr != output
|
|
&& *(write_ptr - 1) != '\n' && *(write_ptr - 1) != ';' && *(write_ptr - 1) != '{'
|
|
&& *(write_ptr - 1) != '('
|
|
&& *(write_ptr - 1) != ','
|
|
) {
|
|
*write_ptr++ = '\n';
|
|
}
|
|
|
|
// Handle single-line comments (//)
|
|
if (*read_ptr == '/' && *(read_ptr + 1) == '/' && !in_string) {
|
|
// Go to end of line
|
|
while (*read_ptr && *read_ptr != '\n') {
|
|
++read_ptr;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Handle multi-line comments (/* */)
|
|
if (*read_ptr == '/' && *(read_ptr + 1) == '*' && !in_string) {
|
|
// Go to end of comment
|
|
while (*read_ptr && (*read_ptr != '*' || *(read_ptr + 1) != '/')) {
|
|
++read_ptr;
|
|
}
|
|
|
|
if (*read_ptr == '*' && *(read_ptr + 1) == '/') {
|
|
read_ptr += 2;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Handle strings to avoid removing content within them
|
|
if (*read_ptr == '"') {
|
|
in_string = !in_string;
|
|
}
|
|
|
|
// Copy valid characters to write_ptr
|
|
while (*read_ptr && !is_eol(read_ptr) && *read_ptr != '"'
|
|
&& !(*read_ptr == '/' && (*(read_ptr + 1) == '/' || *(read_ptr + 1) == '*'))
|
|
) {
|
|
if (!in_string
|
|
&& (*read_ptr == '*' || *read_ptr == '/' || *read_ptr == '=' || *read_ptr == '+' || *read_ptr == '-' || *read_ptr == '%'
|
|
|| *read_ptr == '(' || *read_ptr == ')'
|
|
|| *read_ptr == '{' || *read_ptr == '}'
|
|
|| *read_ptr == ',' || *read_ptr == '?' || *read_ptr == ':' || *read_ptr == ';'
|
|
|| *read_ptr == '&' || *read_ptr == '|'
|
|
|| *read_ptr == '>' || *read_ptr == '<'
|
|
)
|
|
) {
|
|
if (is_whitespace(*(write_ptr - 1)) || *(write_ptr - 1) == '\n') {
|
|
--write_ptr;
|
|
}
|
|
|
|
*write_ptr++ = *read_ptr++;
|
|
|
|
if (*read_ptr && is_whitespace(*read_ptr)) {
|
|
++read_ptr;
|
|
}
|
|
} else {
|
|
*write_ptr++ = *read_ptr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*write_ptr = '\0';
|
|
|
|
// -1 to remove \0 from length, same as strlen
|
|
return (int32) (write_ptr - output);
|
|
}
|
|
|
|
GLuint shader_make(GLenum type, const char* source, RingMemory* ring)
|
|
{
|
|
GLuint shader = glCreateShader(type);
|
|
glShaderSource(shader, 1, (GLchar **) &source, NULL);
|
|
glCompileShader(shader);
|
|
|
|
GLint status;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
|
|
#if DEBUG || INTERNAL
|
|
if (status == GL_FALSE) {
|
|
GLint length;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
|
|
|
|
GLchar* info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar));
|
|
|
|
glGetShaderInfoLog(shader, length, NULL, info);
|
|
LOG_1(info);
|
|
|
|
ASSERT_SIMPLE(false);
|
|
}
|
|
#endif
|
|
|
|
return shader;
|
|
}
|
|
|
|
inline
|
|
int32 program_get_size(uint32 program)
|
|
{
|
|
int32 size;
|
|
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &size);
|
|
|
|
return size;
|
|
}
|
|
|
|
GLuint pipeline_make(
|
|
GLuint vertex_shader,
|
|
GLuint fragment_shader,
|
|
GLint geometry_shader,
|
|
RingMemory* ring
|
|
) {
|
|
GLuint program = glCreateProgram();
|
|
|
|
if (geometry_shader > -1) {
|
|
glAttachShader(program, geometry_shader);
|
|
}
|
|
|
|
glAttachShader(program, vertex_shader);
|
|
glAttachShader(program, fragment_shader);
|
|
glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
|
glLinkProgram(program);
|
|
|
|
GLint status;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
|
|
|
#if DEBUG || INTERNAL
|
|
if (status == GL_FALSE) {
|
|
GLint length;
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
|
|
|
|
GLchar *info = (GLchar *) ring_get_memory(ring, length * sizeof(GLchar));
|
|
|
|
glGetProgramInfoLog(program, length, NULL, info);
|
|
LOG_1(info);
|
|
|
|
ASSERT_SIMPLE(false);
|
|
}
|
|
#endif
|
|
|
|
// @question really?
|
|
if (geometry_shader > -1) {
|
|
glDetachShader(program, geometry_shader);
|
|
}
|
|
|
|
glDetachShader(program, vertex_shader);
|
|
glDetachShader(program, fragment_shader);
|
|
|
|
// @question really?
|
|
if (geometry_shader > -1) {
|
|
glDeleteShader(geometry_shader);
|
|
}
|
|
|
|
glDeleteShader(vertex_shader);
|
|
glDeleteShader(fragment_shader);
|
|
|
|
return program;
|
|
}
|
|
|
|
// @question Depending on how the different gpu apis work we may want to pass Shader* to have a uniform structure
|
|
inline
|
|
void pipeline_use(uint32 id)
|
|
{
|
|
glUseProgram(id);
|
|
}
|
|
|
|
inline
|
|
void gpuapi_attribute_setup(GpuAttributeType type, const OpenglVertexInputAttributeDescription* attr)
|
|
{
|
|
int32 length = gpuapi_attribute_count(type);
|
|
for (int32 i = 0; i < length; ++i) {
|
|
if (attr[i].format == GL_INT) {
|
|
glVertexAttribIPointer(attr[i].location, attr[i].count, attr[i].format, attr[i].stride, attr[i].offset);
|
|
} else {
|
|
glVertexAttribPointer(attr[i].location, attr[i].count, attr[i].format, false, attr[i].stride, attr[i].offset);
|
|
}
|
|
glEnableVertexAttribArray(attr[i].location);
|
|
}
|
|
}
|
|
|
|
constexpr
|
|
void gpuapi_attribute_info_create(GpuAttributeType type, OpenglVertexInputAttributeDescription* attr)
|
|
{
|
|
switch (type) {
|
|
case GPU_ATTRIBUTE_TYPE_VERTEX_3D: {
|
|
attr[0] = {
|
|
.location = 0,
|
|
.count = 3,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3D),
|
|
.offset = (void *) offsetof(Vertex3DTextureColor, position)
|
|
};
|
|
|
|
attr[1] = {
|
|
.location = 1,
|
|
.count = 3,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3D),
|
|
.offset = (void *) offsetof(Vertex3D, normal)
|
|
};
|
|
|
|
attr[2] = {
|
|
.location = 2,
|
|
.count = 2,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3D),
|
|
.offset = (void *) offsetof(Vertex3D, tex_coord)
|
|
};
|
|
|
|
attr[3] = {
|
|
.location = 3,
|
|
.count = 4,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3D),
|
|
.offset = (void *) offsetof(Vertex3D, color)
|
|
};
|
|
} return;
|
|
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_NORMAL: {
|
|
attr[0] = {
|
|
.location = 0,
|
|
.count = 3,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DNormal),
|
|
.offset = (void *) offsetof(Vertex3DNormal, position)
|
|
};
|
|
|
|
attr[1] = {
|
|
.location = 1,
|
|
.count = 3,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DNormal),
|
|
.offset = (void *) offsetof(Vertex3DNormal, normal)
|
|
};
|
|
} return;
|
|
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_COLOR: {
|
|
attr[0] = {
|
|
.location = 0,
|
|
.count = 3,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DColor),
|
|
.offset = (void *) offsetof(Vertex3DColor, position)
|
|
};
|
|
|
|
attr[1] = {
|
|
.location = 1,
|
|
.count = 2,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DColor),
|
|
.offset = (void *) offsetof(Vertex3DColor, color)
|
|
};
|
|
} return;
|
|
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_TEXTURE_COLOR: {
|
|
attr[0] = {
|
|
.location = 0,
|
|
.count = 3,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DTextureColor),
|
|
.offset = (void *) offsetof(Vertex3DTextureColor, position)
|
|
};
|
|
|
|
attr[1] = {
|
|
.location = 1,
|
|
.count = 2,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DTextureColor),
|
|
.offset = (void *) offsetof(Vertex3DTextureColor, texture_color)
|
|
};
|
|
} return;
|
|
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_SAMPLER_TEXTURE_COLOR: {
|
|
attr[0] = {
|
|
.location = 0,
|
|
.count = 3,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DSamplerTextureColor),
|
|
.offset = (void *) offsetof(Vertex3DSamplerTextureColor, position)
|
|
};
|
|
|
|
attr[1] = {
|
|
.location = 1,
|
|
.count = 1,
|
|
.format = GL_INT,
|
|
.stride = sizeof(Vertex3DSamplerTextureColor),
|
|
.offset = (void *) offsetof(Vertex3DSamplerTextureColor, sampler)
|
|
};
|
|
|
|
attr[2] = {
|
|
.location = 2,
|
|
.count = 2,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex3DSamplerTextureColor),
|
|
.offset = (void *) offsetof(Vertex3DSamplerTextureColor, texture_color)
|
|
};
|
|
} return;
|
|
case GPU_ATTRIBUTE_TYPE_VERTEX_2D_TEXTURE: {
|
|
attr[0] = {
|
|
.location = 0,
|
|
.count = 2,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex2DTexture),
|
|
.offset = (void *) offsetof(Vertex2DTexture, position)
|
|
};
|
|
|
|
attr[1] = {
|
|
.location = 1,
|
|
.count = 2,
|
|
.format = GL_FLOAT,
|
|
.stride = sizeof(Vertex2DTexture),
|
|
.offset = (void *) offsetof(Vertex2DTexture, tex_coord)
|
|
};
|
|
} return;
|
|
default:
|
|
UNREACHABLE();
|
|
};
|
|
}
|
|
|
|
void gpuapi_descriptor_set_layout_create(Shader* shader, const OpenglDescriptorSetLayoutBinding* bindings, int32 binding_length) {
|
|
for (int32 i = 0; i < binding_length; ++i) {
|
|
shader->descriptor_set_layout[i].binding = glGetUniformLocation(shader->id, bindings[i].name);
|
|
shader->descriptor_set_layout[i].name = bindings[i].name;
|
|
}
|
|
}
|
|
|
|
#endif |