public void UpdateMesh(ImDrawCmd cmd, ImVector_ushort idxBuffer, ImVector_ImDrawVert vtxBuffer, int startIndex) { mesh.Clear(); // recreate arrays only if too small if (vertices.Length < vtxBuffer.Size) { vertices = new Vector3[vtxBuffer.Size]; uv = new Vector2[vtxBuffer.Size]; colors = new Color32[vtxBuffer.Size]; } // Unity can't hoist Screen.height fetch from the loop // Fine, we'll do it ourselves int screenHeight = Screen.height; // populate mesh from draw data for (int i = 0; i < vtxBuffer.Size; i++) { ImDrawVert vertex = vtxBuffer[i]; vertices[i].x = vertex.pos.x; vertices[i].y = screenHeight - vertex.pos.y; vertices[i].z = 0.0f; uv[i].x = vertex.uv.x; uv[i].y = vertex.uv.y; colors[i].a = (byte)((vertex.col >> 24) & 255); colors[i].b = (byte)((vertex.col >> 16) & 255); colors[i].g = (byte)((vertex.col >> 8) & 255); colors[i].r = (byte)((vertex.col) & 255); } if (triangles.Length != cmd.ElemCount) { triangles = new int[cmd.ElemCount]; } for (int i = 0; i < cmd.ElemCount; i++) { triangles[i] = idxBuffer[i + startIndex]; } mesh.vertices = vertices; mesh.uv = uv; mesh.colors32 = colors; mesh.triangles = triangles; }
public static void RenderDrawData(ImDrawData drawData, int displayW, int displayH) { // 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. int lastTexture; GL.GetIntegerv(GL.Enum.GL_TEXTURE_BINDING_2D, out lastTexture); Int4 lastViewport; GL.GetIntegerv4(GL.Enum.GL_VIEWPORT, out lastViewport); Int4 lastScissorBox; GL.GetIntegerv4(GL.Enum.GL_SCISSOR_BOX, out lastScissorBox); GL.PushAttrib(GL.Enum.GL_ENABLE_BIT | GL.Enum.GL_COLOR_BUFFER_BIT | GL.Enum.GL_TRANSFORM_BIT); GL.Enable(GL.Enum.GL_BLEND); GL.BlendFunc(GL.Enum.GL_SRC_ALPHA, GL.Enum.GL_ONE_MINUS_SRC_ALPHA); GL.Disable(GL.Enum.GL_CULL_FACE); GL.Disable(GL.Enum.GL_DEPTH_TEST); GL.Enable(GL.Enum.GL_SCISSOR_TEST); GL.EnableClientState(GL.Enum.GL_VERTEX_ARRAY); GL.EnableClientState(GL.Enum.GL_TEXTURE_COORD_ARRAY); GL.EnableClientState(GL.Enum.GL_COLOR_ARRAY); GL.Enable(GL.Enum.GL_TEXTURE_2D); GL.UseProgram(0); // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) ImGuiIO io = ImGui.GetIO(); ImGui.ScaleClipRects(drawData, io.DisplayFramebufferScale); // Setup orthographic projection matrix GL.Viewport(0, 0, displayW, displayH); GL.MatrixMode(GL.Enum.GL_PROJECTION); GL.PushMatrix(); GL.LoadIdentity(); GL.Ortho( 0.0f, io.DisplaySize.X / io.DisplayFramebufferScale.X, io.DisplaySize.Y / io.DisplayFramebufferScale.Y, 0.0f, -1.0f, 1.0f ); GL.MatrixMode(GL.Enum.GL_MODELVIEW); GL.PushMatrix(); GL.LoadIdentity(); // Render command lists for (int n = 0; n < drawData.CmdListsCount; n++) { ImDrawList cmdList = drawData[n]; ImVector <ImDrawVert> vtxBuffer = cmdList.VtxBuffer; ImVector <ushort> idxBuffer = cmdList.IdxBuffer; GL.VertexPointer(2, GL.Enum.GL_FLOAT, ImDrawVert.Size, new IntPtr((long)vtxBuffer.Data + ImDrawVert.PosOffset)); GL.TexCoordPointer(2, GL.Enum.GL_FLOAT, ImDrawVert.Size, new IntPtr((long)vtxBuffer.Data + ImDrawVert.UVOffset)); GL.ColorPointer(4, GL.Enum.GL_UNSIGNED_BYTE, ImDrawVert.Size, new IntPtr((long)vtxBuffer.Data + ImDrawVert.ColOffset)); long idxBufferOffset = 0; for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++) { ImDrawCmd pcmd = cmdList.CmdBuffer[cmdi]; if (pcmd.UserCallback != IntPtr.Zero) { pcmd.InvokeUserCallback(ref cmdList, ref pcmd); } else { GL.BindTexture(GL.Enum.GL_TEXTURE_2D, (int)pcmd.TextureId); GL.Scissor( (int)pcmd.ClipRect.X, (int)(io.DisplaySize.Y - pcmd.ClipRect.W), (int)(pcmd.ClipRect.Z - pcmd.ClipRect.X), (int)(pcmd.ClipRect.W - pcmd.ClipRect.Y) ); GL.DrawElements(GL.Enum.GL_TRIANGLES, (int)pcmd.ElemCount, GL.Enum.GL_UNSIGNED_SHORT, new IntPtr((long)idxBuffer.Data + idxBufferOffset)); } idxBufferOffset += pcmd.ElemCount * 2 /*sizeof(ushort)*/; } } // Restore modified state GL.DisableClientState(GL.Enum.GL_COLOR_ARRAY); GL.DisableClientState(GL.Enum.GL_TEXTURE_COORD_ARRAY); GL.DisableClientState(GL.Enum.GL_VERTEX_ARRAY); GL.BindTexture(GL.Enum.GL_TEXTURE_2D, lastTexture); GL.MatrixMode(GL.Enum.GL_MODELVIEW); GL.PopMatrix(); GL.MatrixMode(GL.Enum.GL_PROJECTION); GL.PopMatrix(); GL.PopAttrib(); GL.Viewport(lastViewport.X, lastViewport.Y, lastViewport.Z, lastViewport.W); GL.Scissor(lastScissorBox.X, lastScissorBox.Y, lastScissorBox.Z, lastScissorBox.W); }
void LateUpdate() { last_start = stopwatch.Elapsed.TotalSeconds; if (drawDebugWindow) { DrawDebugWindow(); } ImGui.EndFrame(); if (queue_font_rebuild) { RebuildFonts(); queue_font_rebuild = false; } // custom cursors if (enableCustomCursors) { ImGuiMouseCursor cursor = ImGui.GetMouseCursor(); Texture2D cursorTex = null; Vector2 hotspot = cursorHotspot; switch (cursor) { case ImGuiMouseCursor.Arrow: cursorTex = customCursorArrow; break; case ImGuiMouseCursor.TextInput: cursorTex = customCursorTextInput; break; case ImGuiMouseCursor.ResizeEW: cursorTex = customCursorResizeEW; break; case ImGuiMouseCursor.ResizeNESW: cursorTex = customCursorResizeNESW; hotspot.x += 5; hotspot.y += 5; break; case ImGuiMouseCursor.ResizeNS: cursorTex = customCursorResizeNS; break; case ImGuiMouseCursor.ResizeNWSE: cursorTex = customCursorResizeNWSE; hotspot.x += 5; hotspot.y += 5; break; default: break; } // Don't set cursor if it has not actually changed if (currentCursorTex != cursorTex) { if (cursorTex != null) { Cursor.SetCursor(cursorTex, hotspot, CursorMode.Auto); } else { Cursor.SetCursor(null, cursorHotspot, CursorMode.Auto); } currentCursorTex = cursorTex; } } ImGui.Render(); // render ImGui ImDrawDataPtr data = ImGui.GetDrawData(); if (commandBuffer != null) { // Clear buffer regardless of whether we have something to render or not commandBuffer.Clear(); } // Don't update meshes and Command Buffers if there is nothing to render if (data.CmdListsCount > 0) { // resize meshes array int numDrawCommands = 0; for (int i = 0; i < data.CmdListsCount; i++) { ImDrawListPtr cmdList = data.getDrawListPtr(i); var cmdBuffer = cmdList.CmdBuffer; numDrawCommands += cmdBuffer.Size; } if (meshes == null) { meshes = new List <ImGuiMesh>(); } if (meshes.Count != numDrawCommands) { // add new meshes to list if needed for (int i = meshes.Count; i < numDrawCommands; i++) { ImGuiMesh mesh = new ImGuiMesh(); meshes.Add(mesh); } // delete extra meshes if needed for (int i = meshes.Count - 1; i >= numDrawCommands; i--) { Destroy(meshes[i].mesh); meshes.RemoveAt(i); } } if (commandBuffer == null) { commandBuffer = new CommandBuffer(); commandBuffer.name = "ImGui Renderer"; commandBuffer.SetRenderTarget(BuiltinRenderTextureType.CameraTarget); guiCamera.AddCommandBuffer(CameraEvent.AfterEverything, commandBuffer); } commandBuffer.SetRenderTarget(BuiltinRenderTextureType.CameraTarget); // orthogonal projection of GUI mesh to camera space Matrix4x4 matrix = Matrix4x4.Ortho(0, Screen.width, 0, Screen.height, 0, 0.1f); // negate world to camera transform and projection which Unity applies itself matrix = guiCamera.cameraToWorldMatrix * guiCamera.projectionMatrix.inverse * matrix; // update Command Buffers int count = 0; for (int i = 0; i < data.CmdListsCount; i++) { ImDrawListPtr cmdList = data.getDrawListPtr(i); var cmdBuffer = cmdList.CmdBuffer; uint startElement = 0; for (int j = 0; j < cmdBuffer.Size; j++) { ImDrawCmd cmd = cmdBuffer[j]; Rect rect = new Rect { min = new Vector2(cmd.ClipRect.x, Screen.height - cmd.ClipRect.y), max = new Vector2(cmd.ClipRect.z, Screen.height - cmd.ClipRect.w) }; commandBuffer.EnableScissorRect(rect); meshes[count].UpdateMesh(cmd, cmdList.IdxBuffer, cmdList.VtxBuffer, (int)startElement); if (cmd.TextureId == fontTexturePtr) { mpb.SetTexture(main_tex_id, fontTexture); commandBuffer.DrawMesh(meshes[count].mesh, matrix, material, 0, 0, mpb); } else if (textures.ContainsKey(cmd.TextureId)) { mpb.SetTexture(main_tex_id, textures[cmd.TextureId]); commandBuffer.DrawMesh(meshes[count].mesh, matrix, material, 0, 0, mpb); } else { Debug.LogWarning("Image texture missing!"); } startElement += cmd.ElemCount; count++; } } } else if (commandBuffer != null) { // Remove Command Buffer if there is nothing to render guiCamera.RemoveCommandBuffer(CameraEvent.AfterEverything, commandBuffer); commandBuffer = null; } textures.Clear(); last_end = stopwatch.Elapsed.TotalSeconds; }
public void RenderDrawData(ImDrawData drawData) { GraphicsDevice device = Game.GraphicsDevice; // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. Viewport lastViewport = device.Viewport; Rectangle lastScissorBox = device.ScissorRectangle; device.BlendFactor = Color.White; device.BlendState = BlendState.NonPremultiplied; device.RasterizerState = RasterizerState; device.DepthStencilState = DepthStencilState.DepthRead; // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) ImGuiIO io = ImGui.GetIO(); ImGui.ScaleClipRects(drawData, io.DisplayFramebufferScale); // Setup projection device.Viewport = new Viewport(0, 0, device.PresentationParameters.BackBufferWidth, device.PresentationParameters.BackBufferHeight); if (Effect == null) { Effect = new BasicEffect(device); } Effect effect = Effect; SetupEffect(this, effect); // Render command lists for (int n = 0; n < drawData.CmdListsCount; n++) { ImDrawList cmdList = drawData[n]; ImVector <ImDrawVertXNA> vtxBuffer; unsafe { vtxBuffer = new ImVector <ImDrawVertXNA>(cmdList.VtxBuffer.Native); } ImDrawVertXNA[] vtxArray = new ImDrawVertXNA[vtxBuffer.Size]; for (int i = 0; i < vtxBuffer.Size; i++) { vtxArray[i] = vtxBuffer[i]; } ImVector <short> idxBuffer; unsafe { idxBuffer = new ImVector <short>(cmdList.IdxBuffer.Native); } /* * short[] idxArray = new short[idxBuffer.Size]; * for (int i = 0; i < idxBuffer.Size; i++) * idxArray[i] = idxBuffer[i]; */ uint offset = 0; for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++) { ImDrawCmd pcmd = cmdList.CmdBuffer[cmdi]; if (pcmd.UserCallback != IntPtr.Zero) { pcmd.InvokeUserCallback(ref cmdList, ref pcmd); } else { // Instead of uploading the complete idxBuffer again and again, just upload what's required. short[] idxArray = new short[pcmd.ElemCount]; for (int i = 0; i < pcmd.ElemCount; i++) { idxArray[i] = idxBuffer[(int)offset + i]; } SetEffectTexture(this, effect, GetTexture((int)pcmd.TextureId)); device.ScissorRectangle = new Rectangle( (int)pcmd.ClipRect.X, (int)pcmd.ClipRect.Y, (int)(pcmd.ClipRect.Z - pcmd.ClipRect.X), (int)(pcmd.ClipRect.W - pcmd.ClipRect.Y) ); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); device.DrawUserIndexedPrimitives( PrimitiveType.TriangleList, vtxArray, 0, vtxBuffer.Size, idxArray, 0, (int)pcmd.ElemCount / 3, ImDrawVertXNA._VertexDeclaration ); } } offset += pcmd.ElemCount; } } // Restore modified state device.Viewport = lastViewport; device.ScissorRectangle = lastScissorBox; }