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 }