This commit is contained in:
Josh Holtrop 2024-01-14 20:24:47 -05:00
parent 8d44370067
commit f6cfbcc406
9 changed files with 402 additions and 1 deletions

View File

@ -8,6 +8,7 @@ env "app" do |env|
"libs/bindbc-common/source", "libs/bindbc-common/source",
"libs/bindbc-sdl/source", "libs/bindbc-sdl/source",
"libs/glad", "libs/glad",
"libs/gltk",
] ]
sources = dirs.reduce([]) do |result, dir| sources = dirs.reduce([]) do |result, dir|
result + glob("#{dir}/**/*.{d,c}") result + glob("#{dir}/**/*.{d,c}")

33
libs/gltk/gltk/array.d Normal file
View File

@ -0,0 +1,33 @@
module gltk.array;
import gl;
class Array
{
private GLuint m_id;
this()
{
m_id = 0u;
glGenVertexArrays(1, &m_id);
if (m_id == 0u)
{
throw new Exception("Failed to allocate an OpenGL array");
}
}
~this()
{
glDeleteVertexArrays(1, &m_id);
}
void bind()
{
glBindVertexArray(m_id);
}
@property GLuint id()
{
return m_id;
}
}

48
libs/gltk/gltk/buffer.d Normal file
View File

@ -0,0 +1,48 @@
module gltk.buffer;
import gl;
class Buffer
{
private GLuint m_id;
private GLenum m_target;
this(GLenum target)
{
m_id = 0u;
glGenBuffers(1, &m_id);
if (m_id == 0u)
{
throw new Exception("Failed to allocate an OpenGL buffer");
}
m_target = target;
}
~this()
{
glDeleteBuffers(1, &m_id);
}
void bind()
{
glBindBuffer(m_target, m_id);
}
@property GLuint id()
{
return m_id;
}
void set_buffer_data(GLenum usage, const void * ptr, size_t size)
{
bind();
glBufferData(m_target, size, ptr, usage);
}
void set_buffer_data(T)(GLenum usage, T[] arr)
{
bind();
glBufferData(m_target, arr.length * arr[0].sizeof, arr.ptr, usage);
}
}

7
libs/gltk/gltk/package.d Normal file
View File

@ -0,0 +1,7 @@
module gltk;
public import gltk.array;
public import gltk.buffer;
public import gltk.program;
public import gltk.shader;
public import gltk.texture;

182
libs/gltk/gltk/program.d Normal file
View File

@ -0,0 +1,182 @@
module gltk.program;
import gltk.shader;
import std.string;
import gl;
class Program(uniforms...)
{
/* The number of template parameters must be a multiple of 2. */
static assert((uniforms.length % 2) == 0);
private GLuint m_id;
static foreach (i, v; uniforms)
{
static if ((i % 2) == 0)
{
mixin("private GLint m_uniform_" ~ v ~ ";");
}
}
this(Args...)(Args args)
{
m_id = glCreateProgram();
if (m_id == 0u)
{
throw new Exception("Failed to allocate an OpenGL program");
}
static if (args.length > 0u)
{
build(args);
}
}
~this()
{
glDeleteProgram(m_id);
}
void attach_shader(Shader shader) const
{
glAttachShader(m_id, shader.id);
}
void bind_attrib_location(string name, uint index) const
{
glBindAttribLocation(m_id, index, name.toStringz());
}
void link()
{
glLinkProgram(m_id);
GLint link_status;
glGetProgramiv(m_id, GL_LINK_STATUS, &link_status);
if (link_status != GL_TRUE)
{
string message = "Failed to link program";
GLint log_length = 0;
glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
char[] log = new char[log_length];
glGetProgramInfoLog(m_id, log_length, &log_length, log.ptr);
message ~= "\n";
message ~= log;
message ~= "\n";
}
throw new Exception(message);
}
static foreach(i, v; uniforms)
{
static if ((i % 2) == 0)
{
mixin("m_uniform_" ~ v ~ " = glGetUniformLocation(m_id, \"" ~ v ~ "\");");
}
}
}
GLint get_uniform_location(string uniform_name) const
{
return glGetUniformLocation(m_id, uniform_name.toStringz());
}
void get_uniform_locations(Args...)(string uniform_name, GLint * uniform_location, Args args) const
{
*uniform_location = get_uniform_location(uniform_name);
static if (args.length > 0u)
{
get_uniform_locations(args);
}
}
@property GLuint id() const
{
return m_id;
}
void use() const
{
glUseProgram(m_id);
}
private static string uniform_param_decl_list(string spec)
{
int count = spec[0] - '0';
string type;
if (spec[1] == 'i')
{
type = "GLint";
}
else if (spec[1..2] == "ui")
{
type = "GLuint";
}
else if (spec[1] == 'f')
{
type = "GLfloat";
}
assert(type != "");
if (spec[$ - 1] == 'v')
{
return "uint count, const " ~ type ~ " * v";
}
else
{
string[] decls;
for (int i = 0; i < count; i++)
{
decls ~= type ~ " v" ~ cast(char)('0' + i);
}
return decls.join(", ");
}
}
private static string uniform_param_list(string spec)
{
int count = spec[0] - '0';
if (spec[$ - 1] == 'v')
{
return "count, v";
}
else
{
string[] vees;
for (int i = 0; i < count; i++)
{
vees ~= "v" ~ cast(char)('0' + i);
}
return vees.join(", ");
}
}
static foreach (i, v; uniforms)
{
static if ((i % 2) == 0)
{
mixin("void set_" ~ v ~ "(" ~ uniform_param_decl_list(uniforms[i + 1]) ~ ")" ~
"{" ~
" glUniform" ~ uniforms[i + 1] ~ "(m_uniform_" ~ v ~ ", " ~ uniform_param_list(uniforms[i + 1]) ~ ");" ~
"}");
}
}
private void build(Args...)(Shader s, Args args)
{
attach_shader(s);
build(args);
}
private void build(Args...)(string attrib_name, uint index, Args args)
{
bind_attrib_location(attrib_name, index);
build(args);
}
private void build()
{
link();
}
}

81
libs/gltk/gltk/shader.d Normal file
View File

@ -0,0 +1,81 @@
module gltk.shader;
import gl;
static import std.file;
class Shader
{
private GLuint m_id;
private GLenum m_shader_type;
this(GLenum shader_type)
{
m_shader_type = shader_type;
m_id = glCreateShader(shader_type);
if (m_id == 0u)
{
throw new Exception("Failed to allocate an OpenGL shader");
}
}
~this()
{
glDeleteShader(m_id);
}
void set_source(const char * source, int length = -1)
{
GLint status;
GLint gllength = length;
glShaderSource(m_id, 1, &source, &gllength);
glCompileShader(m_id);
glGetShaderiv(m_id, GL_COMPILE_STATUS, &status);
if (status == GL_TRUE)
{
return;
}
string message = "Error compiling ";
switch (m_shader_type)
{
case GL_VERTEX_SHADER:
message ~= "vertex";
break;
case GL_FRAGMENT_SHADER:
message ~= "fragment";
break;
default:
message ~= "unknown";
break;
}
message ~= " shader";
GLint log_length;
glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
char[] log = new char[log_length];
glGetShaderInfoLog(m_id, log_length, &log_length, log.ptr);
message ~= "\nShader Log:\n";
message ~= log;
message ~= "\n";
}
glDeleteShader(m_id);
throw new Exception(message);
}
void set_source_from_file(string filename)
{
const(char)[] file_data = cast(const(char)[])std.file.read(filename);
set_source(file_data.ptr, cast(int)file_data.length);
}
@property GLuint id()
{
return m_id;
}
}

45
libs/gltk/gltk/texture.d Normal file
View File

@ -0,0 +1,45 @@
module gltk.texture;
import gl;
class Texture
{
private GLuint m_id;
this()
{
m_id = 0u;
glGenTextures(1, &m_id);
if (m_id == 0u)
{
throw new Exception("Failed to allocate an OpenGL texture");
}
}
~this()
{
glDeleteTextures(1, &m_id);
}
void bind(GLenum target) const
{
glBindTexture(target, m_id);
}
@property GLuint id()
{
return m_id;
}
static uint next_power_of_2(uint n)
{
n--;
n |= n >> 1u;
n |= n >> 2u;
n |= n >> 4u;
n |= n >> 8u;
n |= n >> 16u;
n++;
return n;
}
};

View File

@ -1,7 +1,8 @@
import std.stdio; import std.stdio;
import sdl; import sdl;
import glad.gl.all; import gl;
import glad.gl.loader; import glad.gl.loader;
import gltk;
enum int WIDTH = 800; enum int WIDTH = 800;
enum int HEIGHT = 600; enum int HEIGHT = 600;

3
src/gl.d Normal file
View File

@ -0,0 +1,3 @@
module gl;
public import glad.gl.all;