1 module evael.renderer.gl.gl_command; 2 3 import evael.renderer.gl.gl_wrapper; 4 import evael.renderer.gl.gl_enum_converter; 5 import evael.renderer.gl.gl_shader; 6 import evael.renderer.gl.gl_texture; 7 8 import evael.renderer.graphics_command; 9 import evael.renderer.resources; 10 11 import evael.lib.containers.array; 12 13 public 14 { 15 import evael.utils.color; 16 } 17 18 class GLCommand : GraphicsCommand 19 { 20 private GLShader m_shader; 21 22 /** 23 * GLCommand constructor. 24 */ 25 @nogc 26 public this(Pipeline pipeline) 27 { 28 super(pipeline); 29 30 this.m_shader = cast(GLShader) pipeline.shader; 31 } 32 33 /** 34 * GLCommand destructor. 35 */ 36 @nogc 37 public ~this() 38 { 39 40 } 41 42 /** 43 * Specifies clear values for the color buffers. 44 * Params: 45 * color : clear color 46 */ 47 @nogc 48 public override void clearColor(in Color color = Color.Black) const nothrow 49 { 50 auto colorf = color.asFloat(); 51 52 gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 53 gl.ClearColor(colorf[0], colorf[1], colorf[2], 1.0f); 54 } 55 56 /** 57 * Renders primitives. 58 * Params: 59 * first : starting index in the enabled arrays 60 * count : number of indices to be rendered 61 */ 62 @nogc 63 public void draw(T)(in int first, in int count) nothrow 64 { 65 this.prepareDraw!T(); 66 67 gl.DrawArrays(GL_TRIANGLES, first, count); 68 69 this.postDraw(); 70 } 71 72 /** 73 * Renders indexed primitives. 74 * Params: 75 * count : number of elements to be rendered 76 * type : the type of the values in indices 77 * indices : pointer to the location where the indices are stored 78 */ 79 @nogc 80 public void drawIndexed(T)(in int count, in IndexBufferType type, in void* indices) const nothrow 81 { 82 this.prepareDraw!T(); 83 84 gl.DrawElements(this.m_pipeline.primitiveType, count, type, indices); 85 } 86 87 /** 88 * Prepares states for the next drawing operation. 89 **/ 90 @nogc 91 private void prepareDraw(T, string file = __FILE__, int line = __LINE__)() nothrow 92 { 93 gl.UseProgram(this.m_shader.programId); 94 95 this.m_pipeline.apply(); 96 97 gl.BindBuffer(this.m_vertexBuffer.internalType, this.m_vertexBuffer.id); 98 this.setVertexAttributes!(T, file, line)(); 99 } 100 101 /** 102 * Cleans states for the next drawing operation. 103 */ 104 @nogc 105 private void postDraw() nothrow 106 { 107 this.m_pipeline.clear(); 108 109 gl.BindBuffer(this.m_vertexBuffer.internalType, 0); 110 } 111 112 /** 113 * Sets vertex attributes. 114 */ 115 @nogc 116 private void setVertexAttributes(T, string file = __FILE__, int line = __LINE__)() const nothrow 117 { 118 enum size = cast(GLint) T.sizeof; 119 120 foreach (i, member; __traits(allMembers, T)) 121 { 122 static if (member == "opAssign") 123 { 124 continue; 125 } 126 else 127 { 128 enum UDAs = __traits(getAttributes, __traits(getMember, T, member)); 129 130 static assert(UDAs.length > 0, "You need to specify UDA for member " ~ T.stringof ~ "." ~ member); 131 132 enum shaderAttribute = UDAs[0]; 133 134 static if(is(typeof(shaderAttribute) : ShaderAttribute)) 135 { 136 enum offset = __traits(getMember, T, member).offsetof; 137 138 enum glAttributeType = GLEnumConverter.attributeType(shaderAttribute.type); 139 140 gl.EnableVertexAttribArray(shaderAttribute.layoutIndex); 141 gl.VertexAttribPointer( 142 shaderAttribute.layoutIndex, 143 shaderAttribute.size, 144 glAttributeType, 145 shaderAttribute.normalized, 146 size, cast(void*) offset 147 ); 148 149 version(GL_DEBUG) 150 { 151 import std..string : format; 152 pragma(msg, "%s:%d : gl.VertexAttribPointer(%d, %d, %d, %d, %d, %d);".format(file, line, shaderAttribute.layoutIndex, 153 shaderAttribute.size, 154 shaderAttribute.type, 155 shaderAttribute.normalized, 156 size, offset 157 )); 158 } 159 } 160 else 161 { 162 static assert(false, "UDA defined for member " ~ T.stringof ~ "." ~ member ~ " but is not a valid ShaderAttribute."); 163 } 164 } 165 } 166 } 167 }