1 /** 2 * Copyright: Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved 3 * Authors: $(Gabriel Gheorghe) 4 * License: $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007) 5 * Source: $(LINK2 https://github.com/GabyForceQ/LibertyEngine/blob/master/source/liberty/graphics/opengl/vertex.d, _vertex.d) 6 * Documentation: 7 * Coverage: 8 */ 9 module liberty.graphics.opengl.vertex; 10 version (__OpenGL__) : 11 import derelict.opengl; 12 import liberty.graphics.renderer; 13 import liberty.graphics.opengl.traits; 14 import std.string, std.typetuple, std.typecons, std.traits; 15 import liberty.math.vector; 16 import liberty.graphics.opengl.shader; 17 import liberty.graphics.video.vertex : VertexSpec; 18 /// Specify an attribute which has to be normalized. 19 struct Normalized; 20 /// Describe a Vertex structure. 21 /// You must instantiate it with a compile-time struct describing your vertex format. 22 final class GLVertexSpec(VERTEX) : VertexSpec!VERTEX { 23 private { 24 VertexAttribute[] _attributes; 25 } 26 /// Creates a vertex specification. 27 this(GLShaderProgram shader_program) { 28 alias TT = FieldTypeTuple!VERTEX; 29 foreach (member; __traits(allMembers, VERTEX)) { // TODO: static foreach? 30 static assert(member != "this", `Found a 'this' member in vertex struct. Use a 'static struct' instead.`); 31 enum fullName = "VERTEX." ~ member; 32 mixin("alias T = typeof(" ~ fullName ~ ");"); 33 static if (staticIndexOf!(T, TT) != -1) { 34 int location = shader_program.attribute(member).location; 35 mixin("enum size_t offset = VERTEX." ~ member ~ ".offsetof;"); 36 enum UDAs = __traits(getAttributes, member); 37 bool normalize = false; //(staticIndexOf!(Normalized, UDAs) == -1); // TODO: -> not working @Normalized. 38 int n; 39 uint type; 40 toGLTypeAndSize!T(type, n); 41 _attributes ~= VertexAttribute(location, n, type, normalize ? 1 : 0, offset); 42 } 43 } 44 } 45 /// Use this vertex specification. 46 override void use(uint divisor = 0) { 47 for (uint i = 0; i < _attributes.length; i++) { 48 _attributes[i].use(cast(int)vertexSize, divisor); 49 } 50 } 51 /// Unuse this vertex specification. 52 /// If you are using a VAO, you don't need to call it, since the attributes would be tied to the VAO activation. 53 /// Throws: $(D GLException) on error. 54 override void unuse() { 55 for (uint i = 0; i < _attributes.length; i++) { 56 _attributes[i].unuse(); 57 } 58 } 59 } 60 /// Represent an OpenGL program attribute. 61 final class GLAttribute { 62 private { 63 int _location; 64 uint _type; 65 int _size; 66 string _name; 67 bool _disabled; 68 } 69 /// 70 enum int fakeLocation = -1; 71 /// 72 this(string name, int location, uint type, GLsizei size) { 73 _name = name; 74 _location = location; 75 _type = type; 76 _size = size; 77 _disabled = false; 78 } 79 /// Creates a fake disabled attribute, designed to cope with attribute 80 /// that have been optimized out by the OpenGL driver, or those which do not exist. 81 this(string name) { 82 _disabled = true; 83 _location = fakeLocation; 84 _type = GL_FLOAT; // whatever 85 _size = 1; 86 //s_gl._logger.warningf("Faking attribute '%s' which either does not exist in the shader program, or was discarded by the driver as unused", name); 87 } 88 /// 89 int location() pure nothrow const @safe @nogc @property { 90 return _location; 91 } 92 /// 93 string name() pure nothrow const @safe @nogc @property { 94 return _name; 95 } 96 } 97 /// Describes a single attribute in a vertex entry. 98 struct VertexAttribute { 99 private { 100 int _location; 101 int _n; 102 uint _type; 103 ubyte _normalize; // boolean 104 size_t _offset; 105 bool _divisorSet; 106 } 107 /// Use this attribute. 108 /// Throws: $(D GLException) on error. 109 void use(int vertex_size, uint divisor) { 110 if (_location == GLAttribute.fakeLocation) { 111 return; 112 } 113 if (divisor != 0) { 114 _divisorSet = true; 115 } 116 glEnableVertexAttribArray(_location); 117 if (isVideoIntegerType(_type)) { 118 glVertexAttribIPointer(_location, _n, _type, vertex_size, cast(void*)_offset); 119 } else { 120 glVertexAttribPointer(_location, _n, _type, _normalize, vertex_size, cast(void*)_offset); 121 } 122 GraphicsEngine.get.backend.runtimeCheck(); 123 } 124 /// Unuse this attribute. 125 /// Throws: $(D GLException) on error. 126 void unuse() { 127 if (_divisorSet) { 128 glVertexAttribDivisor(_location, 0); 129 } 130 _divisorSet = false; 131 glDisableVertexAttribArray(_location); 132 GraphicsEngine.get.backend.runtimeCheck(); 133 } 134 } 135 /// Define a simple vertex type from a vector type. 136 align(1) struct VertexPosition(VECTOR, string FIELD_NAME = "position") if (isVector!VECTOR) { 137 align(1): 138 mixin("VECTOR " ~ FIELD_NAME ~ ";"); 139 static assert(VertexPosition.sizeof == VECTOR.sizeof); 140 } 141 /// 142 unittest { 143 static struct VertexTest { 144 Vector3F position; 145 Vector3F normal; 146 Vector4F color; 147 @Normalized Vector2I uv; 148 float intensity; 149 } 150 alias Test1 = GLVertexSpec!VertexTest; 151 alias Test2 = GLVertexSpec!(VertexPosition!Vector3F); 152 }