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
|
# Copy the meshes used for the demo into the build directory
|
||||||
FILE(COPY "meshes/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/meshes/")
|
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
|
# Headers
|
||||||
INCLUDE_DIRECTORIES("src/" "opengl-framework/src/" "glfw/include/" "common/" "scenes/" "imgui/")
|
INCLUDE_DIRECTORIES("src/" "opengl-framework/src/" "glfw/include/" "common/" "scenes/" "imgui/")
|
||||||
|
|
||||||
|
@ -37,11 +45,10 @@ SET(TESTBED_SOURCES
|
||||||
|
|
||||||
# IMGUI source files
|
# IMGUI source files
|
||||||
SET(IMGUI_SOURCES
|
SET(IMGUI_SOURCES
|
||||||
imgui/imgui.h
|
|
||||||
imgui/imgui.cpp
|
imgui/imgui.cpp
|
||||||
imgui/imconfig.h
|
imgui/imgui.h
|
||||||
imgui/stb_rect_pack.h
|
imgui/imguiRenderGL3.h
|
||||||
imgui/stb_textedit.h
|
imgui/imguiRenderGL3.cpp
|
||||||
imgui/stb_truetype.h
|
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
|
// Change the material properties of the rigid body
|
||||||
rp3d::Material& material = mFloor->getRigidBody()->getMaterial();
|
rp3d::Material& material = mFloor->getRigidBody()->getMaterial();
|
||||||
material.setBounciness(rp3d::decimal(0.2));
|
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
|
// Destructor
|
||||||
|
@ -309,6 +320,18 @@ CollisionShapesScene::~CollisionShapesScene() {
|
||||||
// Update the physics world (take a simulation step)
|
// Update the physics world (take a simulation step)
|
||||||
void CollisionShapesScene::updatePhysics() {
|
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
|
// Take a simulation step
|
||||||
mDynamicsWorld->update(mEngineSettings.timeStep);
|
mDynamicsWorld->update(mEngineSettings.timeStep);
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,17 @@ CubesScene::CubesScene(const std::string& name)
|
||||||
// Change the material properties of the floor rigid body
|
// Change the material properties of the floor rigid body
|
||||||
rp3d::Material& material = mFloor->getRigidBody()->getMaterial();
|
rp3d::Material& material = mFloor->getRigidBody()->getMaterial();
|
||||||
material.setBounciness(rp3d::decimal(0.3));
|
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
|
// Destructor
|
||||||
|
@ -120,6 +131,19 @@ CubesScene::~CubesScene() {
|
||||||
// Update the physics world (take a simulation step)
|
// Update the physics world (take a simulation step)
|
||||||
void CubesScene::updatePhysics() {
|
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
|
// Take a simulation step
|
||||||
mDynamicsWorld->update(mEngineSettings.timeStep);
|
mDynamicsWorld->update(mEngineSettings.timeStep);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,17 @@ JointsScene::JointsScene(const std::string& name)
|
||||||
|
|
||||||
// Create the floor
|
// Create the floor
|
||||||
createFloor();
|
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
|
// Destructor
|
||||||
|
@ -119,6 +130,18 @@ JointsScene::~JointsScene() {
|
||||||
// Update the physics world (take a simulation step)
|
// Update the physics world (take a simulation step)
|
||||||
void JointsScene::updatePhysics() {
|
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)
|
// Update the motor speed of the Slider Joint (to move up and down)
|
||||||
long double motorSpeed = 2 * cos(mEngineSettings.elapsedTime * 1.5);
|
long double motorSpeed = 2 * cos(mEngineSettings.elapsedTime * 1.5);
|
||||||
mSliderJoint->setMotorSpeed(rp3d::decimal(motorSpeed));
|
mSliderJoint->setMotorSpeed(rp3d::decimal(motorSpeed));
|
||||||
|
|
|
@ -237,6 +237,7 @@ RaycastScene::~RaycastScene() {
|
||||||
// Update the physics world (take a simulation step)
|
// Update the physics world (take a simulation step)
|
||||||
void RaycastScene::updatePhysics() {
|
void RaycastScene::updatePhysics() {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take a step for the simulation
|
// Take a step for the simulation
|
||||||
|
|
|
@ -40,6 +40,8 @@ Shader Gui::mShader;
|
||||||
openglframework::VertexBufferObject Gui::mVBO(GL_ARRAY_BUFFER);
|
openglframework::VertexBufferObject Gui::mVBO(GL_ARRAY_BUFFER);
|
||||||
openglframework::VertexArrayObject Gui::mVAO;
|
openglframework::VertexArrayObject Gui::mVAO;
|
||||||
Gui::LeftPane Gui::mLeftPane = SCENES;
|
Gui::LeftPane Gui::mLeftPane = SCENES;
|
||||||
|
double Gui::mScrollX = 0.0;
|
||||||
|
double Gui::mScrollY = 0.0;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Gui::Gui() {
|
Gui::Gui() {
|
||||||
|
@ -61,13 +63,7 @@ Gui::~Gui() {
|
||||||
|
|
||||||
mShader.destroy();
|
mShader.destroy();
|
||||||
|
|
||||||
if (g_FontTexture)
|
imguiRenderGLDestroy();
|
||||||
{
|
|
||||||
glDeleteTextures(1, &g_FontTexture);
|
|
||||||
ImGui::GetIO().Fonts->TexID = 0;
|
|
||||||
g_FontTexture = 0;
|
|
||||||
}
|
|
||||||
ImGui::Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and return the singleton instance of this class
|
// Create and return the singleton instance of this class
|
||||||
|
@ -79,149 +75,196 @@ Gui& Gui::getInstance() {
|
||||||
/// Initialize the GUI
|
/// Initialize the GUI
|
||||||
void Gui::init() {
|
void Gui::init() {
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
// Init UI
|
||||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
if (!imguiRenderGLInit("DroidSans.ttf")) {
|
||||||
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
fprintf(stderr, "Could not init GUI renderer.\n");
|
||||||
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
exit(EXIT_FAILURE);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gui::displayHeader() {
|
void Gui::displayHeader() {
|
||||||
|
|
||||||
TestbedApplication& app = TestbedApplication::getInstance();
|
TestbedApplication& app = TestbedApplication::getInstance();
|
||||||
|
|
||||||
ImVec2 buttonSize(120, 40);
|
int windowWidth, windowHeight;
|
||||||
|
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||||
|
|
||||||
int display_w, display_h;
|
const int button_width = 150;
|
||||||
glfwGetFramebufferSize(mWindow, &display_w, &display_h);
|
|
||||||
|
|
||||||
ImGuiWindowFlags window_flags = 0;
|
int scrollarea = 0;
|
||||||
window_flags |= ImGuiWindowFlags_NoTitleBar;
|
imguiBeginScrollArea(NULL, 0, app.mWindowToFramebufferRatio.y * (windowHeight - HEADER_HEIGHT),
|
||||||
window_flags |= ImGuiWindowFlags_NoResize;
|
app.mWindowToFramebufferRatio.x * windowWidth,
|
||||||
window_flags |= ImGuiWindowFlags_NoMove;
|
app.mWindowToFramebufferRatio.y * HEADER_HEIGHT, &scrollarea);
|
||||||
|
|
||||||
ImGui::PushID("Header");
|
imguiStartLineOfItems();
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, BACKGROUND_COLOR);
|
|
||||||
|
|
||||||
ImGui::Begin("Header", NULL, ImVec2(display_w, HEADER_HEIGHT), 1.0f, window_flags);
|
// ----- Left Pane Header ----- //
|
||||||
ImGui::SetWindowPos(ImVec2(0, 0));
|
|
||||||
|
|
||||||
bool isRunning = app.mTimer.isRunning();
|
// Play/Pause
|
||||||
if (ImGui::Button(isRunning ? "Pause" : "Play", buttonSize)) {
|
if (imguiButton(app.mTimer.isRunning() ? "Pause" : "Play", true, button_width)) {
|
||||||
app.togglePlayPauseSimulation();
|
app.togglePlayPauseSimulation();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
if (ImGui::Button("Step", buttonSize)) {
|
// Step
|
||||||
app.toggleTakeSinglePhysicsStep();
|
if (imguiButton("Step", !app.mTimer.isRunning(), button_width)) {
|
||||||
}
|
app.toggleTakeSinglePhysicsStep();
|
||||||
ImGui::SameLine();
|
}
|
||||||
|
|
||||||
if (ImGui::Button("Restart", buttonSize)) {
|
// Restart
|
||||||
app.restartSimulation();
|
if (imguiButton("Restart", true, button_width)) {
|
||||||
}
|
app.restartSimulation();
|
||||||
ImGui::SameLine();
|
}
|
||||||
|
|
||||||
ImGui::End();
|
imguiEndLineOfItems();
|
||||||
|
imguiEndScrollArea();
|
||||||
ImGui::PopStyleColor(1);
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gui::displayLeftPane() {
|
void Gui::displayLeftPane() {
|
||||||
|
|
||||||
const int nbButtonsHeader = 4;
|
TestbedApplication& app = TestbedApplication::getInstance();
|
||||||
ImVec2 buttonSize(LEFT_PANE_WIDTH / nbButtonsHeader - 9, LEFT_PANE_HEADER_HEIGHT);
|
|
||||||
|
|
||||||
int display_w, display_h;
|
int windowWidth, windowHeight;
|
||||||
glfwGetFramebufferSize(mWindow, &display_w, &display_h);
|
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||||
|
|
||||||
ImGuiWindowFlags window_flags = 0;
|
int scrollarea = 0;
|
||||||
window_flags |= ImGuiWindowFlags_NoTitleBar;
|
imguiBeginScrollArea(NULL, 0, app.mWindowToFramebufferRatio.y * (windowHeight - HEADER_HEIGHT - LEFT_PANE_HEADER_HEIGHT),
|
||||||
window_flags |= ImGuiWindowFlags_NoResize;
|
app.mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||||
window_flags |= ImGuiWindowFlags_NoMove;
|
app.mWindowToFramebufferRatio.y * LEFT_PANE_HEADER_HEIGHT, &scrollarea);
|
||||||
|
|
||||||
ImGui::PushID("LeftPane");
|
imguiStartLineOfItems();
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, BACKGROUND_COLOR);
|
|
||||||
|
|
||||||
ImGui::Begin("LeftPane", NULL, ImVec2(LEFT_PANE_WIDTH, display_h - HEADER_HEIGHT), 1.0f, window_flags);
|
// ----- Left Pane Header ----- //
|
||||||
ImGui::SetWindowPos(ImVec2(0, HEADER_HEIGHT));
|
int widthButton = app.mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH / 5;
|
||||||
|
if (imguiButton("Scenes", true, widthButton)) {
|
||||||
|
mLeftPane = SCENES;
|
||||||
|
}
|
||||||
|
|
||||||
// ----- Left Pane Header ----- //
|
if (imguiButton("Physics", true, widthButton)) {
|
||||||
if (ImGui::Button("Scenes", buttonSize)) {
|
mLeftPane = PHYSICS;
|
||||||
mLeftPane = SCENES;
|
}
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
if (ImGui::Button("Physics", buttonSize)) {
|
imguiButton("Rendering", true, widthButton);
|
||||||
mLeftPane = PHYSICS;
|
imguiButton("Profiling", true, widthButton);
|
||||||
}
|
imguiEndLineOfItems();
|
||||||
ImGui::SameLine();
|
imguiEndScrollArea();
|
||||||
|
|
||||||
ImGui::Button("Rendering", buttonSize); ImGui::SameLine();
|
// Display the left pane content
|
||||||
ImGui::Button("Profiling", buttonSize);
|
switch(mLeftPane) {
|
||||||
|
case SCENES: displayScenesPane(); break;
|
||||||
// Display the left pane content
|
case PHYSICS: displayPhysicsPane(); break;
|
||||||
switch(mLeftPane) {
|
case RENDERING: displayRenderingPane(); break;
|
||||||
case SCENES: displayScenesPane(); break;
|
case PROFILING: displayProfilingPane(); break;
|
||||||
case PHYSICS: displayPhysicsPane(); break;
|
}
|
||||||
case RENDERING: displayRenderingPane(); break;
|
|
||||||
case PROFILING: displayProfilingPane(); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
ImGui::PopStyleColor(1);
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the list of scenes
|
// Display the list of scenes
|
||||||
void Gui::displayScenesPane() {
|
void Gui::displayScenesPane() {
|
||||||
|
|
||||||
|
TestbedApplication& app = TestbedApplication::getInstance();
|
||||||
|
|
||||||
static int choice = 0;
|
static int choice = 0;
|
||||||
int startChoice = choice;
|
int startChoice = choice;
|
||||||
TestbedApplication& app = TestbedApplication::getInstance();
|
int scrollarea = 1;
|
||||||
|
int windowWidth, windowHeight;
|
||||||
|
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||||
|
|
||||||
std::vector<Scene*> scenes = app.getScenes();
|
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 each scene
|
||||||
for (int i=0; i<scenes.size(); i++) {
|
for (int i=0; i<scenes.size(); i++) {
|
||||||
|
|
||||||
// Display a radio button
|
// 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) {
|
if (choice != startChoice) {
|
||||||
app.switchScene(scenes[choice]);
|
app.switchScene(scenes[choice]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imguiEndScrollArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gui::displayPhysicsPane() {
|
void Gui::displayPhysicsPane() {
|
||||||
|
|
||||||
TestbedApplication& app = TestbedApplication::getInstance();
|
TestbedApplication& app = TestbedApplication::getInstance();
|
||||||
|
|
||||||
// Physics time step
|
int windowWidth, windowHeight;
|
||||||
//float timestep = app.ge;
|
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
|
||||||
//ImGui::InputFloat("Timestep", ×tep, 0.01f, 1.0f);
|
|
||||||
|
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() {
|
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
|
// Display the GUI
|
||||||
void Gui::render() {
|
void Gui::render() {
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
TestbedApplication& app = TestbedApplication::getInstance();
|
||||||
//glfwPollEvents();
|
|
||||||
beginNewFrame();
|
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();
|
displayHeader();
|
||||||
displayLeftPane();
|
displayLeftPane();
|
||||||
|
|
||||||
ImGui::ShowTestWindow();
|
imguiEndFrame();
|
||||||
|
|
||||||
// Render the GUI
|
imguiRenderGLDraw(display_w, display_h);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
#define GUI_H
|
#define GUI_H
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include <imgui.h>
|
#include "imgui.h"
|
||||||
|
#include "imguiRenderGL3.h"
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include "openglframework.h"
|
#include "openglframework.h"
|
||||||
|
@ -35,9 +36,8 @@
|
||||||
// Constants
|
// Constants
|
||||||
const float GUI_SCALING = 2.0f;
|
const float GUI_SCALING = 2.0f;
|
||||||
const int HEADER_HEIGHT = 80;
|
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 int LEFT_PANE_HEADER_HEIGHT = 60;
|
||||||
const ImColor BACKGROUND_COLOR = ImColor(41, 41, 41, 255);
|
|
||||||
|
|
||||||
using namespace openglframework;
|
using namespace openglframework;
|
||||||
|
|
||||||
|
@ -72,21 +72,10 @@ class Gui {
|
||||||
static openglframework::VertexArrayObject mVAO;
|
static openglframework::VertexArrayObject mVAO;
|
||||||
static LeftPane mLeftPane;
|
static LeftPane mLeftPane;
|
||||||
|
|
||||||
|
static double mScrollX, mScrollY;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- 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 displayHeader();
|
||||||
static void displayLeftPane();
|
static void displayLeftPane();
|
||||||
|
|
||||||
|
@ -97,6 +86,9 @@ class Gui {
|
||||||
static void displayRenderingPane();
|
static void displayRenderingPane();
|
||||||
static void displayProfilingPane();
|
static void displayProfilingPane();
|
||||||
|
|
||||||
|
static void resetScroll();
|
||||||
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
@ -117,10 +109,22 @@ class Gui {
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
static void setWindow(GLFWwindow* window);
|
static void setWindow(GLFWwindow* window);
|
||||||
|
|
||||||
|
static void setScroll(double scrollX, double scrollY);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void Gui::setWindow(GLFWwindow* window) {
|
inline void Gui::setWindow(GLFWwindow* window) {
|
||||||
mWindow = 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
|
#endif
|
||||||
|
|
|
@ -155,6 +155,9 @@ class Scene {
|
||||||
/// Return a reference to the camera
|
/// Return a reference to the camera
|
||||||
const openglframework::Camera& getCamera() const;
|
const openglframework::Camera& getCamera() const;
|
||||||
|
|
||||||
|
/// Get the engine settings
|
||||||
|
EngineSettings getEngineSettings() const;
|
||||||
|
|
||||||
/// Set the engine settings
|
/// Set the engine settings
|
||||||
void setEngineSettings(const EngineSettings& settings);
|
void setEngineSettings(const EngineSettings& settings);
|
||||||
|
|
||||||
|
@ -186,6 +189,11 @@ inline void Scene::setWindowDimension(int width, int height) {
|
||||||
mWindowHeight = height;
|
mWindowHeight = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the engine settings
|
||||||
|
inline EngineSettings Scene::getEngineSettings() const {
|
||||||
|
return mEngineSettings;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the engine settings
|
// Set the engine settings
|
||||||
inline void Scene::setEngineSettings(const EngineSettings& settings) {
|
inline void Scene::setEngineSettings(const EngineSettings& settings) {
|
||||||
mEngineSettings = settings;
|
mEngineSettings = settings;
|
||||||
|
|
|
@ -53,12 +53,12 @@ TestbedApplication& TestbedApplication::getInstance() {
|
||||||
TestbedApplication::TestbedApplication() : mFPS(0), mNbFrames(0), mPreviousTime(0) {
|
TestbedApplication::TestbedApplication() : mFPS(0), mNbFrames(0), mPreviousTime(0) {
|
||||||
|
|
||||||
mCurrentScene = NULL;
|
mCurrentScene = NULL;
|
||||||
mEngineSettings.timeStep = DEFAULT_TIMESTEP;
|
|
||||||
mIsMultisamplingActive = true;
|
mIsMultisamplingActive = true;
|
||||||
mWidth = 1280;
|
mWidth = 1280;
|
||||||
mHeight = 720;
|
mHeight = 720;
|
||||||
mSinglePhysicsStepEnabled = false;
|
mSinglePhysicsStepEnabled = false;
|
||||||
mSinglePhysicsStepDone = false;
|
mSinglePhysicsStepDone = false;
|
||||||
|
mWindowToFramebufferRatio = Vector2(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
|
@ -164,7 +164,11 @@ void TestbedApplication::createScenes() {
|
||||||
mScenes.push_back(raycastScene);
|
mScenes.push_back(raycastScene);
|
||||||
|
|
||||||
assert(mScenes.size() > 0);
|
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
|
// Remove all the scenes
|
||||||
|
@ -236,20 +240,25 @@ void TestbedApplication::update() {
|
||||||
// Render
|
// Render
|
||||||
void TestbedApplication::render() {
|
void TestbedApplication::render() {
|
||||||
|
|
||||||
// Get the framebuffer dimension
|
int bufferWidth, bufferHeight;
|
||||||
int width, height;
|
glfwGetFramebufferSize(mWindow, &bufferWidth, &bufferHeight);
|
||||||
glfwGetFramebufferSize(mWindow, &width, &height);
|
|
||||||
|
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
|
// Resize the OpenGL viewport
|
||||||
glViewport(LEFT_PANE_WIDTH, HEADER_HEIGHT,
|
glViewport(mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||||
width - LEFT_PANE_WIDTH, height - HEADER_HEIGHT);
|
0,
|
||||||
|
bufferWidth - mWindowToFramebufferRatio.x * LEFT_PANE_WIDTH,
|
||||||
|
bufferHeight - mWindowToFramebufferRatio.y * HEADER_HEIGHT);
|
||||||
|
|
||||||
// Render the scene
|
// Render the scene
|
||||||
mCurrentScene->render();
|
mCurrentScene->render();
|
||||||
|
|
||||||
// Resize the OpenGL viewport
|
|
||||||
glViewport(0, 0, width, height);
|
|
||||||
|
|
||||||
// Display the GUI
|
// Display the GUI
|
||||||
Gui::getInstance().render();
|
Gui::getInstance().render();
|
||||||
|
|
||||||
|
@ -311,6 +320,11 @@ void TestbedApplication::switchScene(Scene* newScene) {
|
||||||
|
|
||||||
mCurrentScene = newScene;
|
mCurrentScene = newScene;
|
||||||
|
|
||||||
|
// Get the engine settings of the scene
|
||||||
|
float currentTimeStep = mEngineSettings.timeStep;
|
||||||
|
mEngineSettings = mCurrentScene->getEngineSettings();
|
||||||
|
mEngineSettings.timeStep = currentTimeStep;
|
||||||
|
|
||||||
// Reset the scene
|
// Reset the scene
|
||||||
mCurrentScene->reset();
|
mCurrentScene->reset();
|
||||||
}
|
}
|
||||||
|
@ -397,6 +411,10 @@ void TestbedApplication::keyboard(GLFWwindow* window, int key, int scancode,
|
||||||
|
|
||||||
// Callback method to receive scrolling events
|
// Callback method to receive scrolling events
|
||||||
void TestbedApplication::scroll(GLFWwindow* window, double xAxis, double yAxis) {
|
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);
|
getInstance().mCurrentScene->scrollingEvent(xAxis, yAxis, SCROLL_SENSITIVITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,8 @@ class TestbedApplication {
|
||||||
/// True if the single physics step has been taken already
|
/// True if the single physics step has been taken already
|
||||||
bool mSinglePhysicsStepDone;
|
bool mSinglePhysicsStepDone;
|
||||||
|
|
||||||
|
openglframework::Vector2 mWindowToFramebufferRatio;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Private constructor (for the singleton class)
|
/// Private constructor (for the singleton class)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user