1 /*
2  * This file is part of gtkD.
3  *
4  * dui is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * dui is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with dui; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
17  */
18 
19 // To compile:
20 // [gdc] gdc CoreGL.d `pkg-config gtkd-3 gl --cflags --libs`
21 // [dmd] rdmd `pkg-config gtkd-3 --cflags` -L-lGL -L-ldl CoreGL.d
22 
23 module coreGL.CoreGL;
24 
25 import std.string;
26 
27 import gdk.GLContext;
28 import gtk.DrawingArea;
29 import gtk.GLArea;
30 import gtk.Main;
31 import gtk.MainWindow;
32 import gtk.Widget;
33 
34 import glcore;
35 
36 void main(string[] args)
37 {
38   Main.init(args);
39 
40   auto mainWnd = new MainWindow("Simplest GLArea + CoreGL Example");
41 
42   auto wnd = new CoreGL;
43   mainWnd.add(wnd);
44   mainWnd.showAll();
45 
46   Main.run();
47 }
48 
49 /**
50  * A really simple Demo illustrating OpenGL core profile with GtkD
51  * This example is provided under the terms of the GPL License.
52  *
53  * @author sebastien.alaiwan@gmail.com
54  */
55 class CoreGL : GLArea
56 {
57 public:
58   this()
59   {
60     setAutoRender(true);
61 
62     addEvents(GdkEventMask.BUTTON_PRESS_MASK);
63     addEvents(GdkEventMask.SCROLL_MASK);
64 
65     addOnRender(&render);
66     addOnRealize(&realize);
67     addOnUnrealize(&unrealize);
68 
69     showAll();
70   }
71 
72   GLuint m_Vao;
73   GLuint m_Program;
74   GLuint m_Mvp;
75 
76   void realize(Widget)
77   {
78     makeCurrent();
79     GLuint position_index;
80     GLuint color_index;
81     initShaders(&m_Program, &m_Mvp, &position_index, &color_index);
82     initBuffers(position_index, color_index);
83   }
84 
85   void unrealize(Widget)
86   {
87     makeCurrent();
88     glDeleteBuffers(1, &m_Vao);
89     glDeleteProgram(m_Program);
90   }
91 
92   bool render(GLContext c, GLArea a)
93   {
94     makeCurrent();
95 
96     glClearColor(0.3, 0.3, 0.3, 1);
97     glClear(GL_COLOR_BUFFER_BIT);
98 
99     drawTriangle();
100 
101     glFlush();
102 
103     return true;
104   }
105 
106   void drawTriangle()
107   {
108     immutable mvp = getIdentityMatrix();
109 
110     glUseProgram(m_Program);
111 
112     // update the "mvp" matrix we use in the shader
113     glUniformMatrix4fv(m_Mvp, 1, GL_FALSE, mvp.ptr);
114 
115     glBindBuffer(GL_ARRAY_BUFFER, m_Vao);
116     glEnableVertexAttribArray(0);
117     glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, null);
118 
119     // draw the three vertices as a triangle
120     glDrawArrays(GL_TRIANGLES, 0, 3);
121 
122     glDisableVertexAttribArray(0);
123     glBindBuffer(GL_ARRAY_BUFFER, 0);
124     glUseProgram(0);
125   }
126 
127   void initBuffers(uint position_index, uint color_index)
128   {
129     static immutable GLfloat[] vertex_data =
130     [
131       0.0f,   0.5f,   0.0f, 1.0f,
132       0.5f, -0.366f, 0.0f, 1.0f,
133       -0.5f, -0.366f, 0.0f, 1.0f,
134     ];
135 
136     // we need to create a VAO to store the other buffers
137     glGenVertexArrays(1, &m_Vao);
138     glBindVertexArray(m_Vao);
139 
140     // this is the VBO that holds the vertex data
141     GLuint buffer;
142     glGenBuffers(1, &buffer);
143     glBindBuffer(GL_ARRAY_BUFFER, buffer);
144     glBufferData(GL_ARRAY_BUFFER, vertex_data.length * float.sizeof, vertex_data.ptr, GL_STATIC_DRAW);
145 
146     // reset the state; we will re-enable the VAO when needed
147     glBindBuffer(GL_ARRAY_BUFFER, 0);
148   }
149 }
150 
151 void initShaders(uint* program_out, uint* mvp_location_out, uint* position_location_out, uint* color_location_out)
152 {
153   const vertex = compileShader(GL_VERTEX_SHADER, VertShaderCode ~ "\0");
154   scope(exit) glDeleteShader(vertex);
155 
156   const fragment = compileShader(GL_FRAGMENT_SHADER, FragShaderCode ~ "\0");
157   scope(exit) glDeleteShader(fragment);
158 
159   const program = glCreateProgram();
160 
161   glAttachShader(program, vertex);
162   scope(exit) glDetachShader(program, vertex);
163 
164   glAttachShader(program, fragment);
165   scope(exit) glDetachShader(program, fragment);
166 
167   glLinkProgram(program);
168 
169   int status = 0;
170   glGetProgramiv(program, GL_LINK_STATUS, &status);
171 
172   if(status == GL_FALSE)
173   {
174     int len = 0;
175     glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
176 
177     char[] buffer;
178     buffer.length = len + 1;
179     glGetProgramInfoLog(program, len, null, buffer.ptr);
180 
181     glDeleteProgram(program);
182 
183     throw new Exception(format("Linking failure in program: %s", buffer));
184   }
185 
186   *program_out = program;
187   *mvp_location_out = glGetUniformLocation(program, "mvp");
188   *position_location_out = glGetAttribLocation(program, "position");
189   *color_location_out = glGetAttribLocation(program, "color");
190 }
191 
192 uint compileShader(int type, string source)
193 {
194   const shader = glCreateShader(type);
195   scope(failure) glDeleteShader(shader);
196   const(char)*srcPtr = source.ptr;
197   glShaderSource(shader, 1, &srcPtr, null);
198   glCompileShader(shader);
199 
200   int status;
201   glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
202 
203   if(status == GL_FALSE)
204   {
205     int len;
206     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
207 
208     char[] buffer;
209     buffer.length = len + 1;
210     glGetShaderInfoLog(shader, len, null, buffer.ptr);
211 
212     const sType = type == GL_VERTEX_SHADER ? "vertex" : "fragment";
213 
214     throw new Exception(format("Compilation failure in %s shader: %s", sType, buffer));
215   }
216 
217   return shader;
218 }
219 
220 float[16] getIdentityMatrix() pure
221 {
222   float mat[4 * 4];
223 
224   // identity matrix
225   for(int x=0;x < 4;++x)
226     for(int y=0;y < 4;++y)
227       mat[x+y*4] = x==y ? 1 : 0;
228 
229   return mat;
230 }
231 
232 immutable FragShaderCode = `
233 #version 130
234 
235 smooth in vec4 vertexColor;
236 
237 out vec4 outputColor;
238 
239 void main() {
240   outputColor = vertexColor;
241 }`;
242 
243 immutable VertShaderCode = `
244 #version 130
245 
246 in vec3 position;
247 in vec3 color;
248 
249 uniform mat4 mvp;
250 
251 smooth out vec4 vertexColor;
252 
253 void main() {
254   gl_Position = mvp * vec4(position, 1.0);
255   vertexColor = vec4(color, 1.0);
256 }`;
257