1 //  ---------------------------------------------------------------------------
2 //
3 //  @file       TwOpenGLCore.cpp
4 //  @author     Philippe Decaudin
5 //  @license    This file is part of the AntTweakBar library.
6 //              For conditions of distribution and use, see License.txt
7 //
8 //  ---------------------------------------------------------------------------
9 
10 /*
11 #pragma warning GL3             //// used for development
12 #define GL3_PROTOTYPES 1        ////
13 #include <GL3/gl3.h>            ////
14 #define ANT_OGL_HEADER_INCLUDED ////
15 */
16 
17 #if defined ANT_OSX
18 #   include <OpenGL/gl3.h>
19 #   define ANT_OGL_HEADER_INCLUDED
20 #endif
21 #include "TwPrecomp.h"
22 #include "LoadOGLCore.h"
23 #include "TwOpenGLCore.h"
24 #include "TwMgr.h"
25 
26 using namespace std;
27 
28 extern const char *g_ErrCantLoadOGL;
29 extern const char *g_ErrCantUnloadOGL;
30 
31 //  ---------------------------------------------------------------------------
32 
33 #ifdef _DEBUG
CheckGLCoreError(const char * file,int line,const char * func)34     static void CheckGLCoreError(const char *file, int line, const char *func)
35     {
36         int err=0;
37         char msg[256];
38         while( (err=_glGetError())!=0 )
39         {
40             sprintf(msg, "%s(%d) : [%s] GL_CORE_ERROR=0x%x\n", file, line, func, err);
41             #ifdef ANT_WINDOWS
42                 OutputDebugString(msg);
43             #endif
44             fprintf(stderr, msg);
45         }
46     }
47 #   ifdef __FUNCTION__
48 #       define CHECK_GL_ERROR CheckGLCoreError(__FILE__, __LINE__, __FUNCTION__)
49 #   else
50 #       define CHECK_GL_ERROR CheckGLCoreError(__FILE__, __LINE__, "")
51 #   endif
52 #else
53 #   define CHECK_GL_ERROR ((void)(0))
54 #endif
55 
56 //  ---------------------------------------------------------------------------
57 
BindFont(const CTexFont * _Font)58 static GLuint BindFont(const CTexFont *_Font)
59 {
60     GLuint TexID = 0;
61     _glGenTextures(1, &TexID);
62     _glBindTexture(GL_TEXTURE_2D, TexID);
63     _glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
64     _glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
65     _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
66     _glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
67     _glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
68     _glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
69     _glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, _Font->m_TexWidth, _Font->m_TexHeight, 0, GL_RED, GL_UNSIGNED_BYTE, _Font->m_TexBytes);
70     _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
71     _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
72     _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
73     _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
74     _glBindTexture(GL_TEXTURE_2D, 0);
75 
76     return TexID;
77 }
78 
UnbindFont(GLuint _FontTexID)79 static void UnbindFont(GLuint _FontTexID)
80 {
81     if( _FontTexID>0 )
82         _glDeleteTextures(1, &_FontTexID);
83 }
84 
85 //  ---------------------------------------------------------------------------
86 
CompileShader(GLuint shader)87 static GLuint CompileShader(GLuint shader)
88 {
89     _glCompileShader(shader); CHECK_GL_ERROR;
90 
91     GLint status;
92     _glGetShaderiv(shader, GL_COMPILE_STATUS, &status); CHECK_GL_ERROR;
93     if (status == GL_FALSE)
94     {
95         GLint infoLogLength;
96         _glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); CHECK_GL_ERROR;
97 
98         GLchar strInfoLog[256];
99         _glGetShaderInfoLog(shader, sizeof(strInfoLog), NULL, strInfoLog); CHECK_GL_ERROR;
100 #ifdef ANT_WINDOWS
101         OutputDebugString("Compile failure: ");
102         OutputDebugString(strInfoLog);
103         OutputDebugString("\n");
104 #endif
105         fprintf(stderr, "Compile failure: %s\n", strInfoLog);
106         shader = 0;
107     }
108 
109     return shader;
110 }
111 
LinkProgram(GLuint program)112 static GLuint LinkProgram(GLuint program)
113 {
114     _glLinkProgram(program); CHECK_GL_ERROR;
115 
116     GLint status;
117     _glGetProgramiv(program, GL_LINK_STATUS, &status); CHECK_GL_ERROR;
118     if (status == GL_FALSE)
119     {
120         GLint infoLogLength;
121         _glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); CHECK_GL_ERROR;
122 
123         GLchar strInfoLog[256];
124         _glGetProgramInfoLog(program, sizeof(strInfoLog), NULL, strInfoLog); CHECK_GL_ERROR;
125 #ifdef ANT_WINDOWS
126         OutputDebugString("Linker failure: ");
127         OutputDebugString(strInfoLog);
128         OutputDebugString("\n");
129 #endif
130         fprintf(stderr, "Linker failure: %s\n", strInfoLog);
131         program = 0;
132     }
133 
134     return program;
135 }
136 
137 //  ---------------------------------------------------------------------------
138 
ResizeTriBuffers(size_t _NewSize)139 void CTwGraphOpenGLCore::ResizeTriBuffers(size_t _NewSize)
140 {
141     m_TriBufferSize = _NewSize;
142 
143     _glBindVertexArray(m_TriVArray);
144 
145     _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices);
146     _glBufferData(GL_ARRAY_BUFFER, m_TriBufferSize*sizeof(Vec2), 0, GL_DYNAMIC_DRAW);
147 
148     _glBindBuffer(GL_ARRAY_BUFFER, m_TriUVs);
149     _glBufferData(GL_ARRAY_BUFFER, m_TriBufferSize*sizeof(Vec2), 0, GL_DYNAMIC_DRAW);
150 
151     _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors);
152     _glBufferData(GL_ARRAY_BUFFER, m_TriBufferSize*sizeof(color32), 0, GL_DYNAMIC_DRAW);
153 
154     CHECK_GL_ERROR;
155 }
156 
157 //  ---------------------------------------------------------------------------
158 
Init()159 int CTwGraphOpenGLCore::Init()
160 {
161     m_Drawing = false;
162     m_FontTexID = 0;
163     m_FontTex = NULL;
164 
165     if( LoadOpenGLCore()==0 )
166     {
167         g_TwMgr->SetLastError(g_ErrCantLoadOGL);
168         return 0;
169     }
170 
171     // Create line/rect shaders
172     const GLchar *lineRectVS[] = {
173         "#version 150 core\n"
174         "in vec3 vertex;"
175         "in vec4 color;"
176         "out vec4 fcolor;"
177         "void main() { gl_Position = vec4(vertex, 1); fcolor = color; }"
178     };
179     m_LineRectVS = _glCreateShader(GL_VERTEX_SHADER);
180     _glShaderSource(m_LineRectVS, 1, lineRectVS, NULL);
181     CompileShader(m_LineRectVS);
182 
183     const GLchar *lineRectFS[] = {
184         "#version 150 core\n"
185         "precision highp float;"
186         "in vec4 fcolor;"
187         "out vec4 outColor;"
188         "void main() { outColor = fcolor; }"
189     };
190     m_LineRectFS = _glCreateShader(GL_FRAGMENT_SHADER);
191     _glShaderSource(m_LineRectFS, 1, lineRectFS, NULL);
192     CompileShader(m_LineRectFS);
193 
194     m_LineRectProgram = _glCreateProgram();
195     _glAttachShader(m_LineRectProgram, m_LineRectVS);
196     _glAttachShader(m_LineRectProgram, m_LineRectFS);
197     _glBindAttribLocation(m_LineRectProgram, 0, "vertex");
198     _glBindAttribLocation(m_LineRectProgram, 1, "color");
199     LinkProgram(m_LineRectProgram);
200 
201     // Create line/rect vertex buffer
202     const GLfloat lineRectInitVertices[] = { 0,0,0, 0,0,0, 0,0,0, 0,0,0 };
203     const color32 lineRectInitColors[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
204     _glGenVertexArrays(1, &m_LineRectVArray);
205     _glBindVertexArray(m_LineRectVArray);
206     _glGenBuffers(1, &m_LineRectVertices);
207     _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectVertices);
208     _glBufferData(GL_ARRAY_BUFFER, sizeof(lineRectInitVertices), lineRectInitVertices, GL_DYNAMIC_DRAW);
209     _glGenBuffers(1, &m_LineRectColors);
210     _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectColors);
211     _glBufferData(GL_ARRAY_BUFFER, sizeof(lineRectInitColors), lineRectInitColors, GL_DYNAMIC_DRAW);
212 
213     // Create triangles shaders
214     const GLchar *triVS[] = {
215         "#version 150 core\n"
216         "uniform vec2 offset;"
217         "uniform vec2 wndSize;"
218         "in vec2 vertex;"
219         "in vec4 color;"
220         "out vec4 fcolor;"
221         "void main() { gl_Position = vec4(2.0*(vertex.x+offset.x-0.5)/wndSize.x - 1.0, 1.0 - 2.0*(vertex.y+offset.y-0.5)/wndSize.y, 0, 1); fcolor = color; }"
222     };
223     m_TriVS = _glCreateShader(GL_VERTEX_SHADER);
224     _glShaderSource(m_TriVS, 1, triVS, NULL);
225     CompileShader(m_TriVS);
226 
227     const GLchar *triUniVS[] = {
228         "#version 150 core\n"
229         "uniform vec2 offset;"
230         "uniform vec2 wndSize;"
231         "uniform vec4 color;"
232         "in vec2 vertex;"
233         "out vec4 fcolor;"
234         "void main() { gl_Position = vec4(2.0*(vertex.x+offset.x-0.5)/wndSize.x - 1.0, 1.0 - 2.0*(vertex.y+offset.y-0.5)/wndSize.y, 0, 1); fcolor = color; }"
235     };
236     m_TriUniVS = _glCreateShader(GL_VERTEX_SHADER);
237     _glShaderSource(m_TriUniVS, 1, triUniVS, NULL);
238     CompileShader(m_TriUniVS);
239 
240     m_TriFS = m_TriUniFS = m_LineRectFS;
241 
242     m_TriProgram = _glCreateProgram();
243     _glAttachShader(m_TriProgram, m_TriVS);
244     _glAttachShader(m_TriProgram, m_TriFS);
245     _glBindAttribLocation(m_TriProgram, 0, "vertex");
246     _glBindAttribLocation(m_TriProgram, 1, "color");
247     LinkProgram(m_TriProgram);
248     m_TriLocationOffset = _glGetUniformLocation(m_TriProgram, "offset");
249     m_TriLocationWndSize = _glGetUniformLocation(m_TriProgram, "wndSize");
250 
251     m_TriUniProgram = _glCreateProgram();
252     _glAttachShader(m_TriUniProgram, m_TriUniVS);
253     _glAttachShader(m_TriUniProgram, m_TriUniFS);
254     _glBindAttribLocation(m_TriUniProgram, 0, "vertex");
255     _glBindAttribLocation(m_TriUniProgram, 1, "color");
256     LinkProgram(m_TriUniProgram);
257     m_TriUniLocationOffset = _glGetUniformLocation(m_TriUniProgram, "offset");
258     m_TriUniLocationWndSize = _glGetUniformLocation(m_TriUniProgram, "wndSize");
259     m_TriUniLocationColor = _glGetUniformLocation(m_TriUniProgram, "color");
260 
261     const GLchar *triTexFS[] = {
262         "#version 150 core\n"
263         "precision highp float;"
264         "uniform sampler2D tex;"
265         "in vec2 fuv;"
266         "in vec4 fcolor;"
267         "out vec4 outColor;"
268 // texture2D is deprecated and replaced by texture with GLSL 3.30 but it seems
269 // that on Mac Lion backward compatibility is not ensured.
270 #if defined(ANT_OSX) && (MAC_OS_X_VERSION_MAX_ALLOWED >= 1070)
271         "void main() { outColor.rgb = fcolor.bgr; outColor.a = fcolor.a * texture(tex, fuv).r; }"
272 #else
273         "void main() { outColor.rgb = fcolor.bgr; outColor.a = fcolor.a * texture2D(tex, fuv).r; }"
274 #endif
275     };
276     m_TriTexFS = _glCreateShader(GL_FRAGMENT_SHADER);
277     _glShaderSource(m_TriTexFS, 1, triTexFS, NULL);
278     CompileShader(m_TriTexFS);
279 
280     const GLchar *triTexVS[] = {
281         "#version 150 core\n"
282         "uniform vec2 offset;"
283         "uniform vec2 wndSize;"
284         "in vec2 vertex;"
285         "in vec2 uv;"
286         "in vec4 color;"
287         "out vec2 fuv;"
288         "out vec4 fcolor;"
289         "void main() { gl_Position = vec4(2.0*(vertex.x+offset.x-0.5)/wndSize.x - 1.0, 1.0 - 2.0*(vertex.y+offset.y-0.5)/wndSize.y, 0, 1); fuv = uv; fcolor = color; }"
290     };
291     m_TriTexVS = _glCreateShader(GL_VERTEX_SHADER);
292     _glShaderSource(m_TriTexVS, 1, triTexVS, NULL);
293     CompileShader(m_TriTexVS);
294 
295     const GLchar *triTexUniVS[] = {
296         "#version 150 core\n"
297         "uniform vec2 offset;"
298         "uniform vec2 wndSize;"
299         "uniform vec4 color;"
300         "in vec2 vertex;"
301         "in vec2 uv;"
302         "out vec4 fcolor;"
303         "out vec2 fuv;"
304         "void main() { gl_Position = vec4(2.0*(vertex.x+offset.x-0.5)/wndSize.x - 1.0, 1.0 - 2.0*(vertex.y+offset.y-0.5)/wndSize.y, 0, 1); fuv = uv; fcolor = color; }"
305     };
306     m_TriTexUniVS = _glCreateShader(GL_VERTEX_SHADER);
307     _glShaderSource(m_TriTexUniVS, 1, triTexUniVS, NULL);
308     CompileShader(m_TriTexUniVS);
309 
310     m_TriTexUniFS = m_TriTexFS;
311 
312     m_TriTexProgram = _glCreateProgram();
313     _glAttachShader(m_TriTexProgram, m_TriTexVS);
314     _glAttachShader(m_TriTexProgram, m_TriTexFS);
315     _glBindAttribLocation(m_TriTexProgram, 0, "vertex");
316     _glBindAttribLocation(m_TriTexProgram, 1, "uv");
317     _glBindAttribLocation(m_TriTexProgram, 2, "color");
318     LinkProgram(m_TriTexProgram);
319     m_TriTexLocationOffset = _glGetUniformLocation(m_TriTexProgram, "offset");
320     m_TriTexLocationWndSize = _glGetUniformLocation(m_TriTexProgram, "wndSize");
321     m_TriTexLocationTexture = _glGetUniformLocation(m_TriTexProgram, "tex");
322 
323     m_TriTexUniProgram = _glCreateProgram();
324     _glAttachShader(m_TriTexUniProgram, m_TriTexUniVS);
325     _glAttachShader(m_TriTexUniProgram, m_TriTexUniFS);
326     _glBindAttribLocation(m_TriTexUniProgram, 0, "vertex");
327     _glBindAttribLocation(m_TriTexUniProgram, 1, "uv");
328     _glBindAttribLocation(m_TriTexUniProgram, 2, "color");
329     LinkProgram(m_TriTexUniProgram);
330     m_TriTexUniLocationOffset = _glGetUniformLocation(m_TriTexUniProgram, "offset");
331     m_TriTexUniLocationWndSize = _glGetUniformLocation(m_TriTexUniProgram, "wndSize");
332     m_TriTexUniLocationColor = _glGetUniformLocation(m_TriTexUniProgram, "color");
333     m_TriTexUniLocationTexture = _glGetUniformLocation(m_TriTexUniProgram, "tex");
334 
335     // Create tri vertex buffer
336     _glGenVertexArrays(1, &m_TriVArray);
337     _glGenBuffers(1, &m_TriVertices);
338     _glGenBuffers(1, &m_TriUVs);
339     _glGenBuffers(1, &m_TriColors);
340     ResizeTriBuffers(16384); // set initial size
341 
342     CHECK_GL_ERROR;
343     return 1;
344 }
345 
346 //  ---------------------------------------------------------------------------
347 
Shut()348 int CTwGraphOpenGLCore::Shut()
349 {
350     assert(m_Drawing==false);
351 
352     UnbindFont(m_FontTexID);
353 
354     CHECK_GL_ERROR;
355 
356     _glDeleteProgram(m_LineRectProgram); m_LineRectProgram = 0;
357     _glDeleteShader(m_LineRectVS); m_LineRectVS = 0;
358     _glDeleteShader(m_LineRectFS); m_LineRectFS = 0;
359 
360     _glDeleteProgram(m_TriProgram); m_TriProgram = 0;
361     _glDeleteShader(m_TriVS); m_TriVS = 0;
362 
363     _glDeleteProgram(m_TriUniProgram); m_TriUniProgram = 0;
364     _glDeleteShader(m_TriUniVS); m_TriUniVS = 0;
365 
366     _glDeleteProgram(m_TriTexProgram); m_TriTexProgram = 0;
367     _glDeleteShader(m_TriTexVS); m_TriTexVS = 0;
368     _glDeleteShader(m_TriTexFS); m_TriTexFS = 0;
369 
370     _glDeleteProgram(m_TriTexUniProgram); m_TriTexUniProgram = 0;
371     _glDeleteShader(m_TriTexUniVS); m_TriTexUniVS = 0;
372 
373     _glDeleteBuffers(1, &m_LineRectVertices); m_LineRectVertices = 0;
374     _glDeleteBuffers(1, &m_LineRectColors); m_LineRectColors = 0;
375     _glDeleteVertexArrays(1, &m_LineRectVArray); m_LineRectVArray = 0;
376 
377     _glDeleteBuffers(1, &m_TriVertices); m_TriVertices = 0;
378     _glDeleteBuffers(1, &m_TriColors); m_TriColors = 0;
379     _glDeleteBuffers(1, &m_TriUVs); m_TriUVs = 0;
380     _glDeleteVertexArrays(1, &m_TriVArray); m_TriVArray = 0;
381 
382     CHECK_GL_ERROR;
383 
384     int Res = 1;
385     if( UnloadOpenGLCore()==0 )
386     {
387         g_TwMgr->SetLastError(g_ErrCantUnloadOGL);
388         Res = 0;
389     }
390 
391     return Res;
392 }
393 
394 //  ---------------------------------------------------------------------------
395 
BeginDraw(int _WndWidth,int _WndHeight)396 void CTwGraphOpenGLCore::BeginDraw(int _WndWidth, int _WndHeight)
397 {
398     CHECK_GL_ERROR;
399     assert(m_Drawing==false && _WndWidth>0 && _WndHeight>0);
400     m_Drawing = true;
401     m_WndWidth = _WndWidth;
402     m_WndHeight = _WndHeight;
403     m_OffsetX = 0;
404     m_OffsetY = 0;
405 
406     _glGetIntegerv(GL_VIEWPORT, m_PrevViewport); CHECK_GL_ERROR;
407     if( _WndWidth>0 && _WndHeight>0 )
408     {
409         GLint Vp[4];
410         Vp[0] = 0;
411         Vp[1] = 0;
412         Vp[2] = _WndWidth-1;
413         Vp[3] = _WndHeight-1;
414         _glViewport(Vp[0], Vp[1], Vp[2], Vp[3]);
415     }
416 
417     m_PrevVArray = 0;
418     _glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&m_PrevVArray); CHECK_GL_ERROR;
419     _glBindVertexArray(0); CHECK_GL_ERROR;
420 
421     m_PrevLineWidth = 1;
422     _glGetFloatv(GL_LINE_WIDTH, &m_PrevLineWidth); CHECK_GL_ERROR;
423     _glLineWidth(1); CHECK_GL_ERROR;
424 
425     m_PrevLineSmooth = _glIsEnabled(GL_LINE_SMOOTH);
426     _glDisable(GL_LINE_SMOOTH); CHECK_GL_ERROR;
427 
428     m_PrevCullFace = _glIsEnabled(GL_CULL_FACE);
429     _glDisable(GL_CULL_FACE); CHECK_GL_ERROR;
430 
431     m_PrevDepthTest = _glIsEnabled(GL_DEPTH_TEST);
432     _glDisable(GL_DEPTH_TEST); CHECK_GL_ERROR;
433 
434     m_PrevBlend = _glIsEnabled(GL_BLEND);
435     _glEnable(GL_BLEND); CHECK_GL_ERROR;
436 
437     m_PrevScissorTest = _glIsEnabled(GL_SCISSOR_TEST);
438     _glDisable(GL_SCISSOR_TEST); CHECK_GL_ERROR;
439 
440     _glGetIntegerv(GL_SCISSOR_BOX, m_PrevScissorBox); CHECK_GL_ERROR;
441 
442     _glGetIntegerv(GL_BLEND_SRC, &m_PrevSrcBlend); CHECK_GL_ERROR;
443     _glGetIntegerv(GL_BLEND_DST, &m_PrevDstBlend); CHECK_GL_ERROR;
444     _glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CHECK_GL_ERROR;
445 
446     m_PrevTexture = 0;
447     _glGetIntegerv(GL_TEXTURE_BINDING_2D, &m_PrevTexture); CHECK_GL_ERROR;
448     _glBindTexture(GL_TEXTURE_2D, 0); CHECK_GL_ERROR;
449 
450     m_PrevProgramObject = 0;
451     _glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&m_PrevProgramObject); CHECK_GL_ERROR;
452     _glBindVertexArray(0); CHECK_GL_ERROR;
453     _glUseProgram(0); CHECK_GL_ERROR;
454 
455     m_PrevActiveTexture = 0;
456     _glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&m_PrevActiveTexture); CHECK_GL_ERROR;
457     _glActiveTexture(GL_TEXTURE0);
458 
459     CHECK_GL_ERROR;
460 }
461 
462 //  ---------------------------------------------------------------------------
463 
EndDraw()464 void CTwGraphOpenGLCore::EndDraw()
465 {
466     assert(m_Drawing==true);
467     m_Drawing = false;
468 
469     _glLineWidth(m_PrevLineWidth); CHECK_GL_ERROR;
470 
471     if( m_PrevLineSmooth )
472     {
473       _glEnable(GL_LINE_SMOOTH); CHECK_GL_ERROR;
474     }
475     else
476     {
477       _glDisable(GL_LINE_SMOOTH); CHECK_GL_ERROR;
478     }
479 
480     if( m_PrevCullFace )
481     {
482       _glEnable(GL_CULL_FACE); CHECK_GL_ERROR;
483     }
484     else
485     {
486       _glDisable(GL_CULL_FACE); CHECK_GL_ERROR;
487     }
488 
489     if( m_PrevDepthTest )
490     {
491       _glEnable(GL_DEPTH_TEST); CHECK_GL_ERROR;
492     }
493     else
494     {
495       _glDisable(GL_DEPTH_TEST); CHECK_GL_ERROR;
496     }
497 
498     if( m_PrevBlend )
499     {
500       _glEnable(GL_BLEND); CHECK_GL_ERROR;
501     }
502     else
503     {
504       _glDisable(GL_BLEND); CHECK_GL_ERROR;
505     }
506 
507     if( m_PrevScissorTest )
508     {
509       _glEnable(GL_SCISSOR_TEST); CHECK_GL_ERROR;
510     }
511     else
512     {
513       _glDisable(GL_SCISSOR_TEST); CHECK_GL_ERROR;
514     }
515 
516     _glScissor(m_PrevScissorBox[0], m_PrevScissorBox[1], m_PrevScissorBox[2], m_PrevScissorBox[3]); CHECK_GL_ERROR;
517 
518     _glBlendFunc(m_PrevSrcBlend, m_PrevDstBlend); CHECK_GL_ERROR;
519 
520     _glBindTexture(GL_TEXTURE_2D, m_PrevTexture); CHECK_GL_ERROR;
521 
522     _glUseProgram(m_PrevProgramObject); CHECK_GL_ERROR;
523 
524     _glBindVertexArray(m_PrevVArray); CHECK_GL_ERROR;
525 
526     _glViewport(m_PrevViewport[0], m_PrevViewport[1], m_PrevViewport[2], m_PrevViewport[3]); CHECK_GL_ERROR;
527 
528     CHECK_GL_ERROR;
529 }
530 
531 //  ---------------------------------------------------------------------------
532 
IsDrawing()533 bool CTwGraphOpenGLCore::IsDrawing()
534 {
535     return m_Drawing;
536 }
537 
538 //  ---------------------------------------------------------------------------
539 
Restore()540 void CTwGraphOpenGLCore::Restore()
541 {
542     UnbindFont(m_FontTexID);
543     m_FontTexID = 0;
544     m_FontTex = NULL;
545 }
546 
547 //  ---------------------------------------------------------------------------
548 
ToNormScreenX(float x,int wndWidth)549 static inline float ToNormScreenX(float x, int wndWidth)
550 {
551     return 2.0f*((float)x-0.5f)/wndWidth - 1.0f;
552 }
553 
ToNormScreenY(float y,int wndHeight)554 static inline float ToNormScreenY(float y, int wndHeight)
555 {
556     return 1.0f - 2.0f*((float)y-0.5f)/wndHeight;
557 }
558 
559 //  ---------------------------------------------------------------------------
560 
DrawLine(int _X0,int _Y0,int _X1,int _Y1,color32 _Color0,color32 _Color1,bool _AntiAliased)561 void CTwGraphOpenGLCore::DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased)
562 {
563     CHECK_GL_ERROR;
564     assert(m_Drawing==true);
565 
566     //const GLfloat dx = +0.0f;
567     const GLfloat dx = 0;
568     //GLfloat dy = -0.2f;
569     const GLfloat dy = -0.5f;
570     if( _AntiAliased )
571         _glEnable(GL_LINE_SMOOTH);
572     else
573         _glDisable(GL_LINE_SMOOTH);
574 
575     _glBindVertexArray(m_LineRectVArray);
576 
577     GLfloat x0 = ToNormScreenX(_X0+dx + m_OffsetX, m_WndWidth);
578     GLfloat y0 = ToNormScreenY(_Y0+dy + m_OffsetY, m_WndHeight);
579     GLfloat x1 = ToNormScreenX(_X1+dx + m_OffsetX, m_WndWidth);
580     GLfloat y1 = ToNormScreenY(_Y1+dy + m_OffsetY, m_WndHeight);
581     GLfloat vertices[] = { x0,y0,0,  x1,y1,0 };
582     _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectVertices);
583     _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
584     _glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 0, NULL);
585     _glEnableVertexAttribArray(0);
586 
587     color32 colors[] = { _Color0, _Color1 };
588     _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectColors);
589     _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(colors), colors);
590     _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL);
591     _glEnableVertexAttribArray(1);
592 
593     _glUseProgram(m_LineRectProgram);
594     _glDrawArrays(GL_LINES, 0, 2);
595 
596     if( _AntiAliased )
597         _glDisable(GL_LINE_SMOOTH);
598 
599     CHECK_GL_ERROR;
600 }
601 
602 //  ---------------------------------------------------------------------------
603 
DrawRect(int _X0,int _Y0,int _X1,int _Y1,color32 _Color00,color32 _Color10,color32 _Color01,color32 _Color11)604 void CTwGraphOpenGLCore::DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11)
605 {
606     CHECK_GL_ERROR;
607     assert(m_Drawing==true);
608 
609     // border adjustment
610     if(_X0<_X1)
611         ++_X1;
612     else if(_X0>_X1)
613         ++_X0;
614     if(_Y0<_Y1)
615         --_Y0;
616     else if(_Y0>_Y1)
617         --_Y1;
618 
619     _glBindVertexArray(m_LineRectVArray);
620 
621     GLfloat x0 = ToNormScreenX((float)_X0 + m_OffsetX, m_WndWidth);
622     GLfloat y0 = ToNormScreenY((float)_Y0 + m_OffsetY, m_WndHeight);
623     GLfloat x1 = ToNormScreenX((float)_X1 + m_OffsetX, m_WndWidth);
624     GLfloat y1 = ToNormScreenY((float)_Y1 + m_OffsetY, m_WndHeight);
625     GLfloat vertices[] = { x0,y0,0, x1,y0,0, x0,y1,0, x1,y1,0 };
626     _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectVertices);
627     _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
628     _glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 0, NULL);
629     _glEnableVertexAttribArray(0);
630 
631     GLuint colors[] = { _Color00, _Color10, _Color01, _Color11 };
632     _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectColors);
633     _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(colors), colors);
634     _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL);
635     _glEnableVertexAttribArray(1);
636 
637     _glUseProgram(m_LineRectProgram);
638     _glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
639 
640     CHECK_GL_ERROR;
641 }
642 
643 //  ---------------------------------------------------------------------------
644 
NewTextObj()645 void *CTwGraphOpenGLCore::NewTextObj()
646 {
647     return new CTextObj;
648 }
649 
650 //  ---------------------------------------------------------------------------
651 
DeleteTextObj(void * _TextObj)652 void CTwGraphOpenGLCore::DeleteTextObj(void *_TextObj)
653 {
654     assert(_TextObj!=NULL);
655     delete static_cast<CTextObj *>(_TextObj);
656 }
657 
658 //  ---------------------------------------------------------------------------
659 
BuildText(void * _TextObj,const std::string * _TextLines,color32 * _LineColors,color32 * _LineBgColors,int _NbLines,const CTexFont * _Font,int _Sep,int _BgWidth)660 void CTwGraphOpenGLCore::BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth)
661 {
662     assert(m_Drawing==true);
663     assert(_TextObj!=NULL);
664     assert(_Font!=NULL);
665 
666     if( _Font != m_FontTex )
667     {
668         UnbindFont(m_FontTexID);
669         m_FontTexID = BindFont(_Font);
670         m_FontTex = _Font;
671     }
672     CTextObj *TextObj = static_cast<CTextObj *>(_TextObj);
673     TextObj->m_TextVerts.resize(0);
674     TextObj->m_TextUVs.resize(0);
675     TextObj->m_BgVerts.resize(0);
676     TextObj->m_Colors.resize(0);
677     TextObj->m_BgColors.resize(0);
678 
679     int x, x1, y, y1, i, Len;
680     unsigned char ch;
681     const unsigned char *Text;
682     color32 LineColor = COLOR32_RED;
683     for( int Line=0; Line<_NbLines; ++Line )
684     {
685         x = 0;
686         y = Line * (_Font->m_CharHeight+_Sep);
687         y1 = y+_Font->m_CharHeight;
688         Len = (int)_TextLines[Line].length();
689         Text = (const unsigned char *)(_TextLines[Line].c_str());
690         if( _LineColors!=NULL )
691             LineColor = (_LineColors[Line]&0xff00ff00) | GLubyte(_LineColors[Line]>>16) | (GLubyte(_LineColors[Line])<<16);
692 
693         for( i=0; i<Len; ++i )
694         {
695             ch = Text[i];
696             x1 = x + _Font->m_CharWidth[ch];
697 
698             TextObj->m_TextVerts.push_back(Vec2(x , y ));
699             TextObj->m_TextVerts.push_back(Vec2(x1, y ));
700             TextObj->m_TextVerts.push_back(Vec2(x , y1));
701             TextObj->m_TextVerts.push_back(Vec2(x1, y ));
702             TextObj->m_TextVerts.push_back(Vec2(x1, y1));
703             TextObj->m_TextVerts.push_back(Vec2(x , y1));
704 
705             TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV0[ch]));
706             TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch]));
707             TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch]));
708             TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch]));
709             TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV1[ch]));
710             TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch]));
711 
712             if( _LineColors!=NULL )
713             {
714                 TextObj->m_Colors.push_back(LineColor);
715                 TextObj->m_Colors.push_back(LineColor);
716                 TextObj->m_Colors.push_back(LineColor);
717                 TextObj->m_Colors.push_back(LineColor);
718                 TextObj->m_Colors.push_back(LineColor);
719                 TextObj->m_Colors.push_back(LineColor);
720             }
721 
722             x = x1;
723         }
724         if( _BgWidth>0 )
725         {
726             TextObj->m_BgVerts.push_back(Vec2(-1        , y ));
727             TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y ));
728             TextObj->m_BgVerts.push_back(Vec2(-1        , y1));
729             TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y ));
730             TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y1));
731             TextObj->m_BgVerts.push_back(Vec2(-1        , y1));
732 
733             if( _LineBgColors!=NULL )
734             {
735                 color32 LineBgColor = (_LineBgColors[Line]&0xff00ff00) | GLubyte(_LineBgColors[Line]>>16) | (GLubyte(_LineBgColors[Line])<<16);
736                 TextObj->m_BgColors.push_back(LineBgColor);
737                 TextObj->m_BgColors.push_back(LineBgColor);
738                 TextObj->m_BgColors.push_back(LineBgColor);
739                 TextObj->m_BgColors.push_back(LineBgColor);
740                 TextObj->m_BgColors.push_back(LineBgColor);
741                 TextObj->m_BgColors.push_back(LineBgColor);
742             }
743         }
744     }
745 }
746 
747 //  ---------------------------------------------------------------------------
748 
DrawText(void * _TextObj,int _X,int _Y,color32 _Color,color32 _BgColor)749 void CTwGraphOpenGLCore::DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor)
750 {
751     CHECK_GL_ERROR;
752     assert(m_Drawing==true);
753     assert(_TextObj!=NULL);
754     CTextObj *TextObj = static_cast<CTextObj *>(_TextObj);
755 
756     if( TextObj->m_TextVerts.size()<4 && TextObj->m_BgVerts.size()<4 )
757         return; // nothing to draw
758 
759     // draw character background triangles
760     if( (_BgColor!=0 || TextObj->m_BgColors.size()==TextObj->m_BgVerts.size()) && TextObj->m_BgVerts.size()>=4 )
761     {
762         size_t numBgVerts = TextObj->m_BgVerts.size();
763         if( numBgVerts > m_TriBufferSize )
764             ResizeTriBuffers(numBgVerts + 2048);
765 
766         _glBindVertexArray(m_TriVArray);
767 
768         _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices);
769         _glBufferSubData(GL_ARRAY_BUFFER, 0, numBgVerts*sizeof(Vec2), &(TextObj->m_BgVerts[0]));
770         _glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, 0, NULL);
771         _glEnableVertexAttribArray(0);
772         _glDisableVertexAttribArray(1);
773         _glDisableVertexAttribArray(2);
774 
775         if( TextObj->m_BgColors.size()==TextObj->m_BgVerts.size() && _BgColor==0 )
776         {
777             _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors);
778             _glBufferSubData(GL_ARRAY_BUFFER, 0, numBgVerts*sizeof(color32), &(TextObj->m_BgColors[0]));
779             _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL);
780             _glEnableVertexAttribArray(1);
781 
782             _glUseProgram(m_TriProgram);
783             _glUniform2f(m_TriLocationOffset, (float)_X, (float)_Y);
784             _glUniform2f(m_TriLocationWndSize, (float)m_WndWidth, (float)m_WndHeight);
785         }
786         else
787         {
788             _glUseProgram(m_TriUniProgram);
789             _glUniform4f(m_TriUniLocationColor, GLfloat((_BgColor>>16)&0xff)/256.0f, GLfloat((_BgColor>>8)&0xff)/256.0f, GLfloat(_BgColor&0xff)/256.0f, GLfloat((_BgColor>>24)&0xff)/256.0f);
790             _glUniform2f(m_TriUniLocationOffset, (float)_X, (float)_Y);
791             _glUniform2f(m_TriUniLocationWndSize, (float)m_WndWidth, (float)m_WndHeight);
792         }
793 
794         _glDrawArrays(GL_TRIANGLES, 0, (GLsizei)TextObj->m_BgVerts.size());
795     }
796 
797     // draw character triangles
798     if( TextObj->m_TextVerts.size()>=4 )
799     {
800         _glActiveTexture(GL_TEXTURE0);
801         _glBindTexture(GL_TEXTURE_2D, m_FontTexID);
802         size_t numTextVerts = TextObj->m_TextVerts.size();
803         if( numTextVerts > m_TriBufferSize )
804             ResizeTriBuffers(numTextVerts + 2048);
805 
806         _glBindVertexArray(m_TriVArray);
807         _glDisableVertexAttribArray(2);
808 
809         _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices);
810         _glBufferSubData(GL_ARRAY_BUFFER, 0, numTextVerts*sizeof(Vec2), &(TextObj->m_TextVerts[0]));
811         _glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, 0, NULL);
812         _glEnableVertexAttribArray(0);
813 
814         _glBindBuffer(GL_ARRAY_BUFFER, m_TriUVs);
815         _glBufferSubData(GL_ARRAY_BUFFER, 0, numTextVerts*sizeof(Vec2), &(TextObj->m_TextUVs[0]));
816         _glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
817         _glEnableVertexAttribArray(1);
818 
819         if( TextObj->m_Colors.size()==TextObj->m_TextVerts.size() && _Color==0 )
820         {
821             _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors);
822             _glBufferSubData(GL_ARRAY_BUFFER, 0, numTextVerts*sizeof(color32), &(TextObj->m_Colors[0]));
823             _glVertexAttribPointer(2, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL);
824             _glEnableVertexAttribArray(2);
825 
826             _glUseProgram(m_TriTexProgram);
827             _glUniform2f(m_TriTexLocationOffset, (float)_X, (float)_Y);
828             _glUniform2f(m_TriTexLocationWndSize, (float)m_WndWidth, (float)m_WndHeight);
829             _glUniform1i(m_TriTexLocationTexture, 0);
830         }
831         else
832         {
833             _glUseProgram(m_TriTexUniProgram);
834             _glUniform4f(m_TriTexUniLocationColor, GLfloat((_Color>>16)&0xff)/256.0f, GLfloat((_Color>>8)&0xff)/256.0f, GLfloat(_Color&0xff)/256.0f, GLfloat((_Color>>24)&0xff)/256.0f);
835             _glUniform2f(m_TriTexUniLocationOffset, (float)_X, (float)_Y);
836             _glUniform2f(m_TriTexUniLocationWndSize, (float)m_WndWidth, (float)m_WndHeight);
837             _glUniform1i(m_TriTexUniLocationTexture, 0);
838         }
839 
840         _glDrawArrays(GL_TRIANGLES, 0, (GLsizei)TextObj->m_TextVerts.size());
841     }
842 
843     CHECK_GL_ERROR;
844 }
845 
846 //  ---------------------------------------------------------------------------
847 
ChangeViewport(int _X0,int _Y0,int _Width,int _Height,int _OffsetX,int _OffsetY)848 void CTwGraphOpenGLCore::ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY)
849 {
850     // glViewport impacts the NDC; use glScissor instead
851     m_OffsetX = _X0 + _OffsetX;
852     m_OffsetY = _Y0 + _OffsetY;
853     SetScissor(_X0, _Y0, _Width, _Height);
854 }
855 
856 //  ---------------------------------------------------------------------------
857 
RestoreViewport()858 void CTwGraphOpenGLCore::RestoreViewport()
859 {
860     m_OffsetX = m_OffsetY = 0;
861     SetScissor(0, 0, 0, 0);
862 }
863 
864 //  ---------------------------------------------------------------------------
865 
SetScissor(int _X0,int _Y0,int _Width,int _Height)866 void CTwGraphOpenGLCore::SetScissor(int _X0, int _Y0, int _Width, int _Height)
867 {
868     if( _Width>0 && _Height>0 )
869     {
870         _glScissor(_X0-1, m_WndHeight-_Y0-_Height, _Width-1, _Height);
871         _glEnable(GL_SCISSOR_TEST);
872     }
873     else
874         _glDisable(GL_SCISSOR_TEST);
875 }
876 
877 //  ---------------------------------------------------------------------------
878 
DrawTriangles(int _NumTriangles,int * _Vertices,color32 * _Colors,Cull _CullMode)879 void CTwGraphOpenGLCore::DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode)
880 {
881     assert(m_Drawing==true);
882 
883     const GLfloat dx = +0.0f;
884     const GLfloat dy = +0.0f;
885 
886     // Backup states
887     GLint prevCullFaceMode, prevFrontFace;
888     _glGetIntegerv(GL_CULL_FACE_MODE, &prevCullFaceMode);
889     _glGetIntegerv(GL_FRONT_FACE, &prevFrontFace);
890     GLboolean prevCullEnable = _glIsEnabled(GL_CULL_FACE);
891     _glCullFace(GL_BACK);
892     _glEnable(GL_CULL_FACE);
893     if( _CullMode==CULL_CW )
894         _glFrontFace(GL_CCW);
895     else if( _CullMode==CULL_CCW )
896         _glFrontFace(GL_CW);
897     else
898         _glDisable(GL_CULL_FACE);
899 
900     _glUseProgram(m_TriProgram);
901     _glBindVertexArray(m_TriVArray);
902     _glUniform2f(m_TriLocationOffset, (float)m_OffsetX+dx, (float)m_OffsetY+dy);
903     _glUniform2f(m_TriLocationWndSize, (float)m_WndWidth, (float)m_WndHeight);
904     _glDisableVertexAttribArray(2);
905 
906     size_t numVerts = 3*_NumTriangles;
907     if( numVerts > m_TriBufferSize )
908         ResizeTriBuffers(numVerts + 2048);
909 
910     _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices);
911     _glBufferSubData(GL_ARRAY_BUFFER, 0, numVerts*2*sizeof(int), _Vertices);
912     _glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, NULL);
913     _glEnableVertexAttribArray(0);
914 
915     _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors);
916     _glBufferSubData(GL_ARRAY_BUFFER, 0, numVerts*sizeof(color32), _Colors);
917     _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL);
918     _glEnableVertexAttribArray(1);
919 
920     _glDrawArrays(GL_TRIANGLES, 0, (GLsizei)numVerts);
921 
922     // Reset states
923     _glCullFace(prevCullFaceMode);
924     _glFrontFace(prevFrontFace);
925     if( prevCullEnable )
926         _glEnable(GL_CULL_FACE);
927     else
928         _glDisable(GL_CULL_FACE);
929 
930     CHECK_GL_ERROR;
931 }
932 
933 //  ---------------------------------------------------------------------------
934