Files
game-physics/AntTweakBar/src/TwOpenGLCore.cpp
2017-10-11 15:01:05 +02:00

934 lines
33 KiB
C++

// ---------------------------------------------------------------------------
//
// @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 <GL3/gl3.h> ////
#define ANT_OGL_HEADER_INCLUDED ////
*/
#if defined ANT_OSX
# include <OpenGL/gl3.h>
# 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<CTextObj *>(_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<CTextObj *>(_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; i<Len; ++i )
{
ch = Text[i];
x1 = x + _Font->m_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<CTextObj *>(_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;
}
// ---------------------------------------------------------------------------