// --------------------------------------------------------------------------- // // @file TwOpenGLCore.cpp // @author Philippe Decaudin // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- /* #pragma warning GL3 //// used for development #define GL3_PROTOTYPES 1 //// #include //// #define ANT_OGL_HEADER_INCLUDED //// */ #if defined ANT_OSX # include # define ANT_OGL_HEADER_INCLUDED #endif #include "TwPrecomp.h" #include "LoadOGLCore.h" #include "TwOpenGLCore.h" #include "TwMgr.h" using namespace std; extern const char *g_ErrCantLoadOGL; extern const char *g_ErrCantUnloadOGL; // --------------------------------------------------------------------------- #ifdef _DEBUG static void CheckGLCoreError(const char *file, int line, const char *func) { int err=0; char msg[256]; while( (err=_glGetError())!=0 ) { sprintf(msg, "%s(%d) : [%s] GL_CORE_ERROR=0x%x\n", file, line, func, err); #ifdef ANT_WINDOWS OutputDebugString(msg); #endif fprintf(stderr, msg); } } # ifdef __FUNCTION__ # define CHECK_GL_ERROR CheckGLCoreError(__FILE__, __LINE__, __FUNCTION__) # else # define CHECK_GL_ERROR CheckGLCoreError(__FILE__, __LINE__, "") # endif #else # define CHECK_GL_ERROR ((void)(0)) #endif // --------------------------------------------------------------------------- static GLuint BindFont(const CTexFont *_Font) { GLuint TexID = 0; _glGenTextures(1, &TexID); _glBindTexture(GL_TEXTURE_2D, TexID); _glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); _glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); _glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); _glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); _glPixelStorei(GL_UNPACK_ALIGNMENT, 1); _glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, _Font->m_TexWidth, _Font->m_TexHeight, 0, GL_RED, GL_UNSIGNED_BYTE, _Font->m_TexBytes); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); _glBindTexture(GL_TEXTURE_2D, 0); return TexID; } static void UnbindFont(GLuint _FontTexID) { if( _FontTexID>0 ) _glDeleteTextures(1, &_FontTexID); } // --------------------------------------------------------------------------- static GLuint CompileShader(GLuint shader) { _glCompileShader(shader); CHECK_GL_ERROR; GLint status; _glGetShaderiv(shader, GL_COMPILE_STATUS, &status); CHECK_GL_ERROR; if (status == GL_FALSE) { GLint infoLogLength; _glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); CHECK_GL_ERROR; GLchar strInfoLog[256]; _glGetShaderInfoLog(shader, sizeof(strInfoLog), NULL, strInfoLog); CHECK_GL_ERROR; #ifdef ANT_WINDOWS OutputDebugString("Compile failure: "); OutputDebugString(strInfoLog); OutputDebugString("\n"); #endif fprintf(stderr, "Compile failure: %s\n", strInfoLog); shader = 0; } return shader; } static GLuint LinkProgram(GLuint program) { _glLinkProgram(program); CHECK_GL_ERROR; GLint status; _glGetProgramiv(program, GL_LINK_STATUS, &status); CHECK_GL_ERROR; if (status == GL_FALSE) { GLint infoLogLength; _glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); CHECK_GL_ERROR; GLchar strInfoLog[256]; _glGetProgramInfoLog(program, sizeof(strInfoLog), NULL, strInfoLog); CHECK_GL_ERROR; #ifdef ANT_WINDOWS OutputDebugString("Linker failure: "); OutputDebugString(strInfoLog); OutputDebugString("\n"); #endif fprintf(stderr, "Linker failure: %s\n", strInfoLog); program = 0; } return program; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::ResizeTriBuffers(size_t _NewSize) { m_TriBufferSize = _NewSize; _glBindVertexArray(m_TriVArray); _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices); _glBufferData(GL_ARRAY_BUFFER, m_TriBufferSize*sizeof(Vec2), 0, GL_DYNAMIC_DRAW); _glBindBuffer(GL_ARRAY_BUFFER, m_TriUVs); _glBufferData(GL_ARRAY_BUFFER, m_TriBufferSize*sizeof(Vec2), 0, GL_DYNAMIC_DRAW); _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors); _glBufferData(GL_ARRAY_BUFFER, m_TriBufferSize*sizeof(color32), 0, GL_DYNAMIC_DRAW); CHECK_GL_ERROR; } // --------------------------------------------------------------------------- int CTwGraphOpenGLCore::Init() { m_Drawing = false; m_FontTexID = 0; m_FontTex = NULL; if( LoadOpenGLCore()==0 ) { g_TwMgr->SetLastError(g_ErrCantLoadOGL); return 0; } // Create line/rect shaders const GLchar *lineRectVS[] = { "#version 150 core\n" "in vec3 vertex;" "in vec4 color;" "out vec4 fcolor;" "void main() { gl_Position = vec4(vertex, 1); fcolor = color; }" }; m_LineRectVS = _glCreateShader(GL_VERTEX_SHADER); _glShaderSource(m_LineRectVS, 1, lineRectVS, NULL); CompileShader(m_LineRectVS); const GLchar *lineRectFS[] = { "#version 150 core\n" "precision highp float;" "in vec4 fcolor;" "out vec4 outColor;" "void main() { outColor = fcolor; }" }; m_LineRectFS = _glCreateShader(GL_FRAGMENT_SHADER); _glShaderSource(m_LineRectFS, 1, lineRectFS, NULL); CompileShader(m_LineRectFS); m_LineRectProgram = _glCreateProgram(); _glAttachShader(m_LineRectProgram, m_LineRectVS); _glAttachShader(m_LineRectProgram, m_LineRectFS); _glBindAttribLocation(m_LineRectProgram, 0, "vertex"); _glBindAttribLocation(m_LineRectProgram, 1, "color"); LinkProgram(m_LineRectProgram); // Create line/rect vertex buffer const GLfloat lineRectInitVertices[] = { 0,0,0, 0,0,0, 0,0,0, 0,0,0 }; const color32 lineRectInitColors[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; _glGenVertexArrays(1, &m_LineRectVArray); _glBindVertexArray(m_LineRectVArray); _glGenBuffers(1, &m_LineRectVertices); _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectVertices); _glBufferData(GL_ARRAY_BUFFER, sizeof(lineRectInitVertices), lineRectInitVertices, GL_DYNAMIC_DRAW); _glGenBuffers(1, &m_LineRectColors); _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectColors); _glBufferData(GL_ARRAY_BUFFER, sizeof(lineRectInitColors), lineRectInitColors, GL_DYNAMIC_DRAW); // Create triangles shaders const GLchar *triVS[] = { "#version 150 core\n" "uniform vec2 offset;" "uniform vec2 wndSize;" "in vec2 vertex;" "in vec4 color;" "out vec4 fcolor;" "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; }" }; m_TriVS = _glCreateShader(GL_VERTEX_SHADER); _glShaderSource(m_TriVS, 1, triVS, NULL); CompileShader(m_TriVS); const GLchar *triUniVS[] = { "#version 150 core\n" "uniform vec2 offset;" "uniform vec2 wndSize;" "uniform vec4 color;" "in vec2 vertex;" "out vec4 fcolor;" "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; }" }; m_TriUniVS = _glCreateShader(GL_VERTEX_SHADER); _glShaderSource(m_TriUniVS, 1, triUniVS, NULL); CompileShader(m_TriUniVS); m_TriFS = m_TriUniFS = m_LineRectFS; m_TriProgram = _glCreateProgram(); _glAttachShader(m_TriProgram, m_TriVS); _glAttachShader(m_TriProgram, m_TriFS); _glBindAttribLocation(m_TriProgram, 0, "vertex"); _glBindAttribLocation(m_TriProgram, 1, "color"); LinkProgram(m_TriProgram); m_TriLocationOffset = _glGetUniformLocation(m_TriProgram, "offset"); m_TriLocationWndSize = _glGetUniformLocation(m_TriProgram, "wndSize"); m_TriUniProgram = _glCreateProgram(); _glAttachShader(m_TriUniProgram, m_TriUniVS); _glAttachShader(m_TriUniProgram, m_TriUniFS); _glBindAttribLocation(m_TriUniProgram, 0, "vertex"); _glBindAttribLocation(m_TriUniProgram, 1, "color"); LinkProgram(m_TriUniProgram); m_TriUniLocationOffset = _glGetUniformLocation(m_TriUniProgram, "offset"); m_TriUniLocationWndSize = _glGetUniformLocation(m_TriUniProgram, "wndSize"); m_TriUniLocationColor = _glGetUniformLocation(m_TriUniProgram, "color"); const GLchar *triTexFS[] = { "#version 150 core\n" "precision highp float;" "uniform sampler2D tex;" "in vec2 fuv;" "in vec4 fcolor;" "out vec4 outColor;" // texture2D is deprecated and replaced by texture with GLSL 3.30 but it seems // that on Mac Lion backward compatibility is not ensured. #if defined(ANT_OSX) && (MAC_OS_X_VERSION_MAX_ALLOWED >= 1070) "void main() { outColor.rgb = fcolor.bgr; outColor.a = fcolor.a * texture(tex, fuv).r; }" #else "void main() { outColor.rgb = fcolor.bgr; outColor.a = fcolor.a * texture2D(tex, fuv).r; }" #endif }; m_TriTexFS = _glCreateShader(GL_FRAGMENT_SHADER); _glShaderSource(m_TriTexFS, 1, triTexFS, NULL); CompileShader(m_TriTexFS); const GLchar *triTexVS[] = { "#version 150 core\n" "uniform vec2 offset;" "uniform vec2 wndSize;" "in vec2 vertex;" "in vec2 uv;" "in vec4 color;" "out vec2 fuv;" "out vec4 fcolor;" "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; }" }; m_TriTexVS = _glCreateShader(GL_VERTEX_SHADER); _glShaderSource(m_TriTexVS, 1, triTexVS, NULL); CompileShader(m_TriTexVS); const GLchar *triTexUniVS[] = { "#version 150 core\n" "uniform vec2 offset;" "uniform vec2 wndSize;" "uniform vec4 color;" "in vec2 vertex;" "in vec2 uv;" "out vec4 fcolor;" "out vec2 fuv;" "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; }" }; m_TriTexUniVS = _glCreateShader(GL_VERTEX_SHADER); _glShaderSource(m_TriTexUniVS, 1, triTexUniVS, NULL); CompileShader(m_TriTexUniVS); m_TriTexUniFS = m_TriTexFS; m_TriTexProgram = _glCreateProgram(); _glAttachShader(m_TriTexProgram, m_TriTexVS); _glAttachShader(m_TriTexProgram, m_TriTexFS); _glBindAttribLocation(m_TriTexProgram, 0, "vertex"); _glBindAttribLocation(m_TriTexProgram, 1, "uv"); _glBindAttribLocation(m_TriTexProgram, 2, "color"); LinkProgram(m_TriTexProgram); m_TriTexLocationOffset = _glGetUniformLocation(m_TriTexProgram, "offset"); m_TriTexLocationWndSize = _glGetUniformLocation(m_TriTexProgram, "wndSize"); m_TriTexLocationTexture = _glGetUniformLocation(m_TriTexProgram, "tex"); m_TriTexUniProgram = _glCreateProgram(); _glAttachShader(m_TriTexUniProgram, m_TriTexUniVS); _glAttachShader(m_TriTexUniProgram, m_TriTexUniFS); _glBindAttribLocation(m_TriTexUniProgram, 0, "vertex"); _glBindAttribLocation(m_TriTexUniProgram, 1, "uv"); _glBindAttribLocation(m_TriTexUniProgram, 2, "color"); LinkProgram(m_TriTexUniProgram); m_TriTexUniLocationOffset = _glGetUniformLocation(m_TriTexUniProgram, "offset"); m_TriTexUniLocationWndSize = _glGetUniformLocation(m_TriTexUniProgram, "wndSize"); m_TriTexUniLocationColor = _glGetUniformLocation(m_TriTexUniProgram, "color"); m_TriTexUniLocationTexture = _glGetUniformLocation(m_TriTexUniProgram, "tex"); // Create tri vertex buffer _glGenVertexArrays(1, &m_TriVArray); _glGenBuffers(1, &m_TriVertices); _glGenBuffers(1, &m_TriUVs); _glGenBuffers(1, &m_TriColors); ResizeTriBuffers(16384); // set initial size CHECK_GL_ERROR; return 1; } // --------------------------------------------------------------------------- int CTwGraphOpenGLCore::Shut() { assert(m_Drawing==false); UnbindFont(m_FontTexID); CHECK_GL_ERROR; _glDeleteProgram(m_LineRectProgram); m_LineRectProgram = 0; _glDeleteShader(m_LineRectVS); m_LineRectVS = 0; _glDeleteShader(m_LineRectFS); m_LineRectFS = 0; _glDeleteProgram(m_TriProgram); m_TriProgram = 0; _glDeleteShader(m_TriVS); m_TriVS = 0; _glDeleteProgram(m_TriUniProgram); m_TriUniProgram = 0; _glDeleteShader(m_TriUniVS); m_TriUniVS = 0; _glDeleteProgram(m_TriTexProgram); m_TriTexProgram = 0; _glDeleteShader(m_TriTexVS); m_TriTexVS = 0; _glDeleteShader(m_TriTexFS); m_TriTexFS = 0; _glDeleteProgram(m_TriTexUniProgram); m_TriTexUniProgram = 0; _glDeleteShader(m_TriTexUniVS); m_TriTexUniVS = 0; _glDeleteBuffers(1, &m_LineRectVertices); m_LineRectVertices = 0; _glDeleteBuffers(1, &m_LineRectColors); m_LineRectColors = 0; _glDeleteVertexArrays(1, &m_LineRectVArray); m_LineRectVArray = 0; _glDeleteBuffers(1, &m_TriVertices); m_TriVertices = 0; _glDeleteBuffers(1, &m_TriColors); m_TriColors = 0; _glDeleteBuffers(1, &m_TriUVs); m_TriUVs = 0; _glDeleteVertexArrays(1, &m_TriVArray); m_TriVArray = 0; CHECK_GL_ERROR; int Res = 1; if( UnloadOpenGLCore()==0 ) { g_TwMgr->SetLastError(g_ErrCantUnloadOGL); Res = 0; } return Res; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::BeginDraw(int _WndWidth, int _WndHeight) { CHECK_GL_ERROR; assert(m_Drawing==false && _WndWidth>0 && _WndHeight>0); m_Drawing = true; m_WndWidth = _WndWidth; m_WndHeight = _WndHeight; m_OffsetX = 0; m_OffsetY = 0; _glGetIntegerv(GL_VIEWPORT, m_PrevViewport); CHECK_GL_ERROR; if( _WndWidth>0 && _WndHeight>0 ) { GLint Vp[4]; Vp[0] = 0; Vp[1] = 0; Vp[2] = _WndWidth-1; Vp[3] = _WndHeight-1; _glViewport(Vp[0], Vp[1], Vp[2], Vp[3]); } m_PrevVArray = 0; _glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&m_PrevVArray); CHECK_GL_ERROR; _glBindVertexArray(0); CHECK_GL_ERROR; m_PrevLineWidth = 1; _glGetFloatv(GL_LINE_WIDTH, &m_PrevLineWidth); CHECK_GL_ERROR; _glLineWidth(1); CHECK_GL_ERROR; m_PrevLineSmooth = _glIsEnabled(GL_LINE_SMOOTH); _glDisable(GL_LINE_SMOOTH); CHECK_GL_ERROR; m_PrevCullFace = _glIsEnabled(GL_CULL_FACE); _glDisable(GL_CULL_FACE); CHECK_GL_ERROR; m_PrevDepthTest = _glIsEnabled(GL_DEPTH_TEST); _glDisable(GL_DEPTH_TEST); CHECK_GL_ERROR; m_PrevBlend = _glIsEnabled(GL_BLEND); _glEnable(GL_BLEND); CHECK_GL_ERROR; m_PrevScissorTest = _glIsEnabled(GL_SCISSOR_TEST); _glDisable(GL_SCISSOR_TEST); CHECK_GL_ERROR; _glGetIntegerv(GL_SCISSOR_BOX, m_PrevScissorBox); CHECK_GL_ERROR; _glGetIntegerv(GL_BLEND_SRC, &m_PrevSrcBlend); CHECK_GL_ERROR; _glGetIntegerv(GL_BLEND_DST, &m_PrevDstBlend); CHECK_GL_ERROR; _glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); CHECK_GL_ERROR; m_PrevTexture = 0; _glGetIntegerv(GL_TEXTURE_BINDING_2D, &m_PrevTexture); CHECK_GL_ERROR; _glBindTexture(GL_TEXTURE_2D, 0); CHECK_GL_ERROR; m_PrevProgramObject = 0; _glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&m_PrevProgramObject); CHECK_GL_ERROR; _glBindVertexArray(0); CHECK_GL_ERROR; _glUseProgram(0); CHECK_GL_ERROR; m_PrevActiveTexture = 0; _glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&m_PrevActiveTexture); CHECK_GL_ERROR; _glActiveTexture(GL_TEXTURE0); CHECK_GL_ERROR; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::EndDraw() { assert(m_Drawing==true); m_Drawing = false; _glLineWidth(m_PrevLineWidth); CHECK_GL_ERROR; if( m_PrevLineSmooth ) { _glEnable(GL_LINE_SMOOTH); CHECK_GL_ERROR; } else { _glDisable(GL_LINE_SMOOTH); CHECK_GL_ERROR; } if( m_PrevCullFace ) { _glEnable(GL_CULL_FACE); CHECK_GL_ERROR; } else { _glDisable(GL_CULL_FACE); CHECK_GL_ERROR; } if( m_PrevDepthTest ) { _glEnable(GL_DEPTH_TEST); CHECK_GL_ERROR; } else { _glDisable(GL_DEPTH_TEST); CHECK_GL_ERROR; } if( m_PrevBlend ) { _glEnable(GL_BLEND); CHECK_GL_ERROR; } else { _glDisable(GL_BLEND); CHECK_GL_ERROR; } if( m_PrevScissorTest ) { _glEnable(GL_SCISSOR_TEST); CHECK_GL_ERROR; } else { _glDisable(GL_SCISSOR_TEST); CHECK_GL_ERROR; } _glScissor(m_PrevScissorBox[0], m_PrevScissorBox[1], m_PrevScissorBox[2], m_PrevScissorBox[3]); CHECK_GL_ERROR; _glBlendFunc(m_PrevSrcBlend, m_PrevDstBlend); CHECK_GL_ERROR; _glBindTexture(GL_TEXTURE_2D, m_PrevTexture); CHECK_GL_ERROR; _glUseProgram(m_PrevProgramObject); CHECK_GL_ERROR; _glBindVertexArray(m_PrevVArray); CHECK_GL_ERROR; _glViewport(m_PrevViewport[0], m_PrevViewport[1], m_PrevViewport[2], m_PrevViewport[3]); CHECK_GL_ERROR; CHECK_GL_ERROR; } // --------------------------------------------------------------------------- bool CTwGraphOpenGLCore::IsDrawing() { return m_Drawing; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::Restore() { UnbindFont(m_FontTexID); m_FontTexID = 0; m_FontTex = NULL; } // --------------------------------------------------------------------------- static inline float ToNormScreenX(float x, int wndWidth) { return 2.0f*((float)x-0.5f)/wndWidth - 1.0f; } static inline float ToNormScreenY(float y, int wndHeight) { return 1.0f - 2.0f*((float)y-0.5f)/wndHeight; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased) { CHECK_GL_ERROR; assert(m_Drawing==true); //const GLfloat dx = +0.0f; const GLfloat dx = 0; //GLfloat dy = -0.2f; const GLfloat dy = -0.5f; if( _AntiAliased ) _glEnable(GL_LINE_SMOOTH); else _glDisable(GL_LINE_SMOOTH); _glBindVertexArray(m_LineRectVArray); GLfloat x0 = ToNormScreenX(_X0+dx + m_OffsetX, m_WndWidth); GLfloat y0 = ToNormScreenY(_Y0+dy + m_OffsetY, m_WndHeight); GLfloat x1 = ToNormScreenX(_X1+dx + m_OffsetX, m_WndWidth); GLfloat y1 = ToNormScreenY(_Y1+dy + m_OffsetY, m_WndHeight); GLfloat vertices[] = { x0,y0,0, x1,y1,0 }; _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectVertices); _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); _glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(0); color32 colors[] = { _Color0, _Color1 }; _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectColors); _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(colors), colors); _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(1); _glUseProgram(m_LineRectProgram); _glDrawArrays(GL_LINES, 0, 2); if( _AntiAliased ) _glDisable(GL_LINE_SMOOTH); CHECK_GL_ERROR; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11) { CHECK_GL_ERROR; assert(m_Drawing==true); // border adjustment if(_X0<_X1) ++_X1; else if(_X0>_X1) ++_X0; if(_Y0<_Y1) --_Y0; else if(_Y0>_Y1) --_Y1; _glBindVertexArray(m_LineRectVArray); GLfloat x0 = ToNormScreenX((float)_X0 + m_OffsetX, m_WndWidth); GLfloat y0 = ToNormScreenY((float)_Y0 + m_OffsetY, m_WndHeight); GLfloat x1 = ToNormScreenX((float)_X1 + m_OffsetX, m_WndWidth); GLfloat y1 = ToNormScreenY((float)_Y1 + m_OffsetY, m_WndHeight); GLfloat vertices[] = { x0,y0,0, x1,y0,0, x0,y1,0, x1,y1,0 }; _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectVertices); _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); _glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(0); GLuint colors[] = { _Color00, _Color10, _Color01, _Color11 }; _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectColors); _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(colors), colors); _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(1); _glUseProgram(m_LineRectProgram); _glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR; } // --------------------------------------------------------------------------- void *CTwGraphOpenGLCore::NewTextObj() { return new CTextObj; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DeleteTextObj(void *_TextObj) { assert(_TextObj!=NULL); delete static_cast(_TextObj); } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth) { assert(m_Drawing==true); assert(_TextObj!=NULL); assert(_Font!=NULL); if( _Font != m_FontTex ) { UnbindFont(m_FontTexID); m_FontTexID = BindFont(_Font); m_FontTex = _Font; } CTextObj *TextObj = static_cast(_TextObj); TextObj->m_TextVerts.resize(0); TextObj->m_TextUVs.resize(0); TextObj->m_BgVerts.resize(0); TextObj->m_Colors.resize(0); TextObj->m_BgColors.resize(0); int x, x1, y, y1, i, Len; unsigned char ch; const unsigned char *Text; color32 LineColor = COLOR32_RED; for( int Line=0; Line<_NbLines; ++Line ) { x = 0; y = Line * (_Font->m_CharHeight+_Sep); y1 = y+_Font->m_CharHeight; Len = (int)_TextLines[Line].length(); Text = (const unsigned char *)(_TextLines[Line].c_str()); if( _LineColors!=NULL ) LineColor = (_LineColors[Line]&0xff00ff00) | GLubyte(_LineColors[Line]>>16) | (GLubyte(_LineColors[Line])<<16); for( i=0; im_CharWidth[ch]; TextObj->m_TextVerts.push_back(Vec2(x , y )); TextObj->m_TextVerts.push_back(Vec2(x1, y )); TextObj->m_TextVerts.push_back(Vec2(x , y1)); TextObj->m_TextVerts.push_back(Vec2(x1, y )); TextObj->m_TextVerts.push_back(Vec2(x1, y1)); TextObj->m_TextVerts.push_back(Vec2(x , y1)); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV1[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch])); if( _LineColors!=NULL ) { TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); } x = x1; } if( _BgWidth>0 ) { TextObj->m_BgVerts.push_back(Vec2(-1 , y )); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y )); TextObj->m_BgVerts.push_back(Vec2(-1 , y1)); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y )); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y1)); TextObj->m_BgVerts.push_back(Vec2(-1 , y1)); if( _LineBgColors!=NULL ) { color32 LineBgColor = (_LineBgColors[Line]&0xff00ff00) | GLubyte(_LineBgColors[Line]>>16) | (GLubyte(_LineBgColors[Line])<<16); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); } } } } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor) { CHECK_GL_ERROR; assert(m_Drawing==true); assert(_TextObj!=NULL); CTextObj *TextObj = static_cast(_TextObj); if( TextObj->m_TextVerts.size()<4 && TextObj->m_BgVerts.size()<4 ) return; // nothing to draw // draw character background triangles if( (_BgColor!=0 || TextObj->m_BgColors.size()==TextObj->m_BgVerts.size()) && TextObj->m_BgVerts.size()>=4 ) { size_t numBgVerts = TextObj->m_BgVerts.size(); if( numBgVerts > m_TriBufferSize ) ResizeTriBuffers(numBgVerts + 2048); _glBindVertexArray(m_TriVArray); _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices); _glBufferSubData(GL_ARRAY_BUFFER, 0, numBgVerts*sizeof(Vec2), &(TextObj->m_BgVerts[0])); _glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(0); _glDisableVertexAttribArray(1); _glDisableVertexAttribArray(2); if( TextObj->m_BgColors.size()==TextObj->m_BgVerts.size() && _BgColor==0 ) { _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors); _glBufferSubData(GL_ARRAY_BUFFER, 0, numBgVerts*sizeof(color32), &(TextObj->m_BgColors[0])); _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(1); _glUseProgram(m_TriProgram); _glUniform2f(m_TriLocationOffset, (float)_X, (float)_Y); _glUniform2f(m_TriLocationWndSize, (float)m_WndWidth, (float)m_WndHeight); } else { _glUseProgram(m_TriUniProgram); _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); _glUniform2f(m_TriUniLocationOffset, (float)_X, (float)_Y); _glUniform2f(m_TriUniLocationWndSize, (float)m_WndWidth, (float)m_WndHeight); } _glDrawArrays(GL_TRIANGLES, 0, (GLsizei)TextObj->m_BgVerts.size()); } // draw character triangles if( TextObj->m_TextVerts.size()>=4 ) { _glActiveTexture(GL_TEXTURE0); _glBindTexture(GL_TEXTURE_2D, m_FontTexID); size_t numTextVerts = TextObj->m_TextVerts.size(); if( numTextVerts > m_TriBufferSize ) ResizeTriBuffers(numTextVerts + 2048); _glBindVertexArray(m_TriVArray); _glDisableVertexAttribArray(2); _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices); _glBufferSubData(GL_ARRAY_BUFFER, 0, numTextVerts*sizeof(Vec2), &(TextObj->m_TextVerts[0])); _glVertexAttribPointer(0, 2, GL_FLOAT, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(0); _glBindBuffer(GL_ARRAY_BUFFER, m_TriUVs); _glBufferSubData(GL_ARRAY_BUFFER, 0, numTextVerts*sizeof(Vec2), &(TextObj->m_TextUVs[0])); _glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL); _glEnableVertexAttribArray(1); if( TextObj->m_Colors.size()==TextObj->m_TextVerts.size() && _Color==0 ) { _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors); _glBufferSubData(GL_ARRAY_BUFFER, 0, numTextVerts*sizeof(color32), &(TextObj->m_Colors[0])); _glVertexAttribPointer(2, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(2); _glUseProgram(m_TriTexProgram); _glUniform2f(m_TriTexLocationOffset, (float)_X, (float)_Y); _glUniform2f(m_TriTexLocationWndSize, (float)m_WndWidth, (float)m_WndHeight); _glUniform1i(m_TriTexLocationTexture, 0); } else { _glUseProgram(m_TriTexUniProgram); _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); _glUniform2f(m_TriTexUniLocationOffset, (float)_X, (float)_Y); _glUniform2f(m_TriTexUniLocationWndSize, (float)m_WndWidth, (float)m_WndHeight); _glUniform1i(m_TriTexUniLocationTexture, 0); } _glDrawArrays(GL_TRIANGLES, 0, (GLsizei)TextObj->m_TextVerts.size()); } CHECK_GL_ERROR; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY) { // glViewport impacts the NDC; use glScissor instead m_OffsetX = _X0 + _OffsetX; m_OffsetY = _Y0 + _OffsetY; SetScissor(_X0, _Y0, _Width, _Height); } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::RestoreViewport() { m_OffsetX = m_OffsetY = 0; SetScissor(0, 0, 0, 0); } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::SetScissor(int _X0, int _Y0, int _Width, int _Height) { if( _Width>0 && _Height>0 ) { _glScissor(_X0-1, m_WndHeight-_Y0-_Height, _Width-1, _Height); _glEnable(GL_SCISSOR_TEST); } else _glDisable(GL_SCISSOR_TEST); } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode) { assert(m_Drawing==true); const GLfloat dx = +0.0f; const GLfloat dy = +0.0f; // Backup states GLint prevCullFaceMode, prevFrontFace; _glGetIntegerv(GL_CULL_FACE_MODE, &prevCullFaceMode); _glGetIntegerv(GL_FRONT_FACE, &prevFrontFace); GLboolean prevCullEnable = _glIsEnabled(GL_CULL_FACE); _glCullFace(GL_BACK); _glEnable(GL_CULL_FACE); if( _CullMode==CULL_CW ) _glFrontFace(GL_CCW); else if( _CullMode==CULL_CCW ) _glFrontFace(GL_CW); else _glDisable(GL_CULL_FACE); _glUseProgram(m_TriProgram); _glBindVertexArray(m_TriVArray); _glUniform2f(m_TriLocationOffset, (float)m_OffsetX+dx, (float)m_OffsetY+dy); _glUniform2f(m_TriLocationWndSize, (float)m_WndWidth, (float)m_WndHeight); _glDisableVertexAttribArray(2); size_t numVerts = 3*_NumTriangles; if( numVerts > m_TriBufferSize ) ResizeTriBuffers(numVerts + 2048); _glBindBuffer(GL_ARRAY_BUFFER, m_TriVertices); _glBufferSubData(GL_ARRAY_BUFFER, 0, numVerts*2*sizeof(int), _Vertices); _glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, NULL); _glEnableVertexAttribArray(0); _glBindBuffer(GL_ARRAY_BUFFER, m_TriColors); _glBufferSubData(GL_ARRAY_BUFFER, 0, numVerts*sizeof(color32), _Colors); _glVertexAttribPointer(1, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(1); _glDrawArrays(GL_TRIANGLES, 0, (GLsizei)numVerts); // Reset states _glCullFace(prevCullFaceMode); _glFrontFace(prevFrontFace); if( prevCullEnable ) _glEnable(GL_CULL_FACE); else _glDisable(GL_CULL_FACE); CHECK_GL_ERROR; } // ---------------------------------------------------------------------------