Change imgui library and other modifications in testbed application
This commit is contained in:
parent
39b7883462
commit
be5d635e81
|
@ -19,6 +19,14 @@ FILE(COPY "shaders/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/shaders/")
|
|||
# Copy the meshes used for the demo into the build directory
|
||||
FILE(COPY "meshes/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/meshes/")
|
||||
|
||||
# Copy the fonts used for the GUI into the build directory
|
||||
FILE(COPY "imgui/DroidSans.ttf" DESTINATION "${EXECUTABLE_OUTPUT_PATH}")
|
||||
|
||||
# Enable C++11 features
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++0x")
|
||||
|
||||
#ADD_DEFINITIONS(-DGL3)
|
||||
|
||||
# Headers
|
||||
INCLUDE_DIRECTORIES("src/" "opengl-framework/src/" "glfw/include/" "common/" "scenes/" "imgui/")
|
||||
|
||||
|
@ -37,11 +45,10 @@ SET(TESTBED_SOURCES
|
|||
|
||||
# IMGUI source files
|
||||
SET(IMGUI_SOURCES
|
||||
imgui/imgui.h
|
||||
imgui/imgui.cpp
|
||||
imgui/imconfig.h
|
||||
imgui/stb_rect_pack.h
|
||||
imgui/stb_textedit.h
|
||||
imgui/imgui.h
|
||||
imgui/imguiRenderGL3.h
|
||||
imgui/imguiRenderGL3.cpp
|
||||
imgui/stb_truetype.h
|
||||
)
|
||||
|
||||
|
|
BIN
testbed/imgui/DroidSans.ttf
Normal file
BIN
testbed/imgui/DroidSans.ttf
Normal file
Binary file not shown.
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2015 Omar Cornut and ImGui contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,58 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// USER IMPLEMENTATION
|
||||
// This file contains compile-time options for ImGui.
|
||||
// Other options (memory allocation overrides, callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO().
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define your own ImVector<> type if you don't want to use the provided implementation defined in imgui.h
|
||||
//#include <vector>
|
||||
//#define ImVector std::vector
|
||||
//#define ImVector MyVector
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Include imgui_user.inl at the end of imgui.cpp so you can include code that extends ImGui using its private data/functions.
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_INL
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Don't implement default handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS
|
||||
|
||||
//---- Don't implement help and test window functionality (ShowUserGuide()/ShowStyleEditor()/ShowTestWindow() methods will be empty)
|
||||
//#define IMGUI_DISABLE_TEST_WINDOWS
|
||||
|
||||
//---- Implement STB libraries in a namespace to avoid conflicts
|
||||
//#define IMGUI_STB_NAMESPACE ImStb
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
|
||||
//---- Freely implement extra functions within the ImGui:: namespace.
|
||||
//---- Declare helpers or widgets implemented in imgui_user.inl or elsewhere, so end-user doesn't need to include multiple files.
|
||||
//---- e.g. you can create variants of the ImGui::Value() helper for your low-level math types, or your own widgets/helpers.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void Value(const char* prefix, const MyVec2& v, const char* float_format = NULL);
|
||||
void Value(const char* prefix, const MyVec4& v, const char* float_format = NULL);
|
||||
}
|
||||
*/
|
||||
|
12142
testbed/imgui/imgui.cpp
12142
testbed/imgui/imgui.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
489
testbed/imgui/imguiRenderGL2.cpp
Normal file
489
testbed/imgui/imguiRenderGL2.cpp
Normal file
|
@ -0,0 +1,489 @@
|
|||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
// Source altered and distributed from https://github.com/AdrienHerubel/imguir
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
/*#ifdef __APPLE__
|
||||
#include <OpenGL/gl2.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
*/
|
||||
|
||||
// Some math headers don't have PI defined.
|
||||
static const float PI = 3.14159265f;
|
||||
|
||||
void imguifree(void* ptr, void* userptr);
|
||||
void* imguimalloc(size_t size, void* userptr);
|
||||
|
||||
#define STBTT_malloc(x,y) imguimalloc(x,y)
|
||||
#define STBTT_free(x,y) imguifree(x,y)
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
|
||||
void imguifree(void* ptr, void* /*userptr*/)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void* imguimalloc(size_t size, void* /*userptr*/)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static const unsigned TEMP_COORD_COUNT = 100;
|
||||
static float g_tempCoords[TEMP_COORD_COUNT*2];
|
||||
static float g_tempNormals[TEMP_COORD_COUNT*2];
|
||||
|
||||
static const int CIRCLE_VERTS = 8*4;
|
||||
static float g_circleVerts[CIRCLE_VERTS*2];
|
||||
|
||||
static stbtt_bakedchar g_cdata[96]; // ASCII 32..126 is 95 glyphs
|
||||
static GLuint g_ftex = 0;
|
||||
|
||||
inline unsigned int RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
return (r) | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
|
||||
static void drawPolygon(const float* coords, unsigned numCoords, float r, unsigned int col)
|
||||
{
|
||||
if (numCoords > TEMP_COORD_COUNT) numCoords = TEMP_COORD_COUNT;
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
const float* v0 = &coords[j*2];
|
||||
const float* v1 = &coords[i*2];
|
||||
float dx = v1[0] - v0[0];
|
||||
float dy = v1[1] - v0[1];
|
||||
float d = sqrtf(dx*dx+dy*dy);
|
||||
if (d > 0)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
dx *= d;
|
||||
dy *= d;
|
||||
}
|
||||
g_tempNormals[j*2+0] = dy;
|
||||
g_tempNormals[j*2+1] = -dx;
|
||||
}
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
float dlx0 = g_tempNormals[j*2+0];
|
||||
float dly0 = g_tempNormals[j*2+1];
|
||||
float dlx1 = g_tempNormals[i*2+0];
|
||||
float dly1 = g_tempNormals[i*2+1];
|
||||
float dmx = (dlx0 + dlx1) * 0.5f;
|
||||
float dmy = (dly0 + dly1) * 0.5f;
|
||||
float dmr2 = dmx*dmx + dmy*dmy;
|
||||
if (dmr2 > 0.000001f)
|
||||
{
|
||||
float scale = 1.0f / dmr2;
|
||||
if (scale > 10.0f) scale = 10.0f;
|
||||
dmx *= scale;
|
||||
dmy *= scale;
|
||||
}
|
||||
g_tempCoords[i*2+0] = coords[i*2+0]+dmx*r;
|
||||
g_tempCoords[i*2+1] = coords[i*2+1]+dmy*r;
|
||||
}
|
||||
|
||||
unsigned int colTrans = RGBA(col&0xff, (col>>8)&0xff, (col>>16)&0xff, 0);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
glColor4ubv((GLubyte*)&col);
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
glVertex2fv(&coords[i*2]);
|
||||
glVertex2fv(&coords[j*2]);
|
||||
glColor4ubv((GLubyte*)&colTrans);
|
||||
glVertex2fv(&g_tempCoords[j*2]);
|
||||
|
||||
glVertex2fv(&g_tempCoords[j*2]);
|
||||
glVertex2fv(&g_tempCoords[i*2]);
|
||||
|
||||
glColor4ubv((GLubyte*)&col);
|
||||
glVertex2fv(&coords[i*2]);
|
||||
}
|
||||
|
||||
glColor4ubv((GLubyte*)&col);
|
||||
for (unsigned i = 2; i < numCoords; ++i)
|
||||
{
|
||||
glVertex2fv(&coords[0]);
|
||||
glVertex2fv(&coords[(i-1)*2]);
|
||||
glVertex2fv(&coords[i*2]);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static void drawRect(float x, float y, float w, float h, float fth, unsigned int col)
|
||||
{
|
||||
float verts[4*2] =
|
||||
{
|
||||
x+0.5f, y+0.5f,
|
||||
x+w-0.5f, y+0.5f,
|
||||
x+w-0.5f, y+h-0.5f,
|
||||
x+0.5f, y+h-0.5f,
|
||||
};
|
||||
drawPolygon(verts, 4, fth, col);
|
||||
}
|
||||
|
||||
/*
|
||||
static void drawEllipse(float x, float y, float w, float h, float fth, unsigned int col)
|
||||
{
|
||||
float verts[CIRCLE_VERTS*2];
|
||||
const float* cverts = g_circleVerts;
|
||||
float* v = verts;
|
||||
|
||||
for (int i = 0; i < CIRCLE_VERTS; ++i)
|
||||
{
|
||||
*v++ = x + cverts[i*2]*w;
|
||||
*v++ = y + cverts[i*2+1]*h;
|
||||
}
|
||||
|
||||
drawPolygon(verts, CIRCLE_VERTS, fth, col);
|
||||
}
|
||||
*/
|
||||
|
||||
static void drawRoundedRect(float x, float y, float w, float h, float r, float fth, unsigned int col)
|
||||
{
|
||||
const unsigned n = CIRCLE_VERTS/4;
|
||||
float verts[(n+1)*4*2];
|
||||
const float* cverts = g_circleVerts;
|
||||
float* v = verts;
|
||||
|
||||
for (unsigned i = 0; i <= n; ++i)
|
||||
{
|
||||
*v++ = x+w-r + cverts[i*2]*r;
|
||||
*v++ = y+h-r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n; i <= n*2; ++i)
|
||||
{
|
||||
*v++ = x+r + cverts[i*2]*r;
|
||||
*v++ = y+h-r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n*2; i <= n*3; ++i)
|
||||
{
|
||||
*v++ = x+r + cverts[i*2]*r;
|
||||
*v++ = y+r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n*3; i < n*4; ++i)
|
||||
{
|
||||
*v++ = x+w-r + cverts[i*2]*r;
|
||||
*v++ = y+r + cverts[i*2+1]*r;
|
||||
}
|
||||
*v++ = x+w-r + cverts[0]*r;
|
||||
*v++ = y+r + cverts[1]*r;
|
||||
|
||||
drawPolygon(verts, (n+1)*4, fth, col);
|
||||
}
|
||||
|
||||
|
||||
static void drawLine(float x0, float y0, float x1, float y1, float r, float fth, unsigned int col)
|
||||
{
|
||||
float dx = x1-x0;
|
||||
float dy = y1-y0;
|
||||
float d = sqrtf(dx*dx+dy*dy);
|
||||
if (d > 0.0001f)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
dx *= d;
|
||||
dy *= d;
|
||||
}
|
||||
float nx = dy;
|
||||
float ny = -dx;
|
||||
float verts[4*2];
|
||||
r -= fth;
|
||||
r *= 0.5f;
|
||||
if (r < 0.01f) r = 0.01f;
|
||||
dx *= r;
|
||||
dy *= r;
|
||||
nx *= r;
|
||||
ny *= r;
|
||||
|
||||
verts[0] = x0-dx-nx;
|
||||
verts[1] = y0-dy-ny;
|
||||
|
||||
verts[2] = x0-dx+nx;
|
||||
verts[3] = y0-dy+ny;
|
||||
|
||||
verts[4] = x1+dx+nx;
|
||||
verts[5] = y1+dy+ny;
|
||||
|
||||
verts[6] = x1+dx-nx;
|
||||
verts[7] = y1+dy-ny;
|
||||
|
||||
drawPolygon(verts, 4, fth, col);
|
||||
}
|
||||
|
||||
|
||||
bool imguiRenderGLInit(const char* fontpath)
|
||||
{
|
||||
for (int i = 0; i < CIRCLE_VERTS; ++i)
|
||||
{
|
||||
float a = (float)i/(float)CIRCLE_VERTS * PI*2;
|
||||
g_circleVerts[i*2+0] = cosf(a);
|
||||
g_circleVerts[i*2+1] = sinf(a);
|
||||
}
|
||||
|
||||
// Load font.
|
||||
FILE* fp = fopen(fontpath, "rb");
|
||||
if (!fp) return false;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
unsigned char* ttfBuffer = (unsigned char*)malloc(size);
|
||||
if (!ttfBuffer)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
fread(ttfBuffer, 1, size, fp);
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
|
||||
unsigned char* bmap = (unsigned char*)malloc(512*512);
|
||||
if (!bmap)
|
||||
{
|
||||
free(ttfBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
stbtt_BakeFontBitmap(ttfBuffer,0, 15.0f, bmap,512,512, 32,96, g_cdata);
|
||||
|
||||
// can free ttf_buffer at this point
|
||||
glGenTextures(1, &g_ftex);
|
||||
glBindTexture(GL_TEXTURE_2D, g_ftex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bmap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
free(ttfBuffer);
|
||||
free(bmap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void imguiRenderGLDestroy()
|
||||
{
|
||||
if (g_ftex)
|
||||
{
|
||||
glDeleteTextures(1, &g_ftex);
|
||||
g_ftex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void getBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index,
|
||||
float *xpos, float *ypos, stbtt_aligned_quad *q)
|
||||
{
|
||||
stbtt_bakedchar *b = chardata + char_index;
|
||||
int round_x = STBTT_ifloor(*xpos + b->xoff);
|
||||
int round_y = STBTT_ifloor(*ypos - b->yoff);
|
||||
|
||||
q->x0 = (float)round_x;
|
||||
q->y0 = (float)round_y;
|
||||
q->x1 = (float)round_x + b->x1 - b->x0;
|
||||
q->y1 = (float)round_y - b->y1 + b->y0;
|
||||
|
||||
q->s0 = b->x0 / (float)pw;
|
||||
q->t0 = b->y0 / (float)pw;
|
||||
q->s1 = b->x1 / (float)ph;
|
||||
q->t1 = b->y1 / (float)ph;
|
||||
|
||||
*xpos += b->xadvance;
|
||||
}
|
||||
|
||||
static const float g_tabStops[4] = {150, 210, 270, 330};
|
||||
|
||||
static float getTextLength(stbtt_bakedchar *chardata, const char* text)
|
||||
{
|
||||
float xpos = 0;
|
||||
float len = 0;
|
||||
while (*text)
|
||||
{
|
||||
int c = (unsigned char)*text;
|
||||
if (c == '\t')
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (xpos < g_tabStops[i])
|
||||
{
|
||||
xpos = g_tabStops[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c >= 32 && c < 128)
|
||||
{
|
||||
stbtt_bakedchar *b = chardata + c-32;
|
||||
int round_x = STBTT_ifloor((xpos + b->xoff) + 0.5);
|
||||
len = round_x + b->x1 - b->x0 + 0.5f;
|
||||
xpos += b->xadvance;
|
||||
}
|
||||
++text;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void drawText(float x, float y, const char *text, int align, unsigned int col)
|
||||
{
|
||||
if (!g_ftex) return;
|
||||
if (!text) return;
|
||||
|
||||
if (align == IMGUI_ALIGN_CENTER)
|
||||
x -= getTextLength(g_cdata, text)/2;
|
||||
else if (align == IMGUI_ALIGN_RIGHT)
|
||||
x -= getTextLength(g_cdata, text);
|
||||
|
||||
glColor4ub(col&0xff, (col>>8)&0xff, (col>>16)&0xff, (col>>24)&0xff);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// assume orthographic projection with units = screen pixels, origin at top left
|
||||
glBindTexture(GL_TEXTURE_2D, g_ftex);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
const float ox = x;
|
||||
|
||||
while (*text)
|
||||
{
|
||||
int c = (unsigned char)*text;
|
||||
if (c == '\t')
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (x < g_tabStops[i]+ox)
|
||||
{
|
||||
x = g_tabStops[i]+ox;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c >= 32 && c < 128)
|
||||
{
|
||||
stbtt_aligned_quad q;
|
||||
getBakedQuad(g_cdata, 512,512, c-32, &x,&y,&q);
|
||||
|
||||
glTexCoord2f(q.s0, q.t0);
|
||||
glVertex2f(q.x0, q.y0);
|
||||
glTexCoord2f(q.s1, q.t1);
|
||||
glVertex2f(q.x1, q.y1);
|
||||
glTexCoord2f(q.s1, q.t0);
|
||||
glVertex2f(q.x1, q.y0);
|
||||
|
||||
glTexCoord2f(q.s0, q.t0);
|
||||
glVertex2f(q.x0, q.y0);
|
||||
glTexCoord2f(q.s0, q.t1);
|
||||
glVertex2f(q.x0, q.y1);
|
||||
glTexCoord2f(q.s1, q.t1);
|
||||
glVertex2f(q.x1, q.y1);
|
||||
}
|
||||
++text;
|
||||
}
|
||||
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void imguiRenderGLDraw(int width, int height)
|
||||
{
|
||||
const imguiGfxCmd* q = imguiGetRenderQueue();
|
||||
int nq = imguiGetRenderQueueSize();
|
||||
|
||||
const float s = 1.0f/8.0f;
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
for (int i = 0; i < nq; ++i)
|
||||
{
|
||||
const imguiGfxCmd& cmd = q[i];
|
||||
if (cmd.type == IMGUI_GFXCMD_RECT)
|
||||
{
|
||||
if (cmd.rect.r == 0)
|
||||
{
|
||||
drawRect((float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.w*s-1, (float)cmd.rect.h*s-1,
|
||||
1.0f, cmd.col);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawRoundedRect((float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.w*s-1, (float)cmd.rect.h*s-1,
|
||||
(float)cmd.rect.r*s, 1.0f, cmd.col);
|
||||
}
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_LINE)
|
||||
{
|
||||
drawLine(cmd.line.x0*s, cmd.line.y0*s, cmd.line.x1*s, cmd.line.y1*s, cmd.line.r*s, 1.0f, cmd.col);
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_TRIANGLE)
|
||||
{
|
||||
if (cmd.flags == 1)
|
||||
{
|
||||
const float verts[3*2] =
|
||||
{
|
||||
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s/2-0.5f,
|
||||
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
|
||||
};
|
||||
drawPolygon(verts, 3, 1.0f, cmd.col);
|
||||
}
|
||||
if (cmd.flags == 2)
|
||||
{
|
||||
const float verts[3*2] =
|
||||
{
|
||||
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
|
||||
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s/2-0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
|
||||
};
|
||||
drawPolygon(verts, 3, 1.0f, cmd.col);
|
||||
}
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_TEXT)
|
||||
{
|
||||
drawText(cmd.text.x, cmd.text.y, cmd.text.text, cmd.text.align, cmd.col);
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_SCISSOR)
|
||||
{
|
||||
if (cmd.flags)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
29
testbed/imgui/imguiRenderGL2.h
Normal file
29
testbed/imgui/imguiRenderGL2.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
// Source altered and distributed from https://github.com/AdrienHerubel/imguir
|
||||
|
||||
|
||||
#ifndef IMGUI_RENDER_GL_H
|
||||
#define IMGUI_RENDER_GL_H
|
||||
|
||||
bool imguiRenderGLInit(const char* fontpath);
|
||||
void imguiRenderGLDestroy();
|
||||
void imguiRenderGLDraw(int width, int height);
|
||||
|
||||
#endif // IMGUI_RENDER_GL_H
|
695
testbed/imgui/imguiRenderGL3.cpp
Normal file
695
testbed/imgui/imguiRenderGL3.cpp
Normal file
|
@ -0,0 +1,695 @@
|
|||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
// Source altered and distributed from https://github.com/AdrienHerubel/imgui
|
||||
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <GL/glew.h>
|
||||
/*#ifdef __APPLE__
|
||||
#include <OpenGL/gl3.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
*/
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
// Some math headers don't have PI defined.
|
||||
static const float PI = 3.14159265f;
|
||||
|
||||
void imguifree(void* ptr, void* userptr);
|
||||
void* imguimalloc(size_t size, void* userptr);
|
||||
|
||||
#define STBTT_malloc(x,y) imguimalloc(x,y)
|
||||
#define STBTT_free(x,y) imguifree(x,y)
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
|
||||
void imguifree(void* ptr, void* /*userptr*/)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void* imguimalloc(size_t size, void* /*userptr*/)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static const unsigned TEMP_COORD_COUNT = 100;
|
||||
static float g_tempCoords[TEMP_COORD_COUNT*2];
|
||||
static float g_tempNormals[TEMP_COORD_COUNT*2];
|
||||
static float g_tempVertices[TEMP_COORD_COUNT * 12 + (TEMP_COORD_COUNT - 2) * 6];
|
||||
static float g_tempTextureCoords[TEMP_COORD_COUNT * 12 + (TEMP_COORD_COUNT - 2) * 6];
|
||||
static float g_tempColors[TEMP_COORD_COUNT * 24 + (TEMP_COORD_COUNT - 2) * 12];
|
||||
|
||||
static const int CIRCLE_VERTS = 8*4;
|
||||
static float g_circleVerts[CIRCLE_VERTS*2];
|
||||
|
||||
static stbtt_bakedchar g_cdata[96]; // ASCII 32..126 is 95 glyphs
|
||||
static GLuint g_ftex = 0;
|
||||
static GLuint g_whitetex = 0;
|
||||
static GLuint g_vao = 0;
|
||||
static GLuint g_vbos[3] = {0, 0, 0};
|
||||
static GLuint g_program = 0;
|
||||
static GLuint g_programViewportLocation = 0;
|
||||
static GLuint g_programTextureLocation = 0;
|
||||
|
||||
inline unsigned int RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
return (r) | (g << 8) | (b << 16) | (a << 24);
|
||||
}
|
||||
|
||||
static void drawPolygon(const float* coords, unsigned numCoords, float r, unsigned int col)
|
||||
{
|
||||
if (numCoords > TEMP_COORD_COUNT) numCoords = TEMP_COORD_COUNT;
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
const float* v0 = &coords[j*2];
|
||||
const float* v1 = &coords[i*2];
|
||||
float dx = v1[0] - v0[0];
|
||||
float dy = v1[1] - v0[1];
|
||||
float d = sqrtf(dx*dx+dy*dy);
|
||||
if (d > 0)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
dx *= d;
|
||||
dy *= d;
|
||||
}
|
||||
g_tempNormals[j*2+0] = dy;
|
||||
g_tempNormals[j*2+1] = -dx;
|
||||
}
|
||||
|
||||
float colf[4] = { (float) (col&0xff) / 255.f, (float) ((col>>8)&0xff) / 255.f, (float) ((col>>16)&0xff) / 255.f, (float) ((col>>24)&0xff) / 255.f};
|
||||
float colTransf[4] = { (float) (col&0xff) / 255.f, (float) ((col>>8)&0xff) / 255.f, (float) ((col>>16)&0xff) / 255.f, 0};
|
||||
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
float dlx0 = g_tempNormals[j*2+0];
|
||||
float dly0 = g_tempNormals[j*2+1];
|
||||
float dlx1 = g_tempNormals[i*2+0];
|
||||
float dly1 = g_tempNormals[i*2+1];
|
||||
float dmx = (dlx0 + dlx1) * 0.5f;
|
||||
float dmy = (dly0 + dly1) * 0.5f;
|
||||
float dmr2 = dmx*dmx + dmy*dmy;
|
||||
if (dmr2 > 0.000001f)
|
||||
{
|
||||
float scale = 1.0f / dmr2;
|
||||
if (scale > 10.0f) scale = 10.0f;
|
||||
dmx *= scale;
|
||||
dmy *= scale;
|
||||
}
|
||||
g_tempCoords[i*2+0] = coords[i*2+0]+dmx*r;
|
||||
g_tempCoords[i*2+1] = coords[i*2+1]+dmy*r;
|
||||
}
|
||||
|
||||
int vSize = numCoords * 12 + (numCoords - 2) * 6;
|
||||
int uvSize = numCoords * 2 * 6 + (numCoords - 2) * 2 * 3;
|
||||
int cSize = numCoords * 4 * 6 + (numCoords - 2) * 4 * 3;
|
||||
float * v = g_tempVertices;
|
||||
float * uv = g_tempTextureCoords;
|
||||
memset(uv, 0, uvSize * sizeof(float));
|
||||
float * c = g_tempColors;
|
||||
memset(c, 1, cSize * sizeof(float));
|
||||
|
||||
float * ptrV = v;
|
||||
float * ptrC = c;
|
||||
for (unsigned i = 0, j = numCoords-1; i < numCoords; j=i++)
|
||||
{
|
||||
*ptrV = coords[i*2];
|
||||
*(ptrV+1) = coords[i*2 + 1];
|
||||
ptrV += 2;
|
||||
*ptrV = coords[j*2];
|
||||
*(ptrV+1) = coords[j*2 + 1];
|
||||
ptrV += 2;
|
||||
*ptrV = g_tempCoords[j*2];
|
||||
*(ptrV+1) = g_tempCoords[j*2 + 1];
|
||||
ptrV += 2;
|
||||
*ptrV = g_tempCoords[j*2];
|
||||
*(ptrV+1) = g_tempCoords[j*2 + 1];
|
||||
ptrV += 2;
|
||||
*ptrV = g_tempCoords[i*2];
|
||||
*(ptrV+1) = g_tempCoords[i*2 + 1];
|
||||
ptrV += 2;
|
||||
*ptrV = coords[i*2];
|
||||
*(ptrV+1) = coords[i*2 + 1];
|
||||
ptrV += 2;
|
||||
|
||||
*ptrC = colf[0];
|
||||
*(ptrC+1) = colf[1];
|
||||
*(ptrC+2) = colf[2];
|
||||
*(ptrC+3) = colf[3];
|
||||
ptrC += 4;
|
||||
*ptrC = colf[0];
|
||||
*(ptrC+1) = colf[1];
|
||||
*(ptrC+2) = colf[2];
|
||||
*(ptrC+3) = colf[3];
|
||||
ptrC += 4;
|
||||
*ptrC = colTransf[0];
|
||||
*(ptrC+1) = colTransf[1];
|
||||
*(ptrC+2) = colTransf[2];
|
||||
*(ptrC+3) = colTransf[3];
|
||||
ptrC += 4;
|
||||
*ptrC = colTransf[0];
|
||||
*(ptrC+1) = colTransf[1];
|
||||
*(ptrC+2) = colTransf[2];
|
||||
*(ptrC+3) = colTransf[3];
|
||||
ptrC += 4;
|
||||
*ptrC = colTransf[0];
|
||||
*(ptrC+1) = colTransf[1];
|
||||
*(ptrC+2) = colTransf[2];
|
||||
*(ptrC+3) = colTransf[3];
|
||||
ptrC += 4;
|
||||
*ptrC = colf[0];
|
||||
*(ptrC+1) = colf[1];
|
||||
*(ptrC+2) = colf[2];
|
||||
*(ptrC+3) = colf[3];
|
||||
ptrC += 4;
|
||||
}
|
||||
|
||||
for (unsigned i = 2; i < numCoords; ++i)
|
||||
{
|
||||
*ptrV = coords[0];
|
||||
*(ptrV+1) = coords[1];
|
||||
ptrV += 2;
|
||||
*ptrV = coords[(i-1)*2];
|
||||
*(ptrV+1) = coords[(i-1)*2+1];
|
||||
ptrV += 2;
|
||||
*ptrV = coords[i*2];
|
||||
*(ptrV+1) = coords[i*2 + 1];
|
||||
ptrV += 2;
|
||||
|
||||
*ptrC = colf[0];
|
||||
*(ptrC+1) = colf[1];
|
||||
*(ptrC+2) = colf[2];
|
||||
*(ptrC+3) = colf[3];
|
||||
ptrC += 4;
|
||||
*ptrC = colf[0];
|
||||
*(ptrC+1) = colf[1];
|
||||
*(ptrC+2) = colf[2];
|
||||
*(ptrC+3) = colf[3];
|
||||
ptrC += 4;
|
||||
*ptrC = colf[0];
|
||||
*(ptrC+1) = colf[1];
|
||||
*(ptrC+2) = colf[2];
|
||||
*(ptrC+3) = colf[3];
|
||||
ptrC += 4;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, g_whitetex);
|
||||
|
||||
glBindVertexArray(g_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, vSize*sizeof(float), v, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[1]);
|
||||
glBufferData(GL_ARRAY_BUFFER, uvSize*sizeof(float), uv, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[2]);
|
||||
glBufferData(GL_ARRAY_BUFFER, cSize*sizeof(float), c, GL_STATIC_DRAW);
|
||||
glDrawArrays(GL_TRIANGLES, 0, (numCoords * 2 + numCoords - 2)*3);
|
||||
|
||||
}
|
||||
|
||||
static void drawRect(float x, float y, float w, float h, float fth, unsigned int col)
|
||||
{
|
||||
float verts[4*2] =
|
||||
{
|
||||
x+0.5f, y+0.5f,
|
||||
x+w-0.5f, y+0.5f,
|
||||
x+w-0.5f, y+h-0.5f,
|
||||
x+0.5f, y+h-0.5f,
|
||||
};
|
||||
drawPolygon(verts, 4, fth, col);
|
||||
}
|
||||
|
||||
/*
|
||||
static void drawEllipse(float x, float y, float w, float h, float fth, unsigned int col)
|
||||
{
|
||||
float verts[CIRCLE_VERTS*2];
|
||||
const float* cverts = g_circleVerts;
|
||||
float* v = verts;
|
||||
|
||||
for (int i = 0; i < CIRCLE_VERTS; ++i)
|
||||
{
|
||||
*v++ = x + cverts[i*2]*w;
|
||||
*v++ = y + cverts[i*2+1]*h;
|
||||
}
|
||||
|
||||
drawPolygon(verts, CIRCLE_VERTS, fth, col);
|
||||
}
|
||||
*/
|
||||
|
||||
static void drawRoundedRect(float x, float y, float w, float h, float r, float fth, unsigned int col)
|
||||
{
|
||||
const unsigned n = CIRCLE_VERTS/4;
|
||||
float verts[(n+1)*4*2];
|
||||
const float* cverts = g_circleVerts;
|
||||
float* v = verts;
|
||||
|
||||
for (unsigned i = 0; i <= n; ++i)
|
||||
{
|
||||
*v++ = x+w-r + cverts[i*2]*r;
|
||||
*v++ = y+h-r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n; i <= n*2; ++i)
|
||||
{
|
||||
*v++ = x+r + cverts[i*2]*r;
|
||||
*v++ = y+h-r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n*2; i <= n*3; ++i)
|
||||
{
|
||||
*v++ = x+r + cverts[i*2]*r;
|
||||
*v++ = y+r + cverts[i*2+1]*r;
|
||||
}
|
||||
|
||||
for (unsigned i = n*3; i < n*4; ++i)
|
||||
{
|
||||
*v++ = x+w-r + cverts[i*2]*r;
|
||||
*v++ = y+r + cverts[i*2+1]*r;
|
||||
}
|
||||
*v++ = x+w-r + cverts[0]*r;
|
||||
*v++ = y+r + cverts[1]*r;
|
||||
|
||||
drawPolygon(verts, (n+1)*4, fth, col);
|
||||
}
|
||||
|
||||
|
||||
static void drawLine(float x0, float y0, float x1, float y1, float r, float fth, unsigned int col)
|
||||
{
|
||||
float dx = x1-x0;
|
||||
float dy = y1-y0;
|
||||
float d = sqrtf(dx*dx+dy*dy);
|
||||
if (d > 0.0001f)
|
||||
{
|
||||
d = 1.0f/d;
|
||||
dx *= d;
|
||||
dy *= d;
|
||||
}
|
||||
float nx = dy;
|
||||
float ny = -dx;
|
||||
float verts[4*2];
|
||||
r -= fth;
|
||||
r *= 0.5f;
|
||||
if (r < 0.01f) r = 0.01f;
|
||||
dx *= r;
|
||||
dy *= r;
|
||||
nx *= r;
|
||||
ny *= r;
|
||||
|
||||
verts[0] = x0-dx-nx;
|
||||
verts[1] = y0-dy-ny;
|
||||
|
||||
verts[2] = x0-dx+nx;
|
||||
verts[3] = y0-dy+ny;
|
||||
|
||||
verts[4] = x1+dx+nx;
|
||||
verts[5] = y1+dy+ny;
|
||||
|
||||
verts[6] = x1+dx-nx;
|
||||
verts[7] = y1+dy-ny;
|
||||
|
||||
drawPolygon(verts, 4, fth, col);
|
||||
}
|
||||
|
||||
|
||||
bool imguiRenderGLInit(const char* fontpath)
|
||||
{
|
||||
for (int i = 0; i < CIRCLE_VERTS; ++i)
|
||||
{
|
||||
float a = (float)i/(float)CIRCLE_VERTS * PI*2;
|
||||
g_circleVerts[i*2+0] = cosf(a);
|
||||
g_circleVerts[i*2+1] = sinf(a);
|
||||
}
|
||||
|
||||
// Load font.
|
||||
FILE* fp = fopen(fontpath, "rb");
|
||||
if (!fp) return false;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
unsigned char* ttfBuffer = (unsigned char*)malloc(size);
|
||||
if (!ttfBuffer)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
fread(ttfBuffer, 1, size, fp);
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
|
||||
unsigned char* bmap = (unsigned char*)malloc(512*512);
|
||||
if (!bmap)
|
||||
{
|
||||
free(ttfBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
stbtt_BakeFontBitmap(ttfBuffer,0, FONT_HEIGHT, bmap,512,512, 32,96, g_cdata);
|
||||
|
||||
// can free ttf_buffer at this point
|
||||
glGenTextures(1, &g_ftex);
|
||||
glBindTexture(GL_TEXTURE_2D, g_ftex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 512,512, 0, GL_RED, GL_UNSIGNED_BYTE, bmap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// can free ttf_buffer at this point
|
||||
unsigned char white_alpha = 255;
|
||||
glGenTextures(1, &g_whitetex);
|
||||
glBindTexture(GL_TEXTURE_2D, g_whitetex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &white_alpha);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glGenVertexArrays(1, &g_vao);
|
||||
glGenBuffers(3, g_vbos);
|
||||
|
||||
glBindVertexArray(g_vao);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[0]);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT)*2, (void*)0);
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, 0, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[1]);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT)*2, (void*)0);
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, 0, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[2]);
|
||||
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT)*4, (void*)0);
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, 0, GL_STATIC_DRAW);
|
||||
g_program = glCreateProgram();
|
||||
|
||||
const char * vs =
|
||||
"#version 150\n"
|
||||
"uniform vec2 Viewport;\n"
|
||||
"in vec2 VertexPosition;\n"
|
||||
"in vec2 VertexTexCoord;\n"
|
||||
"in vec4 VertexColor;\n"
|
||||
"out vec2 texCoord;\n"
|
||||
"out vec4 vertexColor;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" vertexColor = VertexColor;\n"
|
||||
" texCoord = VertexTexCoord;\n"
|
||||
" gl_Position = vec4(VertexPosition * 2.0 / Viewport - 1.0, 0.f, 1.0);\n"
|
||||
"}\n";
|
||||
GLuint vso = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vso, 1, (const char **) &vs, NULL);
|
||||
glCompileShader(vso);
|
||||
glAttachShader(g_program, vso);
|
||||
|
||||
const char * fs =
|
||||
"#version 150\n"
|
||||
"in vec2 texCoord;\n"
|
||||
"in vec4 vertexColor;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"out vec4 Color;\n"
|
||||
"void main(void)\n"
|
||||
"{\n"
|
||||
" float alpha = texture(Texture, texCoord).r;\n"
|
||||
" Color = vec4(vertexColor.rgb, vertexColor.a * alpha);\n"
|
||||
"}\n";
|
||||
GLuint fso = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
glShaderSource(fso, 1, (const char **) &fs, NULL);
|
||||
glCompileShader(fso);
|
||||
glAttachShader(g_program, fso);
|
||||
|
||||
glBindAttribLocation(g_program, 0, "VertexPosition");
|
||||
glBindAttribLocation(g_program, 1, "VertexTexCoord");
|
||||
glBindAttribLocation(g_program, 2, "VertexColor");
|
||||
glBindFragDataLocation(g_program, 0, "Color");
|
||||
glLinkProgram(g_program);
|
||||
glDeleteShader(vso);
|
||||
glDeleteShader(fso);
|
||||
|
||||
glUseProgram(g_program);
|
||||
g_programViewportLocation = glGetUniformLocation(g_program, "Viewport");
|
||||
g_programTextureLocation = glGetUniformLocation(g_program, "Texture");
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
|
||||
free(ttfBuffer);
|
||||
free(bmap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void imguiRenderGLDestroy()
|
||||
{
|
||||
if (g_ftex)
|
||||
{
|
||||
glDeleteTextures(1, &g_ftex);
|
||||
g_ftex = 0;
|
||||
}
|
||||
|
||||
if (g_vao)
|
||||
{
|
||||
glDeleteVertexArrays(1, &g_vao);
|
||||
glDeleteBuffers(3, g_vbos);
|
||||
g_vao = 0;
|
||||
}
|
||||
|
||||
if (g_program)
|
||||
{
|
||||
glDeleteProgram(g_program);
|
||||
g_program = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void getBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index,
|
||||
float *xpos, float *ypos, stbtt_aligned_quad *q)
|
||||
{
|
||||
stbtt_bakedchar *b = chardata + char_index;
|
||||
int round_x = STBTT_ifloor(*xpos + b->xoff);
|
||||
int round_y = STBTT_ifloor(*ypos - b->yoff);
|
||||
|
||||
q->x0 = (float)round_x;
|
||||
q->y0 = (float)round_y;
|
||||
q->x1 = (float)round_x + b->x1 - b->x0;
|
||||
q->y1 = (float)round_y - b->y1 + b->y0;
|
||||
|
||||
q->s0 = b->x0 / (float)pw;
|
||||
q->t0 = b->y0 / (float)pw;
|
||||
q->s1 = b->x1 / (float)ph;
|
||||
q->t1 = b->y1 / (float)ph;
|
||||
|
||||
*xpos += b->xadvance;
|
||||
}
|
||||
|
||||
static const float g_tabStops[4] = {150, 210, 270, 330};
|
||||
|
||||
static float getTextLength(stbtt_bakedchar *chardata, const char* text)
|
||||
{
|
||||
float xpos = 0;
|
||||
float len = 0;
|
||||
while (*text)
|
||||
{
|
||||
int c = (unsigned char)*text;
|
||||
if (c == '\t')
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (xpos < g_tabStops[i])
|
||||
{
|
||||
xpos = g_tabStops[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c >= 32 && c < 128)
|
||||
{
|
||||
stbtt_bakedchar *b = chardata + c-32;
|
||||
int round_x = STBTT_ifloor((xpos + b->xoff) + 0.5);
|
||||
len = round_x + b->x1 - b->x0 + 0.5f;
|
||||
xpos += b->xadvance;
|
||||
}
|
||||
++text;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void drawText(float x, float y, const char *text, int align, unsigned int col)
|
||||
{
|
||||
if (!g_ftex) return;
|
||||
if (!text) return;
|
||||
|
||||
if (align == IMGUI_ALIGN_CENTER)
|
||||
x -= getTextLength(g_cdata, text)/2;
|
||||
else if (align == IMGUI_ALIGN_RIGHT)
|
||||
x -= getTextLength(g_cdata, text);
|
||||
|
||||
float r = (float) (col&0xff) / 255.f;
|
||||
float g = (float) ((col>>8)&0xff) / 255.f;
|
||||
float b = (float) ((col>>16)&0xff) / 255.f;
|
||||
float a = (float) ((col>>24)&0xff) / 255.f;
|
||||
|
||||
// assume orthographic projection with units = screen pixels, origin at top left
|
||||
glBindTexture(GL_TEXTURE_2D, g_ftex);
|
||||
|
||||
const float ox = x;
|
||||
|
||||
while (*text)
|
||||
{
|
||||
int c = (unsigned char)*text;
|
||||
if (c == '\t')
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (x < g_tabStops[i]+ox)
|
||||
{
|
||||
x = g_tabStops[i]+ox;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c >= 32 && c < 128)
|
||||
{
|
||||
stbtt_aligned_quad q;
|
||||
getBakedQuad(g_cdata, 512,512, c-32, &x,&y,&q);
|
||||
|
||||
float v[12] = {
|
||||
q.x0, q.y0,
|
||||
q.x1, q.y1,
|
||||
q.x1, q.y0,
|
||||
q.x0, q.y0,
|
||||
q.x0, q.y1,
|
||||
q.x1, q.y1,
|
||||
};
|
||||
float uv[12] = {
|
||||
q.s0, q.t0,
|
||||
q.s1, q.t1,
|
||||
q.s1, q.t0,
|
||||
q.s0, q.t0,
|
||||
q.s0, q.t1,
|
||||
q.s1, q.t1,
|
||||
};
|
||||
float c[24] = {
|
||||
r, g, b, a,
|
||||
r, g, b, a,
|
||||
r, g, b, a,
|
||||
r, g, b, a,
|
||||
r, g, b, a,
|
||||
r, g, b, a,
|
||||
};
|
||||
glBindVertexArray(g_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, 12*sizeof(float), v, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[1]);
|
||||
glBufferData(GL_ARRAY_BUFFER, 12*sizeof(float), uv, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_vbos[2]);
|
||||
glBufferData(GL_ARRAY_BUFFER, 24*sizeof(float), c, GL_STATIC_DRAW);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
}
|
||||
++text;
|
||||
}
|
||||
|
||||
//glEnd();
|
||||
//glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
void imguiRenderGLDraw(int width, int height)
|
||||
{
|
||||
const imguiGfxCmd* q = imguiGetRenderQueue();
|
||||
int nq = imguiGetRenderQueueSize();
|
||||
|
||||
const float s = 1.0f/8.0f;
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
glUseProgram(g_program);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform2f(g_programViewportLocation, (float) width, (float) height);
|
||||
glUniform1i(g_programTextureLocation, 0);
|
||||
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
for (int i = 0; i < nq; ++i)
|
||||
{
|
||||
const imguiGfxCmd& cmd = q[i];
|
||||
if (cmd.type == IMGUI_GFXCMD_RECT)
|
||||
{
|
||||
if (cmd.rect.r == 0)
|
||||
{
|
||||
drawRect((float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.w*s-1, (float)cmd.rect.h*s-1,
|
||||
1.0f, cmd.col);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawRoundedRect((float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.w*s-1, (float)cmd.rect.h*s-1,
|
||||
(float)cmd.rect.r*s, 1.0f, cmd.col);
|
||||
}
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_LINE)
|
||||
{
|
||||
drawLine(cmd.line.x0*s, cmd.line.y0*s, cmd.line.x1*s, cmd.line.y1*s, cmd.line.r*s, 1.0f, cmd.col);
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_TRIANGLE)
|
||||
{
|
||||
if (cmd.flags == 1)
|
||||
{
|
||||
const float verts[3*2] =
|
||||
{
|
||||
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s/2-0.5f,
|
||||
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
|
||||
};
|
||||
drawPolygon(verts, 3, 1.0f, cmd.col);
|
||||
}
|
||||
if (cmd.flags == 2)
|
||||
{
|
||||
const float verts[3*2] =
|
||||
{
|
||||
(float)cmd.rect.x*s+0.5f, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
|
||||
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s/2-0.5f, (float)cmd.rect.y*s+0.5f,
|
||||
(float)cmd.rect.x*s+0.5f+(float)cmd.rect.w*s-1, (float)cmd.rect.y*s+0.5f+(float)cmd.rect.h*s-1,
|
||||
};
|
||||
drawPolygon(verts, 3, 1.0f, cmd.col);
|
||||
}
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_TEXT)
|
||||
{
|
||||
drawText(cmd.text.x, cmd.text.y, cmd.text.text, cmd.text.align, cmd.col);
|
||||
}
|
||||
else if (cmd.type == IMGUI_GFXCMD_SCISSOR)
|
||||
{
|
||||
if (cmd.flags)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
28
testbed/imgui/imguiRenderGL3.h
Normal file
28
testbed/imgui/imguiRenderGL3.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
|
||||
// Source altered and distributed from https://github.com/AdrienHerubel/imgui
|
||||
|
||||
#ifndef IMGUI_RENDER_GL_H
|
||||
#define IMGUI_RENDER_GL_H
|
||||
|
||||
bool imguiRenderGLInit(const char* fontpath);
|
||||
void imguiRenderGLDestroy();
|
||||
void imguiRenderGLDraw(int width, int height);
|
||||
|
||||
#endif // IMGUI_RENDER_GL_H
|
|
@ -1,547 +0,0 @@
|
|||
// stb_rect_pack.h - v0.05 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
typedef int stbrp_coord;
|
||||
#else
|
||||
typedef unsigned short stbrp_coord;
|
||||
#endif
|
||||
|
||||
STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
#ifndef STBRP_LARGE_RECTS
|
||||
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
|
||||
#endif
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
context->extra[1].y = (1<<30);
|
||||
#else
|
||||
context->extra[1].y = 65535;
|
||||
#endif
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
(void)c;
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height < c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
STBRP_ASSERT(y <= best_y);
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
stbrp_node *L1 = NULL, *L2 = NULL;
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
L1 = cur;
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
L2 = cur;
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
stbrp_rect *p = (stbrp_rect *) a;
|
||||
stbrp_rect *q = (stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int rect_width_compare(const void *a, const void *b)
|
||||
{
|
||||
stbrp_rect *p = (stbrp_rect *) a;
|
||||
stbrp_rect *q = (stbrp_rect *) b;
|
||||
if (p->w > q->w)
|
||||
return -1;
|
||||
if (p->w < q->w)
|
||||
return 1;
|
||||
return (p->h > q->h) ? -1 : (p->h < q->h);
|
||||
}
|
||||
|
||||
static int rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
stbrp_rect *p = (stbrp_rect *) a;
|
||||
stbrp_rect *q = (stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
#define STBRP__MAXVAL 0xffffffff
|
||||
#else
|
||||
#define STBRP__MAXVAL 0xffff
|
||||
#endif
|
||||
|
||||
STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
#ifndef STBRP_LARGE_RECTS
|
||||
STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
|
||||
#endif
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
qsort(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
qsort(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags
|
||||
for (i=0; i < num_rects; ++i)
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -216,6 +216,17 @@ CollisionShapesScene::CollisionShapesScene(const std::string& name)
|
|||
// Change the material properties of the rigid body
|
||||
rp3d::Material& material = mFloor->getRigidBody()->getMaterial();
|
||||
material.setBounciness(rp3d::decimal(0.2));
|
||||
|
||||
// Get the physics engine parameters
|
||||
mEngineSettings.isGravityEnabled = mDynamicsWorld->isGravityEnabled();
|
||||
rp3d::Vector3 gravityVector = mDynamicsWorld->getGravity();
|
||||
mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z);
|
||||
mEngineSettings.isSleepingEnabled = mDynamicsWorld->isSleepingEnabled();
|
||||
mEngineSettings.sleepLinearVelocity = mDynamicsWorld->getSleepLinearVelocity();
|
||||
mEngineSettings.sleepAngularVelocity = mDynamicsWorld->getSleepAngularVelocity();
|
||||
mEngineSettings.nbPositionSolverIterations = mDynamicsWorld->getNbIterationsPositionSolver();
|
||||
mEngineSettings.nbVelocitySolverIterations = mDynamicsWorld->getNbIterationsVelocitySolver();
|
||||
mEngineSettings.timeBeforeSleep = mDynamicsWorld->getTimeBeforeSleep();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
|
@ -309,6 +320,18 @@ CollisionShapesScene::~CollisionShapesScene() {
|
|||
// Update the physics world (take a simulation step)
|
||||
void CollisionShapesScene::updatePhysics() {
|
||||
|
||||
// Update the physics engine parameters
|
||||
mDynamicsWorld->setIsGratityEnabled(mEngineSettings.isGravityEnabled);
|
||||
rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y,
|
||||
mEngineSettings.gravity.z);
|
||||
mDynamicsWorld->setGravity(gravity);
|
||||
mDynamicsWorld->enableSleeping(mEngineSettings.isSleepingEnabled);
|
||||
mDynamicsWorld->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity);
|
||||
mDynamicsWorld->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity);
|
||||
mDynamicsWorld->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations);
|
||||
mDynamicsWorld->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations);
|
||||
mDynamicsWorld->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep);
|
||||
|
||||
// Take a simulation step
|
||||
mDynamicsWorld->update(mEngineSettings.timeStep);
|
||||
}
|
||||
|
|
|
@ -89,6 +89,17 @@ CubesScene::CubesScene(const std::string& name)
|
|||
// Change the material properties of the floor rigid body
|
||||
rp3d::Material& material = mFloor->getRigidBody()->getMaterial();
|
||||
material.setBounciness(rp3d::decimal(0.3));
|
||||
|
||||
// Get the physics engine parameters
|
||||
mEngineSettings.isGravityEnabled = mDynamicsWorld->isGravityEnabled();
|
||||
rp3d::Vector3 gravityVector = mDynamicsWorld->getGravity();
|
||||
mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z);
|
||||
mEngineSettings.isSleepingEnabled = mDynamicsWorld->isSleepingEnabled();
|
||||
mEngineSettings.sleepLinearVelocity = mDynamicsWorld->getSleepLinearVelocity();
|
||||
mEngineSettings.sleepAngularVelocity = mDynamicsWorld->getSleepAngularVelocity();
|
||||
mEngineSettings.nbPositionSolverIterations = mDynamicsWorld->getNbIterationsPositionSolver();
|
||||
mEngineSettings.nbVelocitySolverIterations = mDynamicsWorld->getNbIterationsVelocitySolver();
|
||||
mEngineSettings.timeBeforeSleep = mDynamicsWorld->getTimeBeforeSleep();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
|
@ -120,6 +131,19 @@ CubesScene::~CubesScene() {
|
|||
// Update the physics world (take a simulation step)
|
||||
void CubesScene::updatePhysics() {
|
||||
|
||||
|
||||
// Update the physics engine parameters
|
||||
mDynamicsWorld->setIsGratityEnabled(mEngineSettings.isGravityEnabled);
|
||||
rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y,
|
||||
mEngineSettings.gravity.z);
|
||||
mDynamicsWorld->setGravity(gravity);
|
||||
mDynamicsWorld->enableSleeping(mEngineSettings.isSleepingEnabled);
|
||||
mDynamicsWorld->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity);
|
||||
mDynamicsWorld->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity);
|
||||
mDynamicsWorld->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations);
|
||||
mDynamicsWorld->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations);
|
||||
mDynamicsWorld->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep);
|
||||
|
||||
// Take a simulation step
|
||||
mDynamicsWorld->update(mEngineSettings.timeStep);
|
||||
}
|
||||
|
|
|
@ -72,6 +72,17 @@ JointsScene::JointsScene(const std::string& name)
|
|||
|
||||
// Create the floor
|
||||
createFloor();
|
||||
|
||||
// Get the physics engine parameters
|
||||
mEngineSettings.isGravityEnabled = mDynamicsWorld->isGravityEnabled();
|
||||
rp3d::Vector3 gravityVector = mDynamicsWorld->getGravity();
|
||||
mEngineSettings.gravity = openglframework::Vector3(gravityVector.x, gravityVector.y, gravityVector.z);
|
||||
mEngineSettings.isSleepingEnabled = mDynamicsWorld->isSleepingEnabled();
|
||||
mEngineSettings.sleepLinearVelocity = mDynamicsWorld->getSleepLinearVelocity();
|
||||
mEngineSettings.sleepAngularVelocity = mDynamicsWorld->getSleepAngularVelocity();
|
||||
mEngineSettings.nbPositionSolverIterations = mDynamicsWorld->getNbIterationsPositionSolver();
|
||||
mEngineSettings.nbVelocitySolverIterations = mDynamicsWorld->getNbIterationsVelocitySolver();
|
||||
mEngineSettings.timeBeforeSleep = mDynamicsWorld->getTimeBeforeSleep();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
|
@ -119,6 +130,18 @@ JointsScene::~JointsScene() {
|
|||
// Update the physics world (take a simulation step)
|
||||
void JointsScene::updatePhysics() {
|
||||
|
||||
// Update the physics engine parameters
|
||||
mDynamicsWorld->setIsGratityEnabled(mEngineSettings.isGravityEnabled);
|
||||
rp3d::Vector3 gravity(mEngineSettings.gravity.x, mEngineSettings.gravity.y,
|
||||
mEngineSettings.gravity.z);
|
||||
mDynamicsWorld->setGravity(gravity);
|
||||
mDynamicsWorld->enableSleeping(mEngineSettings.isSleepingEnabled);
|
||||
mDynamicsWorld->setSleepLinearVelocity(mEngineSettings.sleepLinearVelocity);
|
||||
mDynamicsWorld->setSleepAngularVelocity(mEngineSettings.sleepAngularVelocity);
|
||||
mDynamicsWorld->setNbIterationsPositionSolver(mEngineSettings.nbPositionSolverIterations);
|
||||
mDynamicsWorld->setNbIterationsVelocitySolver(mEngineSettings.nbVelocitySolverIterations);
|
||||
mDynamicsWorld->setTimeBeforeSleep(mEngineSettings.timeBeforeSleep);
|
||||
|
||||
// Update the motor speed of the Slider Joint (to move up and down)
|
||||
long double motorSpeed = 2 * cos(mEngineSettings.elapsedTime * 1.5);
|
||||
mSliderJoint->setMotorSpeed(rp3d::decimal(motorSpeed));
|
||||
|
|
|
@ -237,6 +237,7 @@ RaycastScene::~RaycastScene() {
|
|||
// Update the physics world (take a simulation step)
|
||||
void RaycastScene::updatePhysics() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Take a step for the simulation
|
||||
|
|
|
@ -40,6 +40,8 @@ Shader Gui::mShader;
|
|||
openglframework::VertexBufferObject Gui::mVBO(GL_ARRAY_BUFFER);
|
||||
openglframework::VertexArrayObject Gui::mVAO;
|
||||
Gui::LeftPane Gui::mLeftPane = SCENES;
|
||||
double Gui::mScrollX = 0.0;
|
||||
double Gui::mScrollY = 0.0;
|
||||
|
||||
// Constructor
|
||||
Gui::Gui() {
|
||||
|
@ -61,13 +63,7 @@ Gui::~Gui() {
|
|||
|
||||
mShader.destroy();
|
||||
|
||||
if (g_FontTexture)
|
||||
{
|
||||
glDeleteTextures(1, &g_FontTexture);
|
||||
ImGui::GetIO().Fonts->TexID = 0;
|
||||
g_FontTexture = 0;
|
||||
}
|
||||
ImGui::Shutdown();
|
||||
imguiRenderGLDestroy();
|
||||
}
|
||||
|
||||
// Create and return the singleton instance of this class
|
||||
|
@ -79,149 +75,196 @@ Gui& Gui::getInstance() {
|
|||
/// Initialize the GUI
|
||||
void Gui::init() {
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||
|
||||
io.RenderDrawListsFn = renderDrawLists;
|
||||
io.SetClipboardTextFn = setClipboardText;
|
||||
io.GetClipboardTextFn = getClipboardText;
|
||||
|
||||
io.FontGlobalScale = GUI_SCALING;
|
||||
// Init UI
|
||||
if (!imguiRenderGLInit("DroidSans.ttf")) {
|
||||
fprintf(stderr, "Could not init GUI renderer.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void Gui::displayHeader() {
|
||||
|
||||
TestbedApplication& app = TestbedApplication::getInstance();
|
||||
|
||||
ImVec2 buttonSize(120, 40);
|
||||
int windowWidth, windowHeight;
|
||||
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(mWindow, &display_w, &display_h);
|
||||
const int button_width = 150;
|
||||
|
||||
ImGuiWindowFlags window_flags = 0;
|
||||
window_flags |= ImGuiWindowFlags_NoTitleBar;
|
||||
window_flags |= ImGuiWindowFlags_NoResize;
|
||||
window_flags |= ImGuiWindowFlags_NoMove;
|
||||
int scrollarea = 0;
|
||||
imguiBeginScrollArea(NULL, 0, app.mWindowToFramebufferRatio.y * (windowHeight - HEADER_HEIGHT),
|
||||
app.mWindowToFramebufferRatio.x * windowWidth,
|
||||
app.mWindowToFramebufferRatio.y * HEADER_HEIGHT, &scrollarea);
|
||||
|
||||
ImGui::PushID("Header");
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, BACKGROUND_COLOR);
|
||||
imguiStartLineOfItems();
|
||||
|
||||
ImGui::Begin("Header", NULL, ImVec2(display_w, HEADER_HEIGHT), 1.0f, window_flags);
|
||||
ImGui::SetWindowPos(ImVec2(0, 0));
|
||||
// ----- Left Pane Header ----- //
|
||||
|
||||
bool isRunning = app.mTimer.isRunning();
|
||||
if (ImGui::Button(isRunning ? "Pause" : "Play", buttonSize)) {
|
||||
app.togglePlayPauseSimulation();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
// Play/Pause
|
||||
if (imguiButton(app.mTimer.isRunning() ? "Pause" : "Play", true, button_width)) {
|
||||
app.togglePlayPauseSimulation();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Step", buttonSize)) {
|
||||
app.toggleTakeSinglePhysicsStep();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
// Step
|
||||
if (imguiButton("Step", !app.mTimer.isRunning(), button_width)) {
|
||||
app.toggleTakeSinglePhysicsStep();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Restart", buttonSize)) {
|
||||
app.restartSimulation();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
// Restart
|
||||
if (imguiButton("Restart", true, button_width)) {
|
||||
app.restartSimulation();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopID();
|
||||
imguiEndLineOfItems();
|
||||
imguiEndScrollArea();
|
||||
}
|
||||
|
||||
void Gui::displayLeftPane() {
|
||||
|
||||
const int nbButtonsHeader = 4;
|
||||
ImVec2 buttonSize(LEFT_PANE_WIDTH / nbButtonsHeader - 9, LEFT_PANE_HEADER_HEIGHT);
|
||||
TestbedApplication& app = TestbedApplication::getInstance();
|
||||
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(mWindow, &display_w, &display_h);
|
||||
int windowWidth, windowHeight;
|
||||
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||
|
||||
ImGuiWindowFlags window_flags = 0;
|
||||
window_flags |= ImGuiWindowFlags_NoTitleBar;
|
||||
window_flags |= ImGuiWindowFlags_NoResize;
|
||||
window_flags |= ImGuiWindowFlags_NoMove;
|
||||
int scrollarea = 0;
|
||||
imguiBeginScrollArea(NULL, 0, app.mWindowToFramebufferRatio.y * (windowHeight - HEADER_HEIGHT - LEFT_PANE_HEADER_HEIGHT),
|
||||
app.mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||
app.mWindowToFramebufferRatio.y * LEFT_PANE_HEADER_HEIGHT, &scrollarea);
|
||||
|
||||
ImGui::PushID("LeftPane");
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, BACKGROUND_COLOR);
|
||||
imguiStartLineOfItems();
|
||||
|
||||
ImGui::Begin("LeftPane", NULL, ImVec2(LEFT_PANE_WIDTH, display_h - HEADER_HEIGHT), 1.0f, window_flags);
|
||||
ImGui::SetWindowPos(ImVec2(0, HEADER_HEIGHT));
|
||||
// ----- Left Pane Header ----- //
|
||||
int widthButton = app.mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH / 5;
|
||||
if (imguiButton("Scenes", true, widthButton)) {
|
||||
mLeftPane = SCENES;
|
||||
}
|
||||
|
||||
// ----- Left Pane Header ----- //
|
||||
if (ImGui::Button("Scenes", buttonSize)) {
|
||||
mLeftPane = SCENES;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (imguiButton("Physics", true, widthButton)) {
|
||||
mLeftPane = PHYSICS;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Physics", buttonSize)) {
|
||||
mLeftPane = PHYSICS;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
imguiButton("Rendering", true, widthButton);
|
||||
imguiButton("Profiling", true, widthButton);
|
||||
imguiEndLineOfItems();
|
||||
imguiEndScrollArea();
|
||||
|
||||
ImGui::Button("Rendering", buttonSize); ImGui::SameLine();
|
||||
ImGui::Button("Profiling", buttonSize);
|
||||
|
||||
// Display the left pane content
|
||||
switch(mLeftPane) {
|
||||
case SCENES: displayScenesPane(); break;
|
||||
case PHYSICS: displayPhysicsPane(); break;
|
||||
case RENDERING: displayRenderingPane(); break;
|
||||
case PROFILING: displayProfilingPane(); break;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopID();
|
||||
// Display the left pane content
|
||||
switch(mLeftPane) {
|
||||
case SCENES: displayScenesPane(); break;
|
||||
case PHYSICS: displayPhysicsPane(); break;
|
||||
case RENDERING: displayRenderingPane(); break;
|
||||
case PROFILING: displayProfilingPane(); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Display the list of scenes
|
||||
void Gui::displayScenesPane() {
|
||||
|
||||
TestbedApplication& app = TestbedApplication::getInstance();
|
||||
|
||||
static int choice = 0;
|
||||
int startChoice = choice;
|
||||
TestbedApplication& app = TestbedApplication::getInstance();
|
||||
int scrollarea = 1;
|
||||
int windowWidth, windowHeight;
|
||||
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||
|
||||
std::vector<Scene*> scenes = app.getScenes();
|
||||
|
||||
imguiBeginScrollArea("Scenes", 0, 0,
|
||||
app.mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||
app.mWindowToFramebufferRatio.y * (windowHeight - HEADER_HEIGHT - LEFT_PANE_HEADER_HEIGHT),
|
||||
&scrollarea);
|
||||
|
||||
// For each scene
|
||||
for (int i=0; i<scenes.size(); i++) {
|
||||
|
||||
// Display a radio button
|
||||
ImGui::RadioButton(scenes[i]->getName().c_str(), &choice, i);
|
||||
if (imguiCheck(scenes[i]->getName().c_str(), choice == i)) {
|
||||
choice = i;
|
||||
}
|
||||
}
|
||||
|
||||
// If the user changed scene
|
||||
if (choice != startChoice) {
|
||||
app.switchScene(scenes[choice]);
|
||||
}
|
||||
|
||||
imguiEndScrollArea();
|
||||
}
|
||||
|
||||
void Gui::displayPhysicsPane() {
|
||||
|
||||
TestbedApplication& app = TestbedApplication::getInstance();
|
||||
|
||||
// Physics time step
|
||||
//float timestep = app.ge;
|
||||
//ImGui::InputFloat("Timestep", ×tep, 0.01f, 1.0f);
|
||||
int windowWidth, windowHeight;
|
||||
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||
|
||||
int scrollarea = 2;
|
||||
imguiBeginScrollArea("Physics Engine Parameters", 0, 0,
|
||||
app.mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||
app.mWindowToFramebufferRatio.y * (windowHeight - HEADER_HEIGHT - LEFT_PANE_HEADER_HEIGHT),
|
||||
&scrollarea);
|
||||
|
||||
// Enabled/Disable Sleeping
|
||||
bool toggle = imguiCheck("Sleeping enabled", app.mEngineSettings.isSleepingEnabled);
|
||||
if (toggle) {
|
||||
app.mEngineSettings.isSleepingEnabled = !app.mEngineSettings.isSleepingEnabled;
|
||||
}
|
||||
|
||||
// Enabled/Disable Gravity
|
||||
toggle = imguiCheck("Gravity enabled", app.mEngineSettings.isGravityEnabled);
|
||||
if (toggle) {
|
||||
app.mEngineSettings.isGravityEnabled = !app.mEngineSettings.isGravityEnabled;
|
||||
}
|
||||
|
||||
// Timestep
|
||||
float timeStep = app.mEngineSettings.timeStep;
|
||||
if (imguiSlider("Timestep", &timeStep, 0.001f, 1.0f, 0.001f)) {
|
||||
app.mEngineSettings.timeStep = timeStep;
|
||||
}
|
||||
|
||||
// Nb velocity solver iterations
|
||||
float nbVelocityIterations = static_cast<float>(app.mEngineSettings.nbVelocitySolverIterations);
|
||||
if (imguiSlider("Velocity Solver Iterations", &nbVelocityIterations, 1.0f, 100.0f, 1.0f)) {
|
||||
app.mEngineSettings.nbVelocitySolverIterations = static_cast<int>(nbVelocityIterations);
|
||||
}
|
||||
|
||||
// Nb position solver iterations
|
||||
float nbPositionIterations = static_cast<float>(app.mEngineSettings.nbPositionSolverIterations);
|
||||
if (imguiSlider("Position Solver Iterations", &nbPositionIterations, 1.0f, 100.0f, 1.0f)) {
|
||||
app.mEngineSettings.nbPositionSolverIterations = static_cast<int>(nbPositionIterations);
|
||||
}
|
||||
|
||||
// Time before sleep
|
||||
float timeBeforeSleep = app.mEngineSettings.timeBeforeSleep;
|
||||
if (imguiSlider("Time before sleep", &timeBeforeSleep, 0.0f, 60.0f, 0.5f)) {
|
||||
app.mEngineSettings.timeBeforeSleep = timeBeforeSleep;
|
||||
}
|
||||
|
||||
// Sleep linear velocity
|
||||
float sleepLinearVelocity = app.mEngineSettings.sleepLinearVelocity;
|
||||
if (imguiSlider("Sleep linear velocity", &sleepLinearVelocity, 0.0f, 30.0f, 0.5f)) {
|
||||
app.mEngineSettings.sleepLinearVelocity = sleepLinearVelocity;
|
||||
}
|
||||
|
||||
// Sleep angular velocity
|
||||
float sleepAngularVelocity = app.mEngineSettings.sleepAngularVelocity;
|
||||
if (imguiSlider("Sleep angular velocity", &sleepAngularVelocity, 0.0f, 30.0f, 0.5f)) {
|
||||
app.mEngineSettings.sleepAngularVelocity = sleepAngularVelocity;
|
||||
}
|
||||
|
||||
// Gravity vector
|
||||
openglframework::Vector3 gravity = app.mEngineSettings.gravity;
|
||||
float gravityX = gravity.x, gravityY = gravity.y, gravityZ = gravity.z;
|
||||
if (imguiSlider("Gravity X", &gravityX, -50.0f, 50.0f, 0.5f)) {
|
||||
app.mEngineSettings.gravity.x = gravityX;
|
||||
}
|
||||
if (imguiSlider("Gravity Y", &gravityY, -50.0f, 50.0f, 0.5f)) {
|
||||
app.mEngineSettings.gravity.y = gravityY;
|
||||
}
|
||||
if (imguiSlider("Gravity Z", &gravityZ, -50.0f, 50.0f, 0.5f)) {
|
||||
app.mEngineSettings.gravity.z = gravityZ;
|
||||
}
|
||||
|
||||
imguiEndScrollArea();
|
||||
}
|
||||
|
||||
void Gui::displayRenderingPane() {
|
||||
|
@ -232,224 +275,40 @@ void Gui::displayProfilingPane() {
|
|||
|
||||
}
|
||||
|
||||
void Gui::createDeviceObjects() {
|
||||
|
||||
mShader.create("shaders/gui.vert", "shaders/gui.frag");
|
||||
|
||||
GLuint shaderID = mShader.getProgramObjectId();
|
||||
g_AttribLocationTex = glGetUniformLocation(shaderID, "Texture");
|
||||
g_AttribLocationProjMtx = glGetUniformLocation(shaderID, "ProjMtx");
|
||||
g_AttribLocationPosition = glGetAttribLocation(shaderID, "Position");
|
||||
g_AttribLocationUV = glGetAttribLocation(shaderID, "UV");
|
||||
g_AttribLocationColor = glGetAttribLocation(shaderID, "Color");
|
||||
|
||||
mVBO.create();
|
||||
|
||||
mVAO.create();
|
||||
mVAO.bind();
|
||||
mVBO.bind();
|
||||
glEnableVertexAttribArray(g_AttribLocationPosition);
|
||||
glEnableVertexAttribArray(g_AttribLocationUV);
|
||||
glEnableVertexAttribArray(g_AttribLocationColor);
|
||||
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
|
||||
glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos));
|
||||
glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv));
|
||||
glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col));
|
||||
#undef OFFSETOF
|
||||
mVAO.unbind();
|
||||
mVBO.unbind();
|
||||
|
||||
createFontTextures();
|
||||
}
|
||||
|
||||
// Display the GUI
|
||||
void Gui::render() {
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
//glfwPollEvents();
|
||||
beginNewFrame();
|
||||
TestbedApplication& app = TestbedApplication::getInstance();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(mWindow, &display_w, &display_h);
|
||||
|
||||
int windowWidth, windowHeight;
|
||||
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||
|
||||
// Mouse position
|
||||
double mouseX, mouseY;
|
||||
glfwGetCursorPos(mWindow, &mouseX, &mouseY);
|
||||
|
||||
// Mouse buttons
|
||||
int leftButton = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_LEFT);
|
||||
unsigned char mousebutton = 0;
|
||||
if(leftButton == GLFW_PRESS ) {
|
||||
mousebutton |= IMGUI_MBUT_LEFT;
|
||||
}
|
||||
|
||||
imguiBeginFrame(app.mWindowToFramebufferRatio.x * mouseX,
|
||||
app.mWindowToFramebufferRatio.y * (windowHeight - mouseY), mousebutton, -mScrollY);
|
||||
resetScroll();
|
||||
|
||||
displayHeader();
|
||||
displayLeftPane();
|
||||
|
||||
ImGui::ShowTestWindow();
|
||||
imguiEndFrame();
|
||||
|
||||
// Render the GUI
|
||||
ImGui::Render();
|
||||
}
|
||||
|
||||
void Gui::beginNewFrame() {
|
||||
|
||||
if (!g_FontTexture)
|
||||
createDeviceObjects();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
glfwGetWindowSize(mWindow, &w, &h);
|
||||
glfwGetFramebufferSize(mWindow, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)display_w, (float)display_h);
|
||||
|
||||
// Setup time step
|
||||
double current_time = glfwGetTime();
|
||||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
|
||||
g_Time = current_time;
|
||||
|
||||
// Setup inputs
|
||||
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
|
||||
if (glfwGetWindowAttrib(mWindow, GLFW_FOCUSED))
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(mWindow, &mouse_x, &mouse_y);
|
||||
mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels
|
||||
mouse_y *= (float)display_h / h;
|
||||
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
|
||||
}
|
||||
else
|
||||
{
|
||||
io.MousePos = ImVec2(-1,-1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(mWindow, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
g_MousePressed[i] = false;
|
||||
}
|
||||
|
||||
io.MouseWheel = g_MouseWheel;
|
||||
g_MouseWheel = 0.0f;
|
||||
|
||||
// Hide/show hardware mouse cursor
|
||||
glfwSetInputMode(mWindow, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL);
|
||||
|
||||
// Start the frame
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void Gui::createFontTextures()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader.
|
||||
|
||||
glGenTextures(1, &g_FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
|
||||
}
|
||||
|
||||
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
|
||||
// If text or lines are blurry when integrating ImGui in your engine:
|
||||
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
|
||||
void Gui::renderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
|
||||
{
|
||||
if (cmd_lists_count == 0)
|
||||
return;
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
|
||||
GLint last_program, last_texture;
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
const float width = ImGui::GetIO().DisplaySize.x;
|
||||
const float height = ImGui::GetIO().DisplaySize.y;
|
||||
Matrix4 orthoProj(2.0f / width, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 2.0/-height, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, -1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f, 1.0f);
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/width, 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/-height, 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||
{ -1.0f, 1.0f, 0.0f, 1.0f },
|
||||
};
|
||||
|
||||
mShader.bind();
|
||||
//mShader.setIntUniform("Texture", 0);
|
||||
//mShader.setMatrix4x4Uniform("ProjMtx", orthoProj);
|
||||
///glUseProgram(g_ShaderHandle);
|
||||
glUniform1i(g_AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
|
||||
// Grow our buffer according to what we need
|
||||
size_t total_vtx_count = 0;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
total_vtx_count += cmd_lists[n]->vtx_buffer.size();
|
||||
mVBO.bind();
|
||||
size_t needed_vtx_size = total_vtx_count * sizeof(ImDrawVert);
|
||||
if (g_VboSize < needed_vtx_size)
|
||||
{
|
||||
g_VboSize = needed_vtx_size + 5000 * sizeof(ImDrawVert); // Grow buffer
|
||||
mVBO.copyDataIntoVBO(g_VboSize, NULL, GL_STREAM_DRAW);
|
||||
//glBufferData(GL_ARRAY_BUFFER, g_VboSize, NULL, GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
// Copy and convert all vertices into a single contiguous buffer
|
||||
unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||
if (!buffer_data)
|
||||
return;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = cmd_lists[n];
|
||||
memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
|
||||
buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert);
|
||||
}
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
mVBO.unbind();
|
||||
mVAO.bind();
|
||||
|
||||
int cmd_offset = 0;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = cmd_lists[n];
|
||||
int vtx_offset = cmd_offset;
|
||||
const ImDrawCmd* pcmd_end = cmd_list->commands.end();
|
||||
for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
|
||||
{
|
||||
if (pcmd->user_callback)
|
||||
{
|
||||
pcmd->user_callback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->texture_id);
|
||||
glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
|
||||
glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
|
||||
}
|
||||
vtx_offset += pcmd->vtx_count;
|
||||
}
|
||||
cmd_offset = vtx_offset;
|
||||
}
|
||||
|
||||
// Restore modified state
|
||||
mVAO.unbind();
|
||||
glUseProgram(last_program);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
}
|
||||
|
||||
const char* Gui::getClipboardText() {
|
||||
return glfwGetClipboardString(mWindow);
|
||||
}
|
||||
|
||||
void Gui::setClipboardText(const char* text) {
|
||||
glfwSetClipboardString(mWindow, text);
|
||||
imguiRenderGLDraw(display_w, display_h);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@
|
|||
#define GUI_H
|
||||
|
||||
// Libraries
|
||||
#include <imgui.h>
|
||||
#include "imgui.h"
|
||||
#include "imguiRenderGL3.h"
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "openglframework.h"
|
||||
|
@ -35,9 +36,8 @@
|
|||
// Constants
|
||||
const float GUI_SCALING = 2.0f;
|
||||
const int HEADER_HEIGHT = 80;
|
||||
const int LEFT_PANE_WIDTH = 700;
|
||||
const int LEFT_PANE_WIDTH = 300;
|
||||
const int LEFT_PANE_HEADER_HEIGHT = 60;
|
||||
const ImColor BACKGROUND_COLOR = ImColor(41, 41, 41, 255);
|
||||
|
||||
using namespace openglframework;
|
||||
|
||||
|
@ -72,21 +72,10 @@ class Gui {
|
|||
static openglframework::VertexArrayObject mVAO;
|
||||
static LeftPane mLeftPane;
|
||||
|
||||
static double mScrollX, mScrollY;
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
||||
void createDeviceObjects();
|
||||
|
||||
void createFontTextures();
|
||||
|
||||
void beginNewFrame();
|
||||
|
||||
static void renderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count);
|
||||
|
||||
static const char* getClipboardText();
|
||||
|
||||
static void setClipboardText(const char* text);
|
||||
|
||||
static void displayHeader();
|
||||
static void displayLeftPane();
|
||||
|
||||
|
@ -97,6 +86,9 @@ class Gui {
|
|||
static void displayRenderingPane();
|
||||
static void displayProfilingPane();
|
||||
|
||||
static void resetScroll();
|
||||
|
||||
|
||||
public :
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
@ -117,10 +109,22 @@ class Gui {
|
|||
void render();
|
||||
|
||||
static void setWindow(GLFWwindow* window);
|
||||
|
||||
static void setScroll(double scrollX, double scrollY);
|
||||
};
|
||||
|
||||
inline void Gui::setWindow(GLFWwindow* window) {
|
||||
mWindow = window;
|
||||
}
|
||||
|
||||
inline void Gui::resetScroll() {
|
||||
mScrollX = 0.0;
|
||||
mScrollY = 0.0;
|
||||
}
|
||||
|
||||
inline void Gui::setScroll(double scrollX, double scrollY) {
|
||||
mScrollX = scrollX;
|
||||
mScrollY = scrollY;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -155,6 +155,9 @@ class Scene {
|
|||
/// Return a reference to the camera
|
||||
const openglframework::Camera& getCamera() const;
|
||||
|
||||
/// Get the engine settings
|
||||
EngineSettings getEngineSettings() const;
|
||||
|
||||
/// Set the engine settings
|
||||
void setEngineSettings(const EngineSettings& settings);
|
||||
|
||||
|
@ -186,6 +189,11 @@ inline void Scene::setWindowDimension(int width, int height) {
|
|||
mWindowHeight = height;
|
||||
}
|
||||
|
||||
// Get the engine settings
|
||||
inline EngineSettings Scene::getEngineSettings() const {
|
||||
return mEngineSettings;
|
||||
}
|
||||
|
||||
// Set the engine settings
|
||||
inline void Scene::setEngineSettings(const EngineSettings& settings) {
|
||||
mEngineSettings = settings;
|
||||
|
|
|
@ -53,12 +53,12 @@ TestbedApplication& TestbedApplication::getInstance() {
|
|||
TestbedApplication::TestbedApplication() : mFPS(0), mNbFrames(0), mPreviousTime(0) {
|
||||
|
||||
mCurrentScene = NULL;
|
||||
mEngineSettings.timeStep = DEFAULT_TIMESTEP;
|
||||
mIsMultisamplingActive = true;
|
||||
mWidth = 1280;
|
||||
mHeight = 720;
|
||||
mSinglePhysicsStepEnabled = false;
|
||||
mSinglePhysicsStepDone = false;
|
||||
mWindowToFramebufferRatio = Vector2(1, 1);
|
||||
}
|
||||
|
||||
// Destructor
|
||||
|
@ -164,7 +164,11 @@ void TestbedApplication::createScenes() {
|
|||
mScenes.push_back(raycastScene);
|
||||
|
||||
assert(mScenes.size() > 0);
|
||||
mCurrentScene = mScenes[0];
|
||||
mCurrentScene = mScenes[1];
|
||||
|
||||
// Get the engine settings from the scene
|
||||
mEngineSettings = mCurrentScene->getEngineSettings();
|
||||
mEngineSettings.timeStep = DEFAULT_TIMESTEP;
|
||||
}
|
||||
|
||||
// Remove all the scenes
|
||||
|
@ -236,20 +240,25 @@ void TestbedApplication::update() {
|
|||
// Render
|
||||
void TestbedApplication::render() {
|
||||
|
||||
// Get the framebuffer dimension
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(mWindow, &width, &height);
|
||||
int bufferWidth, bufferHeight;
|
||||
glfwGetFramebufferSize(mWindow, &bufferWidth, &bufferHeight);
|
||||
|
||||
int windowWidth, windowHeight;
|
||||
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||
|
||||
// Compute the window to framebuffer ratio
|
||||
mWindowToFramebufferRatio.x = float(bufferWidth) / float(windowWidth);
|
||||
mWindowToFramebufferRatio.y = float(bufferHeight) / float(windowHeight);
|
||||
|
||||
// Resize the OpenGL viewport
|
||||
glViewport(LEFT_PANE_WIDTH, HEADER_HEIGHT,
|
||||
width - LEFT_PANE_WIDTH, height - HEADER_HEIGHT);
|
||||
glViewport(mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||
0,
|
||||
bufferWidth - mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||
bufferHeight - mWindowToFramebufferRatio.y * HEADER_HEIGHT);
|
||||
|
||||
// Render the scene
|
||||
mCurrentScene->render();
|
||||
|
||||
// Resize the OpenGL viewport
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
// Display the GUI
|
||||
Gui::getInstance().render();
|
||||
|
||||
|
@ -311,6 +320,11 @@ void TestbedApplication::switchScene(Scene* newScene) {
|
|||
|
||||
mCurrentScene = newScene;
|
||||
|
||||
// Get the engine settings of the scene
|
||||
float currentTimeStep = mEngineSettings.timeStep;
|
||||
mEngineSettings = mCurrentScene->getEngineSettings();
|
||||
mEngineSettings.timeStep = currentTimeStep;
|
||||
|
||||
// Reset the scene
|
||||
mCurrentScene->reset();
|
||||
}
|
||||
|
@ -397,6 +411,10 @@ void TestbedApplication::keyboard(GLFWwindow* window, int key, int scancode,
|
|||
|
||||
// Callback method to receive scrolling events
|
||||
void TestbedApplication::scroll(GLFWwindow* window, double xAxis, double yAxis) {
|
||||
|
||||
// Update scroll on the GUI
|
||||
Gui::getInstance().setScroll(xAxis, yAxis);
|
||||
|
||||
getInstance().mCurrentScene->scrollingEvent(xAxis, yAxis, SCROLL_SENSITIVITY);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@ class TestbedApplication {
|
|||
/// True if the single physics step has been taken already
|
||||
bool mSinglePhysicsStepDone;
|
||||
|
||||
openglframework::Vector2 mWindowToFramebufferRatio;
|
||||
|
||||
// -------------------- Methods -------------------- //
|
||||
|
||||
/// Private constructor (for the singleton class)
|
||||
|
|
Loading…
Reference in New Issue
Block a user