/// <summary> /// Helper to scale the ClipRect field of each ImDrawCmd. /// Use if your final output buffer is at a different scale than ImGui expects, /// or if there is a difference between your window resolution and framebuffer resolution. /// </summary> /// <param name="drawData">Pointer to the DrawData to scale.</param> /// <param name="scale">The scale to apply.</param> public static unsafe void ScaleClipRects(DrawData *drawData, Vector2 scale) { for (int i = 0; i < drawData->CmdListsCount; i++) { DrawList *cmd_list = drawData->CmdLists[i]; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { DrawCmd *drawCmdList = (DrawCmd *)cmd_list->CmdBuffer.Data; DrawCmd *cmd = &drawCmdList[cmd_i]; cmd->ClipRect = new Vector4(cmd->ClipRect.X * scale.X, cmd->ClipRect.Y * scale.Y, cmd->ClipRect.Z * scale.X, cmd->ClipRect.W * scale.Y); } } }
public static extern DrawCmd *ImDrawList_GetCmdPtr(DrawList *list, int n);
public static extern int ImDrawList_GetCmdSize(DrawList *list);
public static extern ushort *ImDrawList_GetIndexPtr(DrawList *list, int n);
public static extern int ImDrawList_GetIndexBufferSize(DrawList *list);
public static extern DrawVert *ImDrawList_GetVertexPtr(DrawList *list, int n);
private unsafe void RenderImDrawData(DrawData *draw_data) { // Rendering int display_w, display_h; display_w = Application.GetWindow().GetWidth(); display_h = Application.GetWindow().GetHeight(); var clear_color = new System.Numerics.Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f); GL.Viewport(0, 0, display_w, display_h); GL.ClearColor(clear_color.X, clear_color.Y, clear_color.Z, clear_color.W); GL.Clear(ClearBufferMask.ColorBufferBit); // 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 last_texture; GL.GetInteger(GetPName.TextureBinding2D, out last_texture); GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Disable(EnableCap.CullFace); GL.Disable(EnableCap.DepthTest); GL.Enable(EnableCap.ScissorTest); GL.EnableClientState(ArrayCap.VertexArray); GL.EnableClientState(ArrayCap.TextureCoordArray); GL.EnableClientState(ArrayCap.ColorArray); GL.Enable(EnableCap.Texture2D); GL.UseProgram(0); // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) IO io = ImGui.GetIO(); ImGui.ScaleClipRects(draw_data, io.DisplayFramebufferScale); // Setup orthographic projection matrix GL.MatrixMode(MatrixMode.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(MatrixMode.Modelview); GL.PushMatrix(); GL.LoadIdentity(); // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { DrawList *cmd_list = draw_data->CmdLists[n]; byte * vtx_buffer = (byte *)cmd_list->VtxBuffer.Data; ushort * idx_buffer = (ushort *)cmd_list->IdxBuffer.Data; DrawVert vert0 = *((DrawVert *)vtx_buffer); DrawVert vert1 = *(((DrawVert *)vtx_buffer) + 1); DrawVert vert2 = *(((DrawVert *)vtx_buffer) + 2); GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset)); GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset)); GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset)); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { DrawCmd *pcmd = &(((DrawCmd *)cmd_list->CmdBuffer.Data)[cmd_i]); if (pcmd->UserCallback != IntPtr.Zero) { throw new NotImplementedException(); } else { GL.BindTexture(TextureTarget.Texture2D, pcmd->TextureId.ToInt32()); 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)); ushort[] indices = new ushort[pcmd->ElemCount]; for (int i = 0; i < indices.Length; i++) { indices[i] = idx_buffer[i]; } GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer)); } idx_buffer += pcmd->ElemCount; } } // Restore modified state GL.DisableClientState(ArrayCap.ColorArray); GL.DisableClientState(ArrayCap.TextureCoordArray); GL.DisableClientState(ArrayCap.VertexArray); GL.BindTexture(TextureTarget.Texture2D, last_texture); GL.MatrixMode(MatrixMode.Modelview); GL.PopMatrix(); GL.MatrixMode(MatrixMode.Projection); GL.PopMatrix(); GL.PopAttrib(); }
private unsafe void RenderImDrawData(DrawData *draw_data, RenderContext rc) { VertexDescriptor descriptor = new VertexDescriptor((byte)sizeof(DrawVert), 3, 0, IntPtr.Zero); int vertexOffsetInVertices = 0; int indexOffsetInElements = 0; for (int i = 0; i < draw_data->CmdListsCount; i++) { DrawList *cmd_list = draw_data->CmdLists[i]; _vertexBuffer.SetVertexData(new IntPtr(cmd_list->VtxBuffer.Data), descriptor, cmd_list->VtxBuffer.Size, vertexOffsetInVertices); _indexBuffer.SetIndices(new IntPtr(cmd_list->IdxBuffer.Data), IndexFormat.UInt16, sizeof(ushort), cmd_list->IdxBuffer.Size, indexOffsetInElements); vertexOffsetInVertices += cmd_list->VtxBuffer.Size; indexOffsetInElements += cmd_list->IdxBuffer.Size; } // Setup orthographic projection matrix into our constant buffer { var io = ImGui.GetIO(); Matrix4x4 mvp = Matrix4x4.CreateOrthographicOffCenter( 0f, io.DisplaySize.X / io.DisplayFramebufferScale.X, io.DisplaySize.Y / io.DisplayFramebufferScale.Y, 0.0f, -1.0f, 1.0f); _projectionMatrixProvider.Data = mvp; } rc.SetBlendState(_blendState); rc.SetDepthStencilState(_depthDisabledState); RasterizerState previousRasterizerState = rc.RasterizerState; rc.SetRasterizerState(_rasterizerState); rc.SetVertexBuffer(_vertexBuffer); rc.SetIndexBuffer(_indexBuffer); rc.SetMaterial(_material); ImGui.ScaleClipRects(draw_data, ImGui.GetIO().DisplayFramebufferScale); // Render command lists int vtx_offset = 0; int idx_offset = 0; for (int n = 0; n < draw_data->CmdListsCount; n++) { DrawList *cmd_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { DrawCmd *pcmd = &(((DrawCmd *)cmd_list->CmdBuffer.Data)[cmd_i]); if (pcmd->UserCallback != IntPtr.Zero) { throw new NotImplementedException(); } else { if (pcmd->TextureId != IntPtr.Zero) { if (pcmd->TextureId == new IntPtr(_fontAtlasID)) { _material.UseTexture(0, _fontTextureBinding); } else { ShaderTextureBinding binding = ImGuiImageHelper.GetShaderTextureBinding(pcmd->TextureId); _material.UseTexture(0, binding); } } // TODO: This doesn't take into account viewport coordinates. rc.SetScissorRectangle( (int)pcmd->ClipRect.X, (int)pcmd->ClipRect.Y, (int)pcmd->ClipRect.Z, (int)pcmd->ClipRect.W); rc.DrawIndexedPrimitives((int)pcmd->ElemCount, idx_offset, vtx_offset); } idx_offset += (int)pcmd->ElemCount; } vtx_offset += cmd_list->VtxBuffer.Size; } rc.ClearScissorRectangle(); rc.SetBlendState(rc.OverrideBlend); rc.SetDepthStencilState(rc.DefaultDepthStencilState); rc.SetRasterizerState(previousRasterizerState); }