1 // Written in the D programming language.
2 
3 /**
4 DLANGUI library.
5 
6 This module contains OpenGL access layer.
7 
8 To enable OpenGL support, build with version(USE_OPENGL);
9 
10 Synopsis:
11 
12 ----
13 import dlangui.graphics.glsupport;
14 
15 ----
16 
17 Copyright: Vadim Lopatin, 2014
18 License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
19 Authors:   $(WEB coolreader.org, Vadim Lopatin)
20 */
21 module dlangui.graphics.glsupport;
22 
23 version(USE_OPENGL) {
24 
25 import dlangui.core.logger;
26 private import derelict.opengl3.gl3;
27 //private import gl3n.linalg;
28 private import dlangui.core.types;
29 private import std.conv;
30 
31 // utility function to fill 4-float array of vertex colors with converted CR 32bit color
32 private void LVGLFillColor(uint color, float * buf, int count) {
33     float r = ((color >> 16) & 255) / 255.0f;
34     float g = ((color >> 8) & 255) / 255.0f;
35     float b = ((color >> 0) & 255) / 255.0f;
36     float a = (((color >> 24) & 255) ^ 255) / 255.0f;
37     for (int i=0; i<count; i++) {
38         *buf++ = r;
39         *buf++ = g;
40         *buf++ = b;
41         *buf++ = a;
42     }
43 }
44 
45 /// for OpenGL calls diagnostics.
46 private bool checkError(string context, string file = __FILE__, int line = __LINE__) {
47     int err = glGetError();
48     if (err != GL_NO_ERROR) {
49 		//string errorString = fromStringz(gluErrorString());
50         Log.e("OpenGL error ", err, " at ", file, ":", line, " -- ", context);
51         return true;
52     }
53     return false;
54 }
55 
56 immutable float Z_2D = -2.0f;
57 void drawSolidFillRect(Rect rc, uint color1, uint color2, uint color3, uint color4) {
58     float[6 * 4] colors;
59     LVGLFillColor(color1, colors.ptr + 4*0, 1);
60     LVGLFillColor(color4, colors.ptr + 4*1, 1);
61     LVGLFillColor(color3, colors.ptr + 4*2, 1);
62     LVGLFillColor(color1, colors.ptr + 4*3, 1);
63     LVGLFillColor(color3, colors.ptr + 4*4, 1);
64     LVGLFillColor(color2, colors.ptr + 4*5, 1);
65     float x0 = cast(float)(rc.left);
66     float y0 = cast(float)(bufferDy-rc.top);
67     float x1 = cast(float)(rc.right);
68     float y1 = cast(float)(bufferDy-rc.bottom);
69 
70     // don't flip for framebuffer
71     if (currentFramebufferId) {
72         y0 = cast(float)(rc.top);
73         y1 = cast(float)(rc.bottom);
74     }
75 
76     float[3 * 6] vertices = [
77         x0,y0,Z_2D,
78         x0,y1,Z_2D,
79         x1,y1,Z_2D,
80         x0,y0,Z_2D,
81         x1,y1,Z_2D,
82         x1,y0,Z_2D];
83 	if (_solidFillProgram !is null) {
84 		//Log.d("solid fill: vertices ", vertices, " colors ", colors);
85 		_solidFillProgram.execute(vertices, colors);
86 	} else
87 		Log.e("No program");
88 }
89 
90 void drawColorAndTextureRect(uint textureId, int tdx, int tdy, Rect srcrc, Rect dstrc, uint color, bool linear) {
91     //Log.v("drawColorAndTextureRect tx=", textureId, " src=", srcrc, " dst=", dstrc);
92     drawColorAndTextureRect(textureId, tdx, tdy, srcrc.left, srcrc.top, srcrc.width(), srcrc.height(), dstrc.left, dstrc.top, dstrc.width(), dstrc.height(), color, linear);
93 }
94 
95 void drawColorAndTextureRect(uint textureId, int tdx, int tdy, int srcx, int srcy, int srcdx, int srcdy, int xx, int yy, int dx, int dy, uint color, bool linear) {
96     float colors[6*4];
97     LVGLFillColor(color, colors.ptr, 6);
98     float dstx0 = cast(float)xx;
99     float dsty0 = cast(float)(bufferDy - (yy));
100     float dstx1 = cast(float)(xx + dx);
101     float dsty1 = cast(float)(bufferDy - (yy + dy));
102 
103     // don't flip for framebuffer
104     if (currentFramebufferId) {
105         dsty0 = cast(float)((yy));
106         dsty1 = cast(float)((yy + dy));
107     }
108 
109     float srcx0 = srcx / cast(float)tdx;
110     float srcy0 = srcy / cast(float)tdy;
111     float srcx1 = (srcx + srcdx) / cast(float)tdx;
112     float srcy1 = (srcy + srcdy) / cast(float)tdy;
113     float[3 * 6] vertices = [dstx0,dsty0,Z_2D,
114     dstx0,dsty1,Z_2D,
115     dstx1,dsty1,Z_2D,
116     dstx0,dsty0,Z_2D,
117     dstx1,dsty1,Z_2D,
118     dstx1,dsty0,Z_2D];
119     float[2 * 6] texcoords = [srcx0,srcy0, srcx0,srcy1, srcx1,srcy1, srcx0,srcy0, srcx1,srcy1, srcx1,srcy0];
120     _textureProgram.execute(vertices, texcoords, colors, textureId, linear);
121     //drawColorAndTextureRect(vertices, texcoords, colors, textureId, linear);
122 }
123 
124 /// generate new texture ID
125 uint genTexture() {
126     GLuint textureId = 0;
127     glGenTextures(1, &textureId);
128     return textureId;
129 }
130 
131 /// delete OpenGL texture
132 void deleteTexture(ref uint textureId) {
133     if (!textureId)
134         return;
135     if (glIsTexture(textureId) != GL_TRUE) {
136         Log.e("Invalid texture ", textureId);
137         return;
138     }
139     GLuint id = textureId;
140     glDeleteTextures(1, &id);
141     checkError("glDeleteTextures");
142     textureId = 0;
143 }
144 
145 /// call glFlush
146 void flushGL() {
147     glFlush();
148     checkError("glFlush");
149 }
150 
151 bool setTextureImage(uint textureId, int dx, int dy, ubyte * pixels) {
152     //checkError("before setTextureImage");
153     glActiveTexture(GL_TEXTURE0);
154     checkError("updateTexture - glActiveTexture");
155     glBindTexture(GL_TEXTURE_2D, 0);
156     checkError("updateTexture - glBindTexture(0)");
157     glBindTexture(GL_TEXTURE_2D, textureId);
158     checkError("updateTexture - glBindTexture");
159     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
160     checkError("updateTexture - glPixelStorei");
161     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
162     checkError("updateTexture - glTexParameteri");
163     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
164     checkError("updateTexture - glTexParameteri");
165     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
166     checkError("updateTexture - glTexParameteri");
167     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
168     checkError("updateTexture - glTexParameteri");
169 
170     if (!glIsTexture(textureId))
171         Log.e("second test - invalid texture passed to CRGLSupportImpl::setTextureImage");
172 
173     // ORIGINAL: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
174     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dx, dy, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
175     checkError("updateTexture - glTexImage2D");
176     if (glGetError() != GL_NO_ERROR) {
177         Log.e("Cannot set image for texture");
178         return false;
179     }
180     checkError("after setTextureImage");
181     return true;
182 }
183 
184 bool setTextureImageAlpha(uint textureId, int dx, int dy, ubyte * pixels) {
185     checkError("before setTextureImageAlpha");
186     glActiveTexture(GL_TEXTURE0);
187     checkError("updateTexture - glActiveTexture");
188     glBindTexture(GL_TEXTURE_2D, 0);
189     checkError("updateTexture - glBindTexture(0)");
190     glBindTexture(GL_TEXTURE_2D, textureId);
191     checkError("setTextureImageAlpha - glBindTexture");
192     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
193     checkError("setTextureImageAlpha - glPixelStorei");
194     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
195     checkError("setTextureImageAlpha - glTexParameteri");
196     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
197     checkError("setTextureImageAlpha - glTexParameteri");
198     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
199     checkError("setTextureImageAlpha - glTexParameteri");
200     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
201     checkError("setTextureImageAlpha - glTexParameteri");
202 
203     if (!glIsTexture(textureId))
204         Log.e("second test: invalid texture passed to CRGLSupportImpl::setTextureImageAlpha");
205 
206     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, dx, dy, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
207     checkError("setTextureImageAlpha - glTexImage2D");
208     if (glGetError() != GL_NO_ERROR) {
209         Log.e("Cannot set image for texture");
210         return false;
211     }
212     glBindTexture(GL_TEXTURE_2D, 0);
213     checkError("updateTexture - glBindTexture(0)");
214     checkError("after setTextureImageAlpha");
215     return true;
216 }
217 
218 private uint currentFramebufferId;
219 
220 /// returns texture ID for buffer, 0 if failed
221 bool createFramebuffer(ref uint textureId, ref uint framebufferId, int dx, int dy) {
222     checkError("before createFramebuffer");
223     bool res = true;
224     textureId = framebufferId = 0;
225     textureId = genTexture();
226     if (!textureId)
227         return false;
228     GLuint fid = 0;
229     glGenFramebuffers(1, &fid);
230     if (checkError("createFramebuffer glGenFramebuffersOES")) return false;
231     framebufferId = fid;
232     glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
233     if (checkError("createFramebuffer glBindFramebuffer")) return false;
234 
235     glBindTexture(GL_TEXTURE_2D, textureId);
236     checkError("glBindTexture(GL_TEXTURE_2D, _textureId)");
237     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dx, dy, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, null);
238     checkError("glTexImage2D");
239 
240     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
241     checkError("texParameter");
242     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
243     checkError("texParameter");
244     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
245     checkError("texParameter");
246     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
247     checkError("texParameter");
248 
249     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
250     checkError("glFramebufferTexture2D");
251     // Always check that our framebuffer is ok
252     if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
253         Log.e("glFramebufferTexture2D failed");
254         res = false;
255     }
256     checkError("glCheckFramebufferStatus");
257     //glClearColor(0.5f, 0, 0, 1);
258     glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
259     checkError("glClearColor");
260     glClear(GL_COLOR_BUFFER_BIT);
261     checkError("glClear");
262     checkError("after createFramebuffer");
263     //CRLog::trace("CRGLSupportImpl::createFramebuffer %d,%d  texture=%d, buffer=%d", dx, dy, textureId, framebufferId);
264     currentFramebufferId = framebufferId;
265 
266     glBindTexture(GL_TEXTURE_2D, 0);
267     checkError("createFramebuffer - glBindTexture(0)");
268     glBindFramebuffer(GL_FRAMEBUFFER, 0);
269     checkError("createFramebuffer - glBindFramebuffer(0)");
270 
271     return res;
272 }
273 
274 void deleteFramebuffer(ref uint framebufferId) {
275     //CRLog::debug("GLDrawBuf::deleteFramebuffer");
276     if (framebufferId != 0) {
277         glBindFramebuffer(GL_FRAMEBUFFER, 0);
278         checkError("deleteFramebuffer - glBindFramebuffer");
279         GLuint fid = framebufferId;
280         glDeleteFramebuffers(1, &fid);
281         checkError("deleteFramebuffer - glDeleteFramebuffer");
282     }
283     //CRLog::trace("CRGLSupportImpl::deleteFramebuffer(%d)", framebufferId);
284     framebufferId = 0;
285     checkError("after deleteFramebuffer");
286     currentFramebufferId = 0;
287 }
288 
289 bool bindFramebuffer(uint framebufferId) {
290     //CRLog::trace("CRGLSupportImpl::bindFramebuffer(%d)", framebufferId);
291     glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
292     currentFramebufferId = framebufferId;
293     return !checkError("glBindFramebuffer");
294 }
295 
296 /// projection matrix
297 //private mat4 m;
298 /// current gl buffer width
299 private int bufferDx;
300 /// current gl buffer height
301 private int bufferDy;
302 
303 //private float[16] matrix;
304 private float[16] qtmatrix;
305 
306 void QMatrix4x4_ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
307 {
308     // Bail out if the projection volume is zero-sized.
309     if (left == right || bottom == top || nearPlane == farPlane)
310         return;
311 
312     // Construct the projection.
313     float width = right - left;
314     float invheight = top - bottom;
315     float clip = farPlane - nearPlane;
316     float[4][4] m;
317     m[0][0] = 2.0f / width;
318     m[1][0] = 0.0f;
319     m[2][0] = 0.0f;
320     m[3][0] = -(left + right) / width;
321     m[0][1] = 0.0f;
322     m[1][1] = 2.0f / invheight;
323     m[2][1] = 0.0f;
324     m[3][1] = -(top + bottom) / invheight;
325     m[0][2] = 0.0f;
326     m[1][2] = 0.0f;
327     m[2][2] = -2.0f / clip;
328     m[3][2] = -(nearPlane + farPlane) / clip;
329     m[0][3] = 0.0f;
330     m[1][3] = 0.0f;
331     m[2][3] = 0.0f;
332     m[3][3] = 1.0f;
333     for (int y = 0; y < 4; y++)
334         for (int x = 0; x < 4; x++)
335             qtmatrix[y * 4 + x] = m[y][x];
336 }
337 
338 void setOrthoProjection(int dx, int dy) {
339     bufferDx = dx;
340     bufferDy = dy;
341     QMatrix4x4_ortho(0, dx, 0, dy, 0.5f, 50.0f);
342     glViewport(0, 0, dx, dy);
343     checkError("glViewport");
344 }
345 
346 class GLProgram {
347     @property abstract string vertexSource();
348     @property abstract string fragmentSource();
349     protected GLuint vertexShader;
350     protected GLuint fragmentShader;
351     protected GLuint program;
352     protected bool initialized;
353     protected bool error;
354 	protected string glslversion;
355     this() {
356     }
357     private GLuint compileShader(string src, GLuint type) {
358         import core.stdc.stdlib;
359         import std.string;
360 
361 		Log.d("compileShader glsl=", glslversion, " code: ", src);
362 
363         GLuint shader = glCreateShader(type);//GL_VERTEX_SHADER
364         const char * psrc = src.toStringz;
365         GLuint len = cast(uint)src.length;
366         glShaderSource(shader, 1, &psrc, cast(const(int)*)&len);
367         glCompileShader(shader);
368         GLint compiled;
369         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
370         if (compiled) {
371             // compiled successfully
372             return shader;
373         } else {
374             GLint blen = 0;	
375             GLsizei slen = 0;
376             glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &blen);       
377             if (blen > 1)
378             {
379                 GLchar[] msg = new GLchar[blen + 1];
380                 GLchar * pmsg = &msg[0];
381                 glGetShaderInfoLog(shader, blen, &slen, pmsg);
382                 Log.d("Shader compilation error: ", fromStringz(pmsg));
383             }    
384             return 0;
385         }
386     }
387     bool compile() {
388 		glslversion = fromStringz(glGetString(GL_SHADING_LANGUAGE_VERSION));
389         vertexShader = compileShader(vertexSource, GL_VERTEX_SHADER);
390         fragmentShader = compileShader(fragmentSource, GL_FRAGMENT_SHADER);
391         if (!vertexShader || !fragmentShader) {
392             error = true;
393             return false;
394         }
395         program = glCreateProgram();
396         glAttachShader(program, vertexShader);
397         glAttachShader(program, fragmentShader);
398         glLinkProgram(program);
399         GLint isLinked = 0;
400         glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
401         if (!isLinked) {
402             GLint maxLength = 0;
403             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
404             GLchar[] msg = new GLchar[maxLength + 1];
405             GLchar * pmsg = &msg[0];
406             glGetProgramInfoLog(program, maxLength, &maxLength, pmsg);
407             Log.e("Error while linking program: ", fromStringz(pmsg));
408             error = true;
409             return false;
410         }
411         Log.d("Program compiled successfully");
412         //glDetachShader(program, vertexShader);
413         //glDetachShader(program, fragmentShader);
414         glUseProgram(program);
415         checkError("glUseProgram " ~ to!string(program));
416         if (!initLocations()) {
417             Log.e("some of locations were not found");
418             error = true;
419         }
420         initialized = true;
421         return true;
422     }
423     bool initLocations() {
424         return true;
425     }
426     bool bind() {
427         if (!initialized)
428             return false;
429 		if (!glIsProgram(program))
430 			Log.e("!glIsProgram(program)");
431         glUseProgram(program);
432         checkError("glUseProgram " ~ to!string(program));
433         return true;
434     }
435     void release() {
436         glUseProgram(0);
437         checkError("glUseProgram(0)");
438     }
439     ~this() {
440         clear();
441     }
442     void clear() {
443         // TODO: cleanup
444         if (program)
445             glDeleteProgram(program);
446         if (vertexShader)
447             glDeleteShader(vertexShader);
448         if (fragmentShader)
449             glDeleteShader(fragmentShader);
450         program = vertexShader = fragmentShader = 0;
451         initialized = false;
452     }
453 }
454 
455 immutable string HIGHP = "";
456 immutable string LOWP = "";
457 immutable string MEDIUMP = "";
458 
459 class SolidFillProgram : GLProgram {
460     @property override string vertexSource() {
461         return         
462             "attribute " ~ HIGHP ~ " vec4 vertex;\n"
463             "attribute " ~ LOWP ~ " vec4 colAttr;\n"
464             "varying " ~ LOWP ~ " vec4 col;\n"
465             "uniform " ~ MEDIUMP ~ " mat4 matrix;\n"
466             "void main(void)\n"
467             "{\n"
468             "    gl_Position = matrix * vertex;\n"
469             "    col = colAttr;\n"
470             "}\n";
471 
472     }
473     @property override string fragmentSource() {
474         return
475             "varying " ~ LOWP ~ " vec4 col;\n"
476             "void main(void)\n"
477             "{\n"
478             "    gl_FragColor = col;\n"
479             "}\n";
480     }
481 
482     void beforeExecute() {
483         glEnable(GL_BLEND);
484         glDisable(GL_CULL_FACE);
485         checkError("glDisable(GL_CULL_FACE)");
486         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
487         //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 
488         checkError("glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)");
489         bind();
490         //glUniformMatrix4fv(matrixLocation,  1, false, m.value_ptr);
491         //glUniformMatrix4fv(matrixLocation,  1, false, matrix.ptr);
492         glUniformMatrix4fv(matrixLocation,  1, false, qtmatrix.ptr);
493         checkError("glUniformMatrix4fv");
494     }
495 
496     void afterExecute() {
497         release();
498     }
499 
500     protected GLint matrixLocation;
501     protected GLint vertexLocation;
502     protected GLint colAttrLocation;
503 	protected GLuint vertexBuffer;
504 	protected GLuint colAttrBuffer;
505     override bool initLocations() {
506         bool res = super.initLocations();
507 
508 		//glGenBuffers(1, &vertexBuffer);
509 		//glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
510 		//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 3 * 6, null, GL_DYNAMIC_DRAW);
511 		//glGenBuffers(1, &colAttrBuffer);
512 		//glBindBuffer(GL_ARRAY_BUFFER, colAttrBuffer);
513 		//glBufferData(GL_ARRAY_BUFFER, float.sizeof * 4 * 6, null, GL_DYNAMIC_DRAW);
514 
515         matrixLocation = glGetUniformLocation(program, "matrix");
516 		checkError("glGetUniformLocation matrix");
517         vertexLocation = glGetAttribLocation(program, "vertex");
518 		checkError("glGetAttribLocation vertex");
519         colAttrLocation = glGetAttribLocation(program, "colAttr");
520 		checkError("glGetAttribLocation colAttr");
521         return res && matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0;
522     }
523 
524     bool execute(float[] vertices, float[] colors) {
525         if (error)
526             return false;
527         if (!initialized)
528             if (!compile())
529                 return false;
530         beforeExecute();
531 
532         glEnableVertexAttribArray(vertexLocation);
533         checkError("glEnableVertexAttribArray");
534         glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, float.sizeof * 3, vertices.ptr);
535         checkError("glVertexAttribPointer");
536 
537         glEnableVertexAttribArray(colAttrLocation);
538         checkError("glEnableVertexAttribArray");
539         glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, float.sizeof * 4, colors.ptr);
540         checkError("glVertexAttribPointer");
541 
542         glDrawArrays(GL_TRIANGLES, 0, 6);
543         checkError("glDrawArrays");
544 
545         glDisableVertexAttribArray(vertexLocation);
546         checkError("glDisableVertexAttribArray");
547         glDisableVertexAttribArray(colAttrLocation);
548         checkError("glDisableVertexAttribArray");
549 
550         afterExecute();
551         return true;
552     }
553 }
554 
555 class TextureProgram : SolidFillProgram {
556     @property override string vertexSource() {
557         return         
558             "attribute " ~ HIGHP ~ " vec4 vertex;\n"
559             "attribute " ~ LOWP ~ " vec4 colAttr;\n"
560             "attribute " ~ MEDIUMP ~ " vec4 texCoord;\n"
561             "varying " ~ LOWP ~ " vec4 col;\n"
562             "varying " ~ MEDIUMP ~ " vec4 texc;\n"
563             "uniform " ~ MEDIUMP ~ " mat4 matrix;\n"
564             "void main(void)\n"
565             "{\n"
566             "    gl_Position = matrix * vertex;\n"
567             "    col = colAttr;\n"
568             "    texc = texCoord;\n"
569             "}\n";
570 
571     }
572     @property override string fragmentSource() {
573         return
574             "uniform sampler2D texture;\n"
575             "varying " ~ LOWP ~ " vec4 col;\n"
576             "varying " ~ MEDIUMP ~ " vec4 texc;\n"
577             "void main(void)\n"
578             "{\n"
579             "    gl_FragColor = texture2D(texture, texc.st) * col;\n"
580             "}\n";
581     }
582 
583     GLint texCoordLocation;
584     override bool initLocations() {
585         bool res = super.initLocations();
586         texCoordLocation = glGetAttribLocation(program, "texCoord");
587         return res && texCoordLocation >= 0;
588     }
589 
590     bool execute(float[] vertices, float[] texcoords, float[] colors, uint textureId, bool linear) {
591         if (error)
592             return false;
593         if (!initialized)
594             if (!compile())
595                 return false;
596         beforeExecute();
597         glActiveTexture(GL_TEXTURE0);
598         checkError("glActiveTexture GL_TEXTURE0");
599         glBindTexture(GL_TEXTURE_2D, textureId);
600         checkError("glBindTexture");
601         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
602         checkError("drawColorAndTextureRect - glTexParameteri");
603         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST);
604         checkError("drawColorAndTextureRect - glTexParameteri");
605 
606         glEnableVertexAttribArray(vertexLocation);
607         glEnableVertexAttribArray(colAttrLocation);
608         glEnableVertexAttribArray(texCoordLocation);
609 
610         glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices.ptr);
611         glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, colors.ptr);
612         glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords.ptr);
613 
614         glDrawArrays(GL_TRIANGLES, 0, 6);
615         checkError("glDrawArrays");
616 
617         glDisableVertexAttribArray(vertexLocation);
618         glDisableVertexAttribArray(colAttrLocation);
619         glDisableVertexAttribArray(texCoordLocation);
620 
621         afterExecute();
622         glBindTexture(GL_TEXTURE_2D, 0);
623         checkError("glBindTexture");
624         return true;
625     }
626 }
627 
628 __gshared TextureProgram _textureProgram;
629 __gshared SolidFillProgram _solidFillProgram;
630 
631 bool initShaders() {
632     if (_textureProgram is null) {
633         _textureProgram = new TextureProgram();
634         if (!_textureProgram.compile())
635             return false;
636     }
637     if (_solidFillProgram is null) {
638         _solidFillProgram = new SolidFillProgram();
639         if (!_solidFillProgram.compile())
640             return false;
641     }
642     Log.d("Shaders compiled successfully");
643     return true;
644 }
645 
646 bool uninitShaders() {
647     Log.d("Uniniting shaders");
648     if (_textureProgram !is null) {
649         destroy(_textureProgram);
650 		_textureProgram = null;
651     }
652     if (_solidFillProgram !is null) {
653         destroy(_solidFillProgram);
654 		_solidFillProgram = null;
655     }
656     return true;
657 }
658 
659 bool isTexture(uint textureId) {
660     return glIsTexture(textureId) == GL_TRUE;
661 }
662 
663 void setRotation(int x, int y, int rotationAngle) {
664     /*
665     this->rotationAngle = rotationAngle;
666     rotationX = x;
667     rotationY = y;
668     if (!currentFramebufferId) {
669         rotationY = bufferDy - rotationY;
670     }
671 
672     QMatrix4x4 matrix2;
673     matrix2.ortho(0, bufferDx, 0, bufferDy, 0.5f, 5.0f);
674     if (rotationAngle) {
675 		matrix2.translate(rotationX, rotationY, 0);
676 		matrix2.rotate(rotationAngle, 0, 0, 1);
677 		matrix2.translate(-rotationX, -rotationY, 0);
678     }
679     matrix2.copyDataTo(m);
680     */
681 }
682 
683 
684 }