Merges thirdparty modules into this repo.

This commit is contained in:
2021-04-21 00:00:00 +00:00
parent acb898ad9b
commit 7802ad1211
45 changed files with 2826 additions and 12 deletions

1
thirdparty/gl4d vendored

Submodule thirdparty/gl4d deleted from 33883a68a9

8
thirdparty/gl4d/.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
/.bin
/.dub
/dub.selections.json
/docs
/docs.json
*.swp

13
thirdparty/gl4d/dub.json vendored Normal file
View File

@@ -0,0 +1,13 @@
{
"name": "gl4d",
"license": "MIT",
"targetType": "library",
"targetPath": ".bin",
"dependencies": {
"bindbc-opengl": "~>0.9.0",
"gl3n": "~>1.3.1"
},
"versions": ["GL_33"]
}

164
thirdparty/gl4d/src/gl4d/Buffer.d vendored Normal file
View File

@@ -0,0 +1,164 @@
/// License: MIT
module gl4d.Buffer;
import std.conv,
std.typecons;
import gl4d.gl,
gl4d.math,
gl4d.GLObject;
///
alias ArrayBuffer = Buffer!GL_ARRAY_BUFFER;
/// RefCounted version of ArrayBuffer.
alias ArrayBufferRef = BufferRef!GL_ARRAY_BUFFER;
///
alias ArrayBufferAllocator = BufferAllocator!GL_ARRAY_BUFFER;
///
alias ArrayBufferOverwriter = BufferOverwriter!GL_ARRAY_BUFFER;
///
alias ElementArrayBuffer = Buffer!GL_ELEMENT_ARRAY_BUFFER;
/// RefCounted version of ElementArrayBuffer.
alias ElementArrayBufferRef = BufferRef!GL_ELEMENT_ARRAY_BUFFER;
///
alias ElementArrayBufferAllocator = BufferAllocator!GL_ELEMENT_ARRAY_BUFFER;
///
alias ElementArrayBufferOverwriter = BufferOverwriter!GL_ELEMENT_ARRAY_BUFFER;
///
alias UniformBuffer = Buffer!GL_UNIFORM_BUFFER;
/// RefCounted version of UniformBuffer.
alias UniformBufferRef = BufferRef!GL_UNIFORM_BUFFER;
///
alias UniformBufferAllocator = BufferAllocator!GL_UNIFORM_BUFFER;
///
alias UniformBufferOverwriter = BufferOverwriter!GL_UNIFORM_BUFFER;
/// RefCounted version of Buffer.
template BufferRef(GLenum target) {
alias BufferRef = RefCounted!(Buffer!target);
}
/// A wrapper type for OpenGL buffer.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct Buffer(GLenum target_) {
mixin GLObject!(
(x, y) => gl.GenBuffers(x, y),
(x) => gl.BindBuffer(target_, x),
(x) => gl.DeleteTextures(1, x)
);
public:
///
enum target = target_;
/// Binds this buffer to be written by transform feedbacks.
static if (target_ == GL_ARRAY_BUFFER)
void BindForTransformFeedback(int index) {
assert(!empty);
gl.BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, index.to!GLuint, id);
}
/// Binds this buffer to the uniform block.
static if (target_ == GL_UNIFORM_BUFFER)
void BindForUniformBlock(int index) {
assert(!empty);
gl.BindBufferBase(GL_UNIFORM_BUFFER, index.to!GLuint, id);
}
}
/// An allocator for buffers.
struct BufferAllocator(GLenum target) {
public:
///
size_t size;
///
const(void)* data;
///
GLenum usage = GL_STATIC_DRAW;
/// Allocates the buffer with parameters this has.
///
/// Binds the buffer automatically.
void Allocate(ref BufferRef!target buffer)
in {
assert(!buffer.empty);
assert(size > 0);
}
do {
buffer.Bind();
gl.BufferData(target, size.to!GLsizeiptr, data, usage);
}
}
/// An overwriter for buffers.
struct BufferOverwriter(GLenum target) {
public:
///
size_t offset;
///
size_t size;
///
const(void)* data;
/// Overwrites the buffer with parameters this has.
///
/// The buffer will be bound automatically.
void Overwrite(ref BufferRef!target buffer)
in {
assert(!buffer.empty);
assert(offset >= 0);
assert(size > 0);
}
do {
buffer.Bind();
gl.BufferSubData(target, offset.to!GLintptr, size.to!GLsizeiptr, data);
}
}
/// Takes the buffer's data pointer.
///
/// T must be a BufferRef type.
///
/// The buffer will be bound automatically.
///
/// Escaping its scope, the pointer will be disabled automatically.
/// Returns: a voldemorte type which can behave as same as PtrT*
auto MapToRead(PtrT = void, T)(ref T buf) {
return buf.Map!(PtrT, T.target, GL_READ_ONLY);
}
/// ditto
auto MapToWrite(PtrT = void, T)(ref T buf) {
return buf.Map!(PtrT, T.target, GL_WRITE_ONLY);
}
/// ditto
auto MapToReadWrite(PtrT = void, T)(ref T buf) {
return buf.Map!(PtrT, T.target, GL_READ_WRITE);
}
private auto Map(PtrT, GLenum target, GLenum usage)(ref BufferRef!target buf) {
assert(!buf.empty);
buf.Bind();
auto ptr = gl.MapBuffer(target, usage);
struct Mapper {
public:
@disable this(this);
~this() {
gl.UnmapBuffer(target);
}
static if (usage == GL_READ_ONLY) {
@property const(PtrT*) entity() const return { return cast(PtrT*) ptr; }
} else {
@property inout(PtrT*) entity() inout return { return cast(PtrT*) ptr; }
}
alias entity this;
}
return Mapper();
}

95
thirdparty/gl4d/src/gl4d/Framebuffer.d vendored Normal file
View File

@@ -0,0 +1,95 @@
/// License: MIT
module gl4d.Framebuffer;
import std.conv,
std.exception,
std.typecons,
std.variant;
import gl4d.gl,
gl4d.math,
gl4d.GLObject,
gl4d.Renderbuffer,
gl4d.Texture;
/// RefCounted version of OpenGL framebuffer.
alias FramebufferRef = RefCounted!Framebuffer;
/// A variant type of types which can be framebuffers' attachments.
alias FramebufferAttachment = Algebraic!(
Texture2DRef,
TextureRectRef,
RenderbufferRef
);
/// A wrapper type for OpenGL framebuffer.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct Framebuffer {
mixin GLObject!(
(x, y) => gl.GenFramebuffers(x, y),
(x) => gl.BindFramebuffer(GL_FRAMEBUFFER, x),
(x) => gl.DeleteFramebuffers(1, x)
);
public:
~this() {
// Forces unrefering all buffers.
foreach (key; attachments_.keys) {
attachments_[key] = FramebufferAttachment.init;
}
}
/// Binds this framebuffer to be read.
void BindToRead() {
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, id);
}
/// Binds this framebuffer to be written.
void BindToWrite() {
gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, id);
}
/// Validates this framebuffer.
///
/// This framebuffer must be bound to be written.
void Validate() {
const status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
(status == GL_FRAMEBUFFER_COMPLETE).
enforce("The framebuffer validation failed.");
}
private:
FramebufferAttachment[GLenum] attachments_;
}
/// Attaches the buffer as the attachment to the framebuffer.
///
/// The framebuffer must be bound to be written.
@property void attachment(GLenum type)(
ref FramebufferRef fb, ref RenderbufferRef buf) {
assert(!fb.empty);
assert(!buf.empty);
fb.attachments_[type] = buf;
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, type, GL_RENDERBUFFER, buf.id);
}
/// ditto
@property void attachment(GLenum type, int miplvl = 0, GLenum target)(
ref FramebufferRef fb, ref TextureRef!target buf)
if (target.IsSupported2DTextureTarget) {
assert(!fb.empty);
assert(!buf.empty);
fb.attachments_[type] = buf;
gl.FramebufferTexture2D(GL_FRAMEBUFFER,
type, target, buf.id, miplvl.to!GLint);
}
/// Changes color attachments' order.
///
/// The framebuffer must be bound to be written.
@property void attachmentOrder(ref FramebufferRef fb, GLenum[] attachments) {
assert(!fb.empty);
gl.DrawBuffers(attachments.length.to!GLsizei, attachments.ptr);
}

56
thirdparty/gl4d/src/gl4d/GLObject.d vendored Normal file
View File

@@ -0,0 +1,56 @@
/// License: MIT
module gl4d.GLObject;
import gl4d.gl;
/// A template for OpenGL objects' wrapper types.
mixin template GLObject(alias generator, alias binder, alias deleter) {
import std.algorithm,
std.array,
std.typecons;
public:
@disable this(this);
/// Creates a single object.
static RefCounted!This Create() {
GLuint id;
generator(1, &id);
return RefCounted!This(id);
}
/// Creates multiple objects.
static RefCounted!This[] Create(int count) {
assert(count > 0);
auto id = new GLuint[count];
generator(count, id.ptr);
return id.map!(i => RefCounted!This(i)).array;
}
~this() {
if (!empty) deleter(&id);
}
static if (is(typeof(() => binder(0)))) {
/// Binds this object.
void Bind() {
assert(!empty);
binder(id);
}
/// Unbinds this object
void Unbind() {
assert(!empty);
binder(0);
}
}
///
@property bool empty() const {
return id == 0;
}
///
const GLuint id;
private:
alias This = typeof(this);
}

204
thirdparty/gl4d/src/gl4d/Program.d vendored Normal file
View File

@@ -0,0 +1,204 @@
/// License: MIT
module gl4d.Program;
import std.algorithm,
std.array,
std.conv,
std.exception,
std.string,
std.typecons;
import gl4d.gl,
gl4d.math,
gl4d.Shader;
/// Whether geometry shaders are available.
enum IsGeometryShaderAvailable = (glSupport >= GLSupport.gl40);
/// RefCounted version of OpenGL program.
alias ProgramRef = RefCounted!Program;
/// A wrapper type for OpenGL program.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct Program {
public:
@disable this(this);
///
this(GLuint id) {
this.id = id;
assert(!empty);
(Get!GL_LINK_STATUS == GL_TRUE).enforce(log);
}
~this() {
if (!empty) gl.DeleteProgram(id);
}
/// Makes this program current.
void Use() {
assert(!empty);
gl.UseProgram(id);
}
/// Makes this program incurrent.
void Unuse() {
assert(!empty);
gl.UseProgram(0);
}
/// Validates this program.
///
/// If it's failed, throws an exception with log.
void Validate() const {
gl.ValidateProgram(id);
(Get!GL_VALIDATE_STATUS == GL_TRUE).enforce(log);
}
/// This may takes too long time.
@property string log() const {
assert(!empty);
const len = Get!GL_INFO_LOG_LENGTH;
auto msg = new char[len];
gl.GetProgramInfoLog(id, len, null, msg.ptr);
return msg.to!string;
}
///
@property bool empty() const {
return id == 0;
}
///
const GLuint id;
private:
// Be carefully, this may take too long time.
GLint Get(GLenum param)() const {
GLint temp = void;
gl.GetProgramiv(id, param, &temp);
return temp;
}
VertexShaderRef vertex_;
static if (IsGeometryShaderAvailable)
GeometryShaderRef geometry_;
FragmentShaderRef fragment_;
}
/// A linker for OpenGL program.
struct ProgramLinker {
public:
///
VertexShaderRef vertex;
static if (IsGeometryShaderAvailable) {
///
GeometryShaderRef geometry;
///
int geometryOutputVertices = 1024;
///
GLenum geometryInputType = GL_POINTS;
///
GLenum geometryOutputType = GL_POINTS;
}
///
FragmentShaderRef fragment;
///
string[] feedbackVaryings;
///
bool feedbackInterleaved;
/// Creates new program with parameters this has.
ProgramRef Link()
in {
assert(!vertex.empty);
assert(!fragment.empty);
}
do {
const id = gl.CreateProgram();
gl.AttachShader(id, vertex.id);
scope(exit) vertex = vertex.init;
gl.AttachShader(id, fragment.id);
scope(exit) fragment = fragment.init;
static if (IsGeometryShaderAvailable) if (!geometry.empty) {
gl.AttachShader(id, geometry.id);
scope(exit) geometry = geometry.init;
static if (glSupport >= GLSupport.gl40) {
gl.ProgramParameteri(id, GL_GEOMETRY_VERTICES_OUT, geometryOutputVertices);
gl.ProgramParameteri(id, GL_GEOMETRY_INPUT_TYPE, geometryInputType);
gl.ProgramParameteri(id, GL_GEOMETRY_OUTPUT_TYPE, geometryOutputType);
}
}
if (feedbackVaryings.length > 0) {
const varys = feedbackVaryings.map!toStringz.array;
gl.TransformFeedbackVaryings(id,
feedbackVaryings.length.to!GLsizei, cast(char**) varys.ptr,
feedbackInterleaved? GL_INTERLEAVED_ATTRIBS: GL_SEPARATE_ATTRIBS);
}
gl.LinkProgram(id);
return ProgramRef(id);
}
}
/// Resets uniform values with the data. (The program must be current.)
///
/// The program must be current.
@property void uniform(int loc, T)(ref ProgramRef program, T data) {
assert(!program.empty);
static if (is(T == int)) {
gl.Uniform1i(loc, data);
} else static if (is(T == vec2i)) {
gl.Uniform2i(loc, data.x, data.y);
} else static if (is(T == vec3i)) {
gl.Uniform3i(loc, data.x, data.y, data.z);
} else static if (is(T == vec4i)) {
gl.Uniform4i(loc, data.x, data.y, data.z, data.w);
} else static if (is(T == float)) {
gl.Uniform1f(loc, data);
} else static if (is(T == vec2)) {
gl.Uniform2f(loc, data.x, data.y);
} else static if (is(T == vec3)) {
gl.Uniform3f(loc, data.x, data.y, data.z);
} else static if (is(T == vec4)) {
gl.Uniform4f(loc, data.x, data.y, data.z, data.w);
} else static if (is(T == mat2)) {
gl.UniformMatrix2fv(loc, 1, true, &data[0][0]);
} else static if (is(T == mat3)) {
gl.UniformMatrix3fv(loc, 1, true, &data[0][0]);
} else static if (is(T == mat4)) {
gl.UniformMatrix4fv(loc, 1, true, &data[0][0]);
} else {
static assert(false);
}
}
// Tests for the above template.
static assert(is(typeof((ref ProgramRef program) => program.uniform!0 = 0)));
static assert(is(typeof((ref ProgramRef program) => program.uniform!1 = vec4())));
static assert(is(typeof((ref ProgramRef program) => program.uniform!2 = mat4())));
/// Numbers uniform blocks of the names.
void NumberUniformBlocks(string[int] names)(ref ProgramRef program) {
assert(!program.empty);
GLuint ubi = void;
static foreach (i, name; names) {
ubi = gl.GetUniformBlockIndex(program.id, name.toStringz);
gl.UniformBlockBinding(program.id, ubi, i.to!GLuint);
}
}

46
thirdparty/gl4d/src/gl4d/Renderbuffer.d vendored Normal file
View File

@@ -0,0 +1,46 @@
/// License: MIT
module gl4d.Renderbuffer;
import std.conv,
std.typecons;
import gl4d.gl,
gl4d.math,
gl4d.GLObject;
/// RefCounted version of OpenGL renderbuffer.
alias RenderbufferRef = RefCounted!Renderbuffer;
/// A wrapper type for OpenGL renderbuffer.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct Renderbuffer {
mixin GLObject!(
(x, y) => gl.GenRenderbuffers(x, y),
(x) => gl.BindRenderbuffer(GL_RENDERBUFFER, x),
(x) => gl.DeleteRenderbuffers(1, x)
);
}
/// An allocator for OpenGL renderbuffers.
struct RenderbufferAllocator {
public:
///
GLenum format;
///
vec2i size;
/// Allocates the renderbuffer's storage with parameters this has.
///
/// The renderbuffer will be bound automatically.
void Allocate(ref RenderbufferRef rb)
in {
assert(!rb.empty);
}
do {
rb.Bind();
gl.RenderbufferStorage(GL_RENDERBUFFER,
format, size.x.to!GLsizei, size.y.to!GLsizei);
}
}

57
thirdparty/gl4d/src/gl4d/Sampler.d vendored Normal file
View File

@@ -0,0 +1,57 @@
/// License: MIT
module gl4d.Sampler;
import std.conv,
std.typecons;
import gl4d.gl,
gl4d.GLObject;
/// RefCounted version of Sampler.
alias SamplerRef = RefCounted!Sampler;
/// A wrapper type for OpenGL sampler.
struct Sampler {
mixin GLObject!(
(x, y) => gl.GenSamplers(x, y),
void,
(x) => gl.DeleteSamplers(1, x)
);
public:
/// Binds to the texture unit index.
void Bind(int index) {
assert(!empty);
gl.BindSampler(index.to!GLuint, id);
}
}
/// A configurer for OpenGL sampler.
struct SamplerConfigurer {
public:
///
GLenum wrapS = GL_CLAMP_TO_EDGE;
///
GLenum wrapT = GL_CLAMP_TO_EDGE;
///
GLenum wrapR = GL_CLAMP_TO_EDGE;
///
GLenum filterMin = GL_NEAREST;
///
GLenum filterMag = GL_NEAREST;
/// Configures the sampler with parameters this has.
void Configure(ref SamplerRef sampler)
in {
assert(!sampler.empty);
}
do {
gl.SamplerParameteri(sampler.id, GL_TEXTURE_WRAP_S, wrapS);
gl.SamplerParameteri(sampler.id, GL_TEXTURE_WRAP_T, wrapT);
gl.SamplerParameteri(sampler.id, GL_TEXTURE_WRAP_R, wrapR);
gl.SamplerParameteri(sampler.id, GL_TEXTURE_MIN_FILTER, filterMin);
gl.SamplerParameteri(sampler.id, GL_TEXTURE_MAG_FILTER, filterMag);
}
}

99
thirdparty/gl4d/src/gl4d/Shader.d vendored Normal file
View File

@@ -0,0 +1,99 @@
/// License: MIT
module gl4d.Shader;
import std.conv,
std.exception,
std.string,
std.typecons;
import gl4d.gl;
/// A wrapper type for OpenGL vertex shader.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct VertexShader {
mixin Shader!GL_VERTEX_SHADER;
}
/// RefCounted version of VertexShader.
alias VertexShaderRef = RefCounted!VertexShader;
/// A wrapper type for OpenGL geometry shader.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct GeometryShader {
mixin Shader!GL_GEOMETRY_SHADER;
}
/// RefCounted version of GeometryShader.
alias GeometryShaderRef = RefCounted!GeometryShader;
/// A wrapper type for OpenGL fragment shader.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct FragmentShader {
mixin Shader!GL_FRAGMENT_SHADER;
}
/// RefCounted version of FragmentShader.
alias FragmentShaderRef = RefCounted!FragmentShader;
/// A body of shader structures which cannot be refered from other modules.
private mixin template Shader(GLenum type) {
public:
@disable this(this);
/// Creates new shader from the source with the type.
static RefCounted!This Compile(string src) {
const id = gl.CreateShader(type);
const srcptr = src.toStringz;
gl.ShaderSource(id, 1, &srcptr, null);
gl.CompileShader(id);
return RefCounted!This(id);
}
///
this(GLuint id) {
this.id = id;
assert(!empty);
(Get!GL_COMPILE_STATUS == GL_TRUE).enforce(log);
}
~this() {
if (!empty) gl.DeleteShader(id);
}
/// This may takes too long time.
@property string log() const {
assert(!empty);
const len = Get!GL_INFO_LOG_LENGTH;
if (len == 0) return null;
auto msg = new char[len];
gl.GetShaderInfoLog(id, len, null, msg.ptr);
return msg.to!string;
}
///
@property bool empty() const {
return id == 0;
}
///
const GLuint id;
private:
alias This = typeof(this);
// Be carefully, this may take too long time.
GLint Get(GLenum param)() const {
assert(!empty);
GLint temp = void;
gl.GetShaderiv(id, param, &temp);
return temp;
}
}

146
thirdparty/gl4d/src/gl4d/Texture.d vendored Normal file
View File

@@ -0,0 +1,146 @@
/// License: MIT
module gl4d.Texture;
import std.conv,
std.typecons;
import gl4d.gl,
gl4d.math,
gl4d.GLObject;
///
alias Texture2D = Texture!GL_TEXTURE_2D;
/// RefCounted version of Texture2D.
alias Texture2DRef = TextureRef!GL_TEXTURE_2D;
///
alias Texture2DAllocator = TextureAllocator!GL_TEXTURE_2D;
///
alias Texture2DOverwriter = TextureOverwriter!GL_TEXTURE_2D;
///
alias TextureRect = Texture!GL_TEXTURE_RECTANGLE;
/// RefCounted version of TextureRect.
alias TextureRectRef = TextureRef!GL_TEXTURE_RECTANGLE;
///
alias TextureRectAllocator = TextureAllocator!GL_TEXTURE_RECTANGLE;
///
alias TextureRectOverwriter = TextureOverwriter!GL_TEXTURE_RECTANGLE;
/// RefCounted version of Texture.
template TextureRef(GLenum target) {
alias TextureRef = RefCounted!(Texture!target);
}
/// A wrapper type for OpenGL texture.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct Texture(GLenum target_) {
mixin GLObject!(
(x, y) => gl.GenTextures(x, y),
(x) => gl.BindTexture(target_, x),
(x) => gl.DeleteTextures(1, x)
);
public:
///
enum target = target_;
/// Binds this texture to the texture unit.
///
/// This texture will be bound.
void BindToUnit(GLenum unit) {
assert(!empty);
gl.ActiveTexture(unit);
Bind();
}
/// Generates mipmaps of this texture.
///
/// This texture must be bound.
void GenerateMipmap() {
assert(!empty);
gl.GenerateMipmap(target_);
}
}
/// An allocator for 2D textures.
struct TextureAllocator(GLenum target)
if (target.IsSupported2DTextureTarget()) {
public:
///
int level;
///
GLint internalFormat;
///
vec2i size;
///
GLint border;
///
GLenum format;
///
GLenum type;
///
const(void)* data;
/// Allocates the texture with parameters this has.
///
/// The texture will be bound.
void Allocate(ref TextureRef!target texture)
in {
assert(!texture.empty);
assert(level >= 0);
assert(size.x > 0 && size.y > 0);
assert(border == 0);
}
do {
texture.Bind();
gl.TexImage2D(target, level.to!GLint, internalFormat,
size.x.to!GLsizei, size.y.to!GLsizei, border, format, type, data);
}
}
/// An overwriter for 2D textures.
struct TextureOverwriter(GLenum target)
if (target.IsSupported2DTextureTarget()) {
public:
///
int level;
///
vec2i offset;
///
vec2i size;
///
GLenum format;
///
GLenum type;
///
const(void)* data;
/// Overwrites the texture with parameters this has.
///
/// The texture will be bound.
void Overwrite(ref TextureRef!target texture)
in {
assert(!texture.empty);
assert(level >= 0);
assert(offset.x >= 0 && offset.y >= 0);
assert(size.x > 0 && size.y > 0);
}
do {
texture.Bind();
gl.TexImage2D(target, level.to!GLint,
offset.x.to!GLint, offset.y.to!GLint,
size.x.to!GLsizei, size.y.to!GLsizei,
format, type, data);
}
}
/// Returns: whether the target is supported 2d texture
@property bool IsSupported2DTextureTarget(GLenum target) {
return
target == GL_TEXTURE_2D ||
target == GL_TEXTURE_RECTANGLE;
}

84
thirdparty/gl4d/src/gl4d/VertexArray.d vendored Normal file
View File

@@ -0,0 +1,84 @@
/// License: MIT
module gl4d.VertexArray;
import std.conv,
std.typecons;
import gl4d.gl,
gl4d.math,
gl4d.Buffer,
gl4d.GLObject;
/// RefCounted version of VertexArray.
alias VertexArrayRef = RefCounted!VertexArray;
/// A wrapper type for OpenGL vertex array.
///
/// Usually this is wrapped by RefCounted.
/// When it's in default, empty() property returns true and id() property is invalid.
struct VertexArray {
mixin GLObject!(
(x, y) => gl.GenVertexArrays(x, y),
(x) => gl.BindVertexArray(x),
(x) => gl.DeleteVertexArrays(1, x)
);
public:
~this() {
// Forces unrefering all buffers.
foreach (key; attachments_.keys) {
attachments_[key] = ArrayBufferRef.init;
}
}
private:
ArrayBufferRef[int] attachments_;
}
/// An attacher between array buffers and vertex arrays.
struct VertexArrayAttacher {
public:
///
int index;
///
GLenum type;
///
int dimension;
///
bool normalized;
///
int stride;
///
int offset;
///
int divisor;
/// Attaches the buffer to the vertex array with parameters this has.
/// (The vertex array must be bound.)
void Attach(ref VertexArrayRef va, ref ArrayBufferRef buf)
in {
assert(!va.empty);
assert(!buf.empty);
assert(index >= 0);
assert(0 < dimension && dimension <= 4);
assert(stride >= 0);
assert(offset >= 0);
assert(divisor >= 0);
}
do {
va.attachments_[index] = buf;
buf.Bind();
const i = index.to!GLuint;
gl.EnableVertexAttribArray(i);
gl.VertexAttribPointer(
i, dimension.to!GLint,
type, normalized, stride.to!GLsizei,
cast(GLvoid*) offset.to!ptrdiff_t);
gl.VertexAttribDivisor(i, divisor.to!GLuint);
}
}

65
thirdparty/gl4d/src/gl4d/gl.d vendored Normal file
View File

@@ -0,0 +1,65 @@
/// License: MIT
module gl4d.gl;
import std.conv,
std.exception,
std.format;
public import bindbc.opengl;
/// This class is just for separating gl functions from the global namespace.
abstract class gl {
public:
/// This library requires this version.
enum RequiredVersion = GLSupport.gl33;
/// Applies current OpenGL context for gl4d features.
///
/// If the context version is not equal to RequiredVersion,
/// an exception will be thrown.
static void ApplyContext() {
const loaded = loadOpenGL();
(RequiredVersion == loaded).
enforce("Loading OpenGL failed with GLSupport %s. (expected %s)".
format(loaded, RequiredVersion));
}
/// Calls OpenGL function with error handling.
static auto opDispatch(string func,
string file = __FILE__, size_t line = __LINE__, Args...)(Args args) {
scope (exit) {
auto err = glGetError();
(err == GL_NO_ERROR).
enforce(GetErrorString(err), file, line);
}
return mixin("gl"~func~"(args)");
}
private:
static string GetErrorString(GLenum err) {
switch (err) {
case GL_NO_ERROR:
return "GL_NO_ERROR "~
"(No error has been recorded."~
" The value of this symbolic constant is guaranteed to be 0.)";
case GL_INVALID_ENUM:
return "GL_INVALID_ENUM "~
"(An unacceptable value is specified for an enumerated argument."~
" The offending command is ignored and has no other side effect than to set the error flag.)";
case GL_INVALID_VALUE:
return "GL_INVALID_VALUE "~
"(A numeric argument is out of range. "~
"The offending command is ignored and has no other side effect than to set the error flag.)";
case GL_INVALID_OPERATION:
return "GL_INVALID_OPERATION "~
"(The specified operation is not allowed in the current state."~
" The offending command is ignored and has no other side effect than to set the error flag.)";
case GL_OUT_OF_MEMORY:
return "GL_OUT_OF_MEMORY "~
"(There is not enough memory left to execute the command."~
" The state of the GL is undefined, except for the state of the error flags, after this error is recorded.";
default:
return err.to!string;
}
}
}

6
thirdparty/gl4d/src/gl4d/math.d vendored Normal file
View File

@@ -0,0 +1,6 @@
/// License: MIT
module gl4d.math;
public {
import gl3n.linalg;
}

17
thirdparty/gl4d/src/gl4d/package.d vendored Normal file
View File

@@ -0,0 +1,17 @@
/// License: MIT
module gl4d;
public {
import gl4d.gl,
gl4d.math,
gl4d.util;
import gl4d.Buffer,
gl4d.Framebuffer,
gl4d.Program,
gl4d.Renderbuffer,
gl4d.Sampler,
gl4d.Shader,
gl4d.Texture,
gl4d.VertexArray;
}

View File

@@ -0,0 +1,50 @@
/// License: MIT
module gl4d.util.ModelMatrixFactory;
import gl3n.linalg;
///
struct ModelMatrixFactory(size_t dim) if (dim == 3 || dim == 4) {
public:
///
alias mat = Matrix!(float, dim, dim);
///
mat Create() const {
auto m = mat.identity;
static if (dim == 3) {
m.scale(scale.x, scale.y, 1);
m.rotatex(rotation.x);
m.rotatey(rotation.y);
m.rotatez(rotation.z);
m.translate(translation.x, translation.y, 1);
} else static if (dim == 4) {
m.scale(scale.x, scale.y, scale.z);
m.rotatex(rotation.x);
m.rotatey(rotation.y);
m.rotatez(rotation.z);
m.translate(translation.x, translation.y, translation.z);
}
return m;
}
static if (dim == 3) {
///
vec2 scale = vec2(1, 1);
///
vec3 rotation = vec3(0, 0, 0);
///
vec2 translation = vec2(0, 0);
} else static if (dim == 4) {
///
vec3 scale = vec3(1, 1, 1);
///
vec3 rotation = vec3(0, 0, 0);
///
vec3 translation = vec3(0, 0, 0);
}
}
static assert(__traits(compiles, ModelMatrixFactory!3));
static assert(__traits(compiles, ModelMatrixFactory!4));

View File

@@ -0,0 +1,22 @@
/// License: MIT
module gl4d.util.ProjectionMatrixFactory;
import gl3n.linalg;
///
struct ProjectionMatrixFactory {
public:
///
mat4 Create() const {
return mat4.perspective(aspect, 1, fov, near, far);
}
///
float aspect = 1;
///
float fov = 60;
///
float far = 100;
///
float near = 0.1;
}

View File

@@ -0,0 +1,20 @@
/// License: MIT
module gl4d.util.ViewMatrixFactory;
import gl3n.linalg;
///
struct ViewMatrixFactory {
public:
///
mat4 Create() const {
return mat4.look_at(pos, target, up);
}
///
vec3 pos = vec3(0, -1, 0);
///
vec3 target = vec3(0, 0, 0);
///
vec3 up = vec3(0, 1, 0);
}

View File

@@ -0,0 +1,8 @@
/// License: MIT
module gl4d.util;
public {
import gl4d.util.ModelMatrixFactory,
gl4d.util.ProjectionMatrixFactory,
gl4d.util.ViewMatrixFactory;
}

201
thirdparty/gl4d/test.d vendored Normal file
View File

@@ -0,0 +1,201 @@
#!/usr/bin/env dub
/+ dub.json:
{
"name": "test",
"dependencies": {
"bindbc-sdl": "~>0.11.0",
"gl4d": {"path": "."}
},
"versions": ["SDL_209"]
}
+/
import std;
import bindbc.sdl;
import gl4d;
enum ShaderHeader = "#version 330 core
#extension GL_ARB_explicit_uniform_location : enable";
enum VertexShaderSource = ShaderHeader~q{
layout(location=0) in vec4 pos;
layout(std140) uniform uniformblock {
float value;
} ub;
out vec2 uv;
out float feedback_value;
void main() {
uv = pos.xy;
gl_Position = pos * ub.value;
feedback_value = length(pos.xy);
}
};
enum FragmentShaderSource = ShaderHeader~q{
in vec2 uv;
layout(std140) uniform uniformblock {
float value;
} ub;
layout(location = 1) uniform sampler2D tex;
out vec4 color;
void main() {
color = texture(tex, uv);
}
};
void Test() {
auto tex = Texture2D.Create();
{
auto data = new ubyte[16*16];
data[] = ubyte.max;
Texture2DAllocator allocator;
allocator.internalFormat = GL_RGBA8;
allocator.size = vec2i(16, 16);
allocator.format = GL_RED;
allocator.type = GL_UNSIGNED_BYTE;
allocator.data = data.ptr;
allocator.Allocate(tex);
}
auto sampler = Sampler.Create();
{
SamplerConfigurer configurer;
configurer.filterMin = GL_NEAREST;
configurer.filterMag = GL_NEAREST;
configurer.Configure(sampler);
}
auto buf = ArrayBuffer.Create();
{
ArrayBufferAllocator allocator;
allocator.size = float.sizeof*4*3;
allocator.data = null;
allocator.usage = GL_STATIC_DRAW;
allocator.Allocate(buf);
auto ptr = buf.MapToWrite!float();
ptr[0] = 0;
ptr[1] = 0;
ptr[2] = 0;
ptr[3] = 1;
ptr[4] = 0.5;
ptr[5] = 0.5;
ptr[6] = 0;
ptr[7] = 1;
ptr[8] = 0.5;
ptr[9] = 0;
ptr[10] = 0;
ptr[11] = 1;
}
auto buf_tf = ArrayBuffer.Create();
{
ArrayBufferAllocator allocator;
allocator.size = float.sizeof * 3;
allocator.data = null;
allocator.usage = GL_STREAM_COPY;
allocator.Allocate(buf_tf);
}
auto ub = UniformBuffer.Create();
{
const data = 1.5f;
UniformBufferAllocator allocator;
allocator.size = float.sizeof;
allocator.data = &data;
allocator.usage = GL_STATIC_DRAW;
allocator.Allocate(ub);
}
ProgramRef program;
{
ProgramLinker linker;
linker.vertex = VertexShader.Compile(VertexShaderSource);
linker.fragment = FragmentShader.Compile(FragmentShaderSource);
linker.feedbackVaryings = ["feedback_value"];
linker.feedbackInterleaved = true;
program = linker.Link();
program.NumberUniformBlocks!(["uniformblock"]);
program.Use();
program.uniform!1 = 0;
}
auto va = VertexArray.Create();
{
va.Bind();
VertexArrayAttacher attacher;
attacher.index = 0;
attacher.type = GL_FLOAT;
attacher.dimension = 4;
attacher.Attach(va, buf);
}
auto rb = Renderbuffer.Create();
{
RenderbufferAllocator allocator;
allocator.format = GL_RGB8;
allocator.size = vec2i(32, 32);
allocator.Allocate(rb);
}
auto fb = Framebuffer.Create();
{
fb.Bind();
fb.attachment!GL_COLOR_ATTACHMENT0 = rb;
fb.attachmentOrder = [GL_COLOR_ATTACHMENT0];
fb.Validate();
fb.Unbind();
}
buf_tf.BindForTransformFeedback(0);
ub.BindForUniformBlock(0);
tex.BindToUnit(GL_TEXTURE0);
sampler.Bind(0);
gl.BeginTransformFeedback(GL_POINTS);
gl.PointSize(5);
gl.DrawArrays(GL_POINTS, 0, 3);
gl.EndTransformFeedback();
{
auto ptr = buf_tf.MapToRead!float();
static foreach (i; 0..3) ptr[i].writeln;
}
}
void main() {
(loadSDL() == sdlSupport).
enforce("SDL library loading failed.");
SDL_Init(SDL_INIT_VIDEO);
scope(exit) SDL_Quit();
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
auto win = SDL_CreateWindow("gl4d testing", 0, 0, 100, 100, SDL_WINDOW_OPENGL).
enforce("Failed creating OpenGL window.");
scope(exit) SDL_DestroyWindow(win);
auto context = SDL_GL_CreateContext(win);
SDL_GL_MakeCurrent(win, context);
gl.ApplyContext();
Test();
SDL_GL_SwapWindow(win);
SDL_Delay(3000);
}