Skip to content

Instantly share code, notes, and snippets.

@hb3p8
Created January 29, 2016 08:33
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hb3p8/52ac227f77e8accf96cf to your computer and use it in GitHub Desktop.
Save hb3p8/52ac227f77e8accf96cf to your computer and use it in GitHub Desktop.
ImGui OSG wrapper
#include <ImGuiHandler.hpp>
#include <imgui/imgui.h>
#include <iostream>
using namespace sf;
// 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 ImGui_RenderDrawLists (ImDrawData* draw_data)
{
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glDisable (GL_LIGHTING);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
//glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)
ImGuiIO& io = ImGui::GetIO();
float fb_height = io.DisplaySize.y * io.DisplayFramebufferScale.y;
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// Setup orthographic projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Render command lists
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->VtxBuffer.front();
const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front();
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos)));
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv)));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col)));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, GL_UNSIGNED_SHORT, idx_buffer);
}
idx_buffer += pcmd->ElemCount;
}
}
#undef OFFSETOF
// Restore modified state
// glDisableClientState(GL_COLOR_ARRAY);
// glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, last_texture);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
struct ImGuiNewFrameCallback : public osg::Camera::DrawCallback {
ImGuiNewFrameCallback (ImGuiHandler& theHandler)
: m_handler (theHandler)
{}
virtual void operator () (osg::RenderInfo& theRenderInfo) const {
m_handler.newFrame (theRenderInfo);
}
private:
ImGuiHandler& m_handler;
};
struct ImGuiDrawCallback : public osg::Camera::DrawCallback {
ImGuiDrawCallback (ImGuiHandler& theHandler)
: m_handler (theHandler)
{}
virtual void operator () (osg::RenderInfo& theRenderInfo) const {
m_handler.render (theRenderInfo);
}
private:
ImGuiHandler& m_handler;
};
ImGuiHandler::ImGuiHandler (GuiCallback *theGuicallback)
: m_callback (theGuicallback) {
g_Time = 0.0f;
for (int i = 0; i < 3; ++i)
g_MousePressed[i] = false;
g_MouseWheel = 0.0f;
g_FontTexture = 0;
}
void ImGuiHandler::init() {
ImGuiIO& io = ImGui::GetIO();
// Build texture atlas
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
// Create OpenGL texture
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
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_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
// Cleanup (don't clear the input data if you want to append new fonts later)
io.Fonts->ClearInputData();
io.Fonts->ClearTexData();
glBindTexture(GL_TEXTURE_2D, last_texture);
io.RenderDrawListsFn = ImGui_RenderDrawLists;
}
void ImGuiHandler::setCameraCallbacks (osg::Camera *theCamera) {
ImGuiDrawCallback* aPostDrawCallback = new ImGuiDrawCallback (*this);
theCamera->setPostDrawCallback (aPostDrawCallback);
ImGuiNewFrameCallback* aPreDrawCallback = new ImGuiNewFrameCallback (*this);
theCamera->setPreDrawCallback (aPreDrawCallback);
}
void ImGuiHandler::newFrame (osg::RenderInfo& theRenderInfo) {
if (!g_FontTexture) {
init();
}
ImGuiIO& io = ImGui::GetIO();
osg::Viewport* aViewport = theRenderInfo.getCurrentCamera()->getViewport();
io.DisplaySize = ImVec2(aViewport->width(), aViewport->height());
double aCurrentTime = theRenderInfo.getView()->getFrameStamp()->getSimulationTime();
io.DeltaTime = g_Time > 0.0 ? (float)(aCurrentTime - g_Time) : (float)(1.0f/60.0f);
g_Time = aCurrentTime;
for (int i = 0; i < 3; i++)
{
io.MouseDown[i] = g_MousePressed[i];
// g_MousePressed[i] = false;
}
io.MouseWheel = g_MouseWheel;
g_MouseWheel = 0.0f;
ImGui::NewFrame();
}
void ImGuiHandler::render (osg::RenderInfo& /*theRenderInfo*/) {
if (m_callback) {
(*m_callback)();
}
ImGui::Render();
}
bool ImGuiHandler::handle (const osgGA::GUIEventAdapter &theEventAdapter,
osgGA::GUIActionAdapter &theActionAdapter,
osg::Object *theObject,
osg::NodeVisitor *theNodeVisitor) {
bool wantCapureMouse = ImGui::GetIO().WantCaptureMouse;
bool wantCapureKeyboard = ImGui::GetIO().WantCaptureKeyboard;
switch (theEventAdapter.getEventType()) {
case osgGA::GUIEventAdapter::KEYDOWN: {
ImGuiIO& io = ImGui::GetIO();
int c = theEventAdapter.getKey();
if (c > 0 && c < 0x10000) {
io.AddInputCharacter((unsigned short)c);
}
std::cout << c << std::endl << std::flush;
return wantCapureKeyboard;
}
case(osgGA::GUIEventAdapter::PUSH):
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2 (theEventAdapter.getX(), io.DisplaySize.y - theEventAdapter.getY());
g_MousePressed[0] = true;
return wantCapureMouse;
}
case(osgGA::GUIEventAdapter::DRAG):
case(osgGA::GUIEventAdapter::MOVE):
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2 (theEventAdapter.getX(), io.DisplaySize.y - theEventAdapter.getY());
return wantCapureMouse;
}
case(osgGA::GUIEventAdapter::RELEASE):
{
g_MousePressed[0] = false;
return wantCapureMouse;
}
case(osgGA::GUIEventAdapter::SCROLL):
{
g_MouseWheel = theEventAdapter.getScrollingDeltaY();
return wantCapureMouse;
}
default:
{
return false;
}
}
return false;
}
bool ImGui::SliderReal (const char *label, double *v, float v_min, float v_max, const char *display_format, float power)
{
float aValue = *v;
if (ImGui::SliderFloat (label, &aValue, v_min, v_max, display_format, power)) {
*v = aValue;
return true;
}
return false;
}
#ifndef UTILS_IMGUI_HANDLER_HEADER
#define UTILS_IMGUI_HANDLER_HEADER
#ifdef _WIN32
#define NOMINMAX
#include <windows.h>
#endif
#include <osgViewer/ViewerEventHandlers>
#include <osg/Camera>
namespace sf {
struct GuiCallback
{
virtual void operator () () {}
};
class ImGuiHandler : public osgGA::GUIEventHandler {
public:
ImGuiHandler (GuiCallback* theGuicallback);
void init();
void newFrame (osg::RenderInfo& theRenderInfo);
void render (osg::RenderInfo& theRenderInfo);
void setCameraCallbacks (osg::Camera* theCamera);
virtual bool handle(const osgGA::GUIEventAdapter& theEventAdapter,
osgGA::GUIActionAdapter& theActionAdapter,
osg::Object* theObject,
osg::NodeVisitor* theNodeVisitor);
private:
GuiCallback* m_callback;
double g_Time;
bool g_MousePressed[3];
float g_MouseWheel;
GLuint g_FontTexture;
};
} // namespace sf
namespace ImGui {
bool SliderReal (const char* label, double* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
}
#endif // UTILS_IMGUI_HANDLER_HEADER
@Raizel
Copy link

Raizel commented Jun 21, 2016

Please, example, how to use it?

@Raizel
Copy link

Raizel commented Jul 31, 2016

Здравствуйте, Данила! Ещё раз прошу вас добавить пример использования этого хэндлера ImGUI для OpenSceneGraph.

@colesnicov
Copy link

Здравствуйте Raizel. вы уже знаете как это использовать?

@colesnicov
Copy link

colesnicov commented Dec 24, 2016

Та что братан. У тебя получилось? Я в си++ и OSG только начинаю (учусь)... Короче, я тут пару часов поигрался и вот что у меня получилось... Это работает с половины, IMGUI не принимает вступ од пользователя. Я почитаю как надо работать с OSG и попытаюсь всю отладить. Покамис хоть текст показывает :) Вот тебе ссылка на gist

@Raizel
Copy link

Raizel commented Feb 4, 2017

Нет, не получилось использовать. Надо будет переписать пример. Всё-таки, IMGUI - отличная вещь!
Что касается OSG, его стоит изучать. Гибкость этого движка впечатляет. Ogre3D по сравнению с ним - полная фигня.
Один большой недостаток OSG - он абсолютно не подходит для игр. Очень много нужно допиливать.

@hb3p8
Copy link
Author

hb3p8 commented Feb 20, 2018

@cxw42
Copy link

cxw42 commented Aug 4, 2018

@Megaton Thank you! What is the license for this code? (I'll ask fulezi the same.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment