RigsofRods
Soft-body Physics Simulation
OgreImGuiOverlay.cpp
Go to the documentation of this file.
1 // This file is part of the OGRE project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at https://www.ogre3d.org/licensing.
4 
5 #include <imgui.h>
6 
7 #include <OgreImGuiOverlay.h>
8 #include <OgreHardwareBufferManager.h>
9 #include <OgreHardwarePixelBuffer.h>
10 #include <OgreRenderSystem.h>
11 #include <OgreTextureManager.h>
12 #include <OgreMaterialManager.h>
13 #include <OgreOverlayManager.h>
14 #include <OgreFontManager.h>
15 #include <OgreTechnique.h>
16 #include <OgreTextureUnitState.h>
17 #include <OgreFont.h>
18 #include <OgreRenderQueue.h>
19 #include <OgreFrameListener.h>
20 #include <OgreRoot.h>
21 
22 namespace Ogre
23 {
24 
25 ImGuiOverlay::ImGuiOverlay() : Overlay("ImGuiOverlay")
26 {
27  ImGui::CreateContext();
28  ImGuiIO& io = ImGui::GetIO();
29 
30  io.BackendPlatformName = "OGRE";
31 }
33 {
34  ImGui::DestroyContext();
35 }
36 
38 {
39  if (!mInitialised)
40  {
42  mCodePointRanges.clear();
43  }
44  mInitialised = true;
45 }
46 
47 //-----------------------------------------------------------------------------------
48 void ImGuiOverlay::_findVisibleObjects(Camera* cam, RenderQueue* queue, Viewport* vp)
49 {
50  if (!mVisible)
51  return;
52 
54  queue->addRenderable(&mRenderable, RENDER_QUEUE_OVERLAY, mZOrder * 100);
55 }
56 //-----------------------------------------------------------------------------------
58 {
59  mMaterial = MaterialManager::getSingleton().create("ImGui/material", RGN_INTERNAL);
60  Pass* mPass = mMaterial->getTechnique(0)->getPass(0);
61  mPass->setCullingMode(CULL_NONE);
62  mPass->setVertexColourTracking(TVC_DIFFUSE);
63  mPass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
64  mPass->setSeparateSceneBlendingOperation(SBO_ADD, SBO_ADD);
65  mPass->setSeparateSceneBlending(SBF_SOURCE_ALPHA, SBF_ONE_MINUS_SOURCE_ALPHA,
66  SBF_ONE_MINUS_SOURCE_ALPHA, SBF_ZERO);
67 
68  TextureUnitState* mTexUnit = mPass->createTextureUnitState();
69  mTexUnit->setTexture(mFontTex);
70  mTexUnit->setTextureFiltering(TFO_NONE);
71 
72  mMaterial->load();
73  mMaterial->setLightingEnabled(false);
74  mMaterial->setDepthCheckEnabled(false);
75 }
76 
77 ImFont* ImGuiOverlay::addFont(const String& name, const String& group)
78 {
79  FontPtr font = FontManager::getSingleton().getByName(name, group);
80  OgreAssert(font, "font does not exist");
81  OgreAssert(font->getType() == FT_TRUETYPE, "font must be of FT_TRUETYPE");
82  DataStreamPtr dataStreamPtr =
83  ResourceGroupManager::getSingleton().openResource(font->getSource(), font->getGroup());
84  MemoryDataStream ttfchunk(dataStreamPtr, false); // transfer ownership to imgui
85 
86  // convert codepoint ranges for imgui
87  CodePointRange cprange;
88  for (const auto& r : font->getCodePointRangeList())
89  {
90  cprange.push_back(r.first);
91  cprange.push_back(r.second);
92  }
93 
94  ImGuiIO& io = ImGui::GetIO();
95  const ImWchar* cprangePtr = io.Fonts->GetGlyphRangesAll();
96  if (!cprange.empty())
97  {
98  cprange.push_back(0); // terminate
99  mCodePointRanges.push_back(cprange);
100  // ptr must persist until createFontTexture
101  cprangePtr = mCodePointRanges.back().data();
102  }
103 
104  ImFontConfig cfg;
105  strncpy(cfg.Name, name.c_str(), 40);
106  return io.Fonts->AddFontFromMemoryTTF(ttfchunk.getPtr(), (int)ttfchunk.size(), font->getTrueTypeSize(), &cfg,
107  cprangePtr);
108 }
109 
111 {
112  // Build texture atlas
113  ImGuiIO& io = ImGui::GetIO();
114  if (io.Fonts->Fonts.empty())
115  io.Fonts->AddFontDefault();
116 
117  unsigned char* pixels;
118  int width, height;
119  io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
120 
121  mFontTex = TextureManager::getSingleton().createManual("ImGui/FontTex", RGN_INTERNAL, TEX_TYPE_2D,
122  width, height, 1, 1, PF_BYTE_RGBA);
123 
124  mFontTex->getBuffer()->blitFromMemory(PixelBox(Box(0, 0, width, height), PF_BYTE_RGBA, pixels));
125 }
126 void ImGuiOverlay::NewFrame(const FrameEvent& evt)
127 {
128  ImGuiIO& io = ImGui::GetIO();
129  io.DeltaTime = std::max<float>(
130  evt.timeSinceLastFrame,
131  1e-4f); // see https://github.com/ocornut/imgui/commit/3c07ec6a6126fb6b98523a9685d1f0f78ca3c40c
132 
133  // Read keyboard modifiers inputs
134  io.KeyAlt = false;
135  io.KeySuper = false;
136 
137  OverlayManager& oMgr = OverlayManager::getSingleton();
138 
139  // Setup display size (every frame to accommodate for window resizing)
140  io.DisplaySize = ImVec2(oMgr.getViewportWidth(), oMgr.getViewportHeight());
141 
142  // Start the frame
143  ImGui::NewFrame();
144 }
145 
147 {
148  if (mMaterial->getSupportedTechniques().empty())
149  {
150  mMaterial->load(); // Support for adding lights run time
151  }
152 
153  RenderSystem* rSys = Root::getSingleton().getRenderSystem();
154  OverlayManager& oMgr = OverlayManager::getSingleton();
155 
156  // Construct projection matrix, taking texel offset corrections in account (important for DirectX9)
157  // See also:
158  // - OGRE-API specific hint: http://www.ogre3d.org/forums/viewtopic.php?f=5&p=536881#p536881
159  // - IMGUI Dx9 demo solution:
160  // https://github.com/ocornut/imgui/blob/master/examples/directx9_example/imgui_impl_dx9.cpp#L127-L138
161  float texelOffsetX = rSys->getHorizontalTexelOffset();
162  float texelOffsetY = rSys->getVerticalTexelOffset();
163  float L = texelOffsetX;
164  float R = oMgr.getViewportWidth() + texelOffsetX;
165  float T = texelOffsetY;
166  float B = oMgr.getViewportHeight() + texelOffsetY;
167 
168  mXform = Matrix4(2.0f / (R - L), 0.0f, 0.0f, (L + R) / (L - R), 0.0f, -2.0f / (B - T), 0.0f,
169  (T + B) / (B - T), 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
170 }
171 
172 bool ImGuiOverlay::ImGUIRenderable::preRender(SceneManager* sm, RenderSystem* rsys)
173 {
174  Viewport* vp = rsys->_getViewport();
175 
176  // Instruct ImGui to Render() and process the resulting CmdList-s
177  // Adopted from https://bitbucket.org/ChaosCreator/imgui-ogre2.1-binding
178  // ... Commentary on OGRE forums: http://www.ogre3d.org/forums/viewtopic.php?f=5&t=89081#p531059
179  ImGui::Render();
180  ImDrawData* draw_data = ImGui::GetDrawData();
181  int vpWidth = vp->getActualWidth();
182  int vpHeight = vp->getActualHeight();
183 
184  TextureUnitState* tu = mMaterial->getBestTechnique()->getPass(0)->getTextureUnitState(0);
185 
186  for (int i = 0; i < draw_data->CmdListsCount; ++i)
187  {
188  const ImDrawList* draw_list = draw_data->CmdLists[i];
189  updateVertexData(draw_list->VtxBuffer, draw_list->IdxBuffer);
190 
191  unsigned int startIdx = 0;
192 
193  for (int j = 0; j < draw_list->CmdBuffer.Size; ++j)
194  {
195  // Create a renderable and fill it's buffers
196  const ImDrawCmd* drawCmd = &draw_list->CmdBuffer[j];
197 
198  // Set scissoring
199  Rect scissor(drawCmd->ClipRect.x, drawCmd->ClipRect.y, drawCmd->ClipRect.z,
200  drawCmd->ClipRect.w);
201 
202  // Clamp bounds to viewport dimensions
203  scissor = scissor.intersect(Rect(0, 0, vpWidth, vpHeight));
204 
205  if (drawCmd->TextureId)
206  {
207  auto handle = (ResourceHandle)drawCmd->TextureId;
208  auto tex = static_pointer_cast<Texture>(TextureManager::getSingleton().getByHandle(handle));
209  if (tex)
210  {
211  rsys->_setTexture(0, true, tex);
212  rsys->_setSampler(0, *TextureManager::getSingleton().getDefaultSampler());
213  }
214  }
215 
216  rsys->setScissorTest(true, scissor.left, scissor.top, scissor.right, scissor.bottom);
217 
218  // Render!
219  mRenderOp.indexData->indexStart = startIdx;
220  mRenderOp.indexData->indexCount = drawCmd->ElemCount;
221 
222  rsys->_render(mRenderOp);
223 
224  if (drawCmd->TextureId)
225  {
226  // reset to pass state
227  rsys->_setTexture(0, true, mFontTex);
228  rsys->_setSampler(0, *tu->getSampler());
229  }
230 
231  // Update counts
232  startIdx += drawCmd->ElemCount;
233  }
234  }
235  rsys->setScissorTest(false);
236  return false;
237 }
238 
240 {
241  // Overlayelements should not be lit by the scene, this will not get called
242  static LightList ll;
243  return ll;
244 }
245 
247 {
248  // default overlays to preserve their own detail level
249  mPolygonModeOverrideable = false;
250 
251  // use identity projection and view matrices
252  mUseIdentityProjection = true;
253  mUseIdentityView = true;
254 
255  mConvertToBGR = false;
256 }
257 //-----------------------------------------------------------------------------------
259 {
260  createFontTexture();
261  createMaterial();
262 
263  mRenderOp.vertexData = OGRE_NEW VertexData();
264  mRenderOp.indexData = OGRE_NEW IndexData();
265 
266  mRenderOp.vertexData->vertexCount = 0;
267  mRenderOp.vertexData->vertexStart = 0;
268 
269  mRenderOp.indexData->indexCount = 0;
270  mRenderOp.indexData->indexStart = 0;
271  mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST;
272  mRenderOp.useIndexes = true;
273  mRenderOp.useGlobalInstancingVertexBufferIsAvailable = false;
274 
275  VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
276 
277  // vertex declaration
278  size_t offset = 0;
279  decl->addElement(0, offset, VET_FLOAT2, VES_POSITION);
280  offset += VertexElement::getTypeSize(VET_FLOAT2);
281  decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
282  offset += VertexElement::getTypeSize(VET_FLOAT2);
283  decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
284 
285  if (Root::getSingleton().getRenderSystem()->getName().find("Direct3D9") != String::npos)
286  mConvertToBGR = true;
287 }
288 //-----------------------------------------------------------------------------------
290 {
291  OGRE_DELETE mRenderOp.vertexData;
292  OGRE_DELETE mRenderOp.indexData;
293 }
294 //-----------------------------------------------------------------------------------
295 void ImGuiOverlay::ImGUIRenderable::updateVertexData(const ImVector<ImDrawVert>& vtxBuf,
296  const ImVector<ImDrawIdx>& idxBuf)
297 {
298  VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding;
299 
300  if (bind->getBindings().empty() || bind->getBuffer(0)->getNumVertices() != size_t(vtxBuf.size()))
301  {
302  bind->setBinding(0, HardwareBufferManager::getSingleton().createVertexBuffer(
303  sizeof(ImDrawVert), vtxBuf.size(), HardwareBuffer::HBU_WRITE_ONLY));
304  }
305  if (!mRenderOp.indexData->indexBuffer ||
306  mRenderOp.indexData->indexBuffer->getNumIndexes() != size_t(idxBuf.size()))
307  {
308  mRenderOp.indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
309  HardwareIndexBuffer::IT_32BIT, idxBuf.size(), HardwareBuffer::HBU_WRITE_ONLY);
310  }
311 
312  if (mConvertToBGR)
313  {
314  // convert RGBA > BGRA
315  PixelBox src(1, vtxBuf.size(), 1, PF_A8B8G8R8, (char*)vtxBuf.Data + offsetof(ImDrawVert, col));
316  src.rowPitch = sizeof(ImDrawVert) / sizeof(ImU32);
317  PixelBox dst = src;
318  dst.format = PF_A8R8G8B8;
319  PixelUtil::bulkPixelConversion(src, dst);
320  }
321 
322  // Copy all vertices
323  bind->getBuffer(0)->writeData(0, vtxBuf.size_in_bytes(), vtxBuf.Data, true);
324  mRenderOp.indexData->indexBuffer->writeData(0, idxBuf.size_in_bytes(), idxBuf.Data, true);
325 
326  mRenderOp.vertexData->vertexStart = 0;
327  mRenderOp.vertexData->vertexCount = vtxBuf.size();
328 }
329 } // namespace Ogre
Ogre::ImGuiOverlay::NewFrame
static void NewFrame(const FrameEvent &evt)
Definition: OgreImGuiOverlay.cpp:126
Ogre::ImGuiOverlay::ImGUIRenderable::~ImGUIRenderable
~ImGUIRenderable()
Definition: OgreImGuiOverlay.cpp:289
Ogre::ImGuiOverlay::CodePointRange
std::vector< ImWchar > CodePointRange
Definition: OgreImGuiOverlay.h:31
Ogre::ImGuiOverlay::ImGUIRenderable::updateVertexData
void updateVertexData(const ImVector< ImDrawVert > &vtxBuf, const ImVector< ImDrawIdx > &idxBuf)
Definition: OgreImGuiOverlay.cpp:295
Ogre::ImGuiOverlay::_findVisibleObjects
void _findVisibleObjects(Camera *cam, RenderQueue *queue, Viewport *vp)
Definition: OgreImGuiOverlay.cpp:48
Ogre::ImGuiOverlay::addFont
ImFont * addFont(const String &name, const String &group OGRE_RESOURCE_GROUP_INIT)
add font from ogre .fontdef file must be called before first show()
Definition: OgreImGuiOverlay.cpp:77
Ogre::ImGuiOverlay::ImGUIRenderable::preRender
bool preRender(SceneManager *sm, RenderSystem *rsys)
Definition: OgreImGuiOverlay.cpp:172
Ogre::ImGuiOverlay::mRenderable
ImGUIRenderable mRenderable
Definition: OgreImGuiOverlay.h:68
Ogre::ImGuiOverlay::ImGUIRenderable::createMaterial
void createMaterial()
Definition: OgreImGuiOverlay.cpp:57
Ogre::ImGuiOverlay::ImGUIRenderable::getLights
const LightList & getLights(void) const
Definition: OgreImGuiOverlay.cpp:239
Ogre::ImGuiOverlay::~ImGuiOverlay
~ImGuiOverlay()
Definition: OgreImGuiOverlay.cpp:32
Ogre::ImGuiOverlay::ImGUIRenderable::createFontTexture
void createFontTexture()
Definition: OgreImGuiOverlay.cpp:110
OgreImGuiOverlay.h
Ogre::ImGuiOverlay::ImGUIRenderable::_update
void _update()
Definition: OgreImGuiOverlay.cpp:146
Ogre::ImGuiOverlay::mCodePointRanges
std::vector< CodePointRange > mCodePointRanges
Definition: OgreImGuiOverlay.h:32
Ogre
Definition: ExtinguishableFireAffector.cpp:35
Ogre::ImGuiOverlay::ImGUIRenderable::ImGUIRenderable
ImGUIRenderable()
Definition: OgreImGuiOverlay.cpp:246
Ogre::ImGuiOverlay::ImGUIRenderable::mMaterial
MaterialPtr mMaterial
Definition: OgreImGuiOverlay.h:65
Ogre::ImGuiOverlay::ImGUIRenderable::mFontTex
TexturePtr mFontTex
Definition: OgreImGuiOverlay.h:64
Ogre::ImGuiOverlay::initialise
void initialise()
Definition: OgreImGuiOverlay.cpp:37
Ogre::ImGuiOverlay::ImGUIRenderable::initialise
void initialise()
Definition: OgreImGuiOverlay.cpp:258
Ogre::ImGuiOverlay::ImGuiOverlay
ImGuiOverlay()
Definition: OgreImGuiOverlay.cpp:25