diff --git a/backends/implot_gpu.h b/backends/implot_gpu.h new file mode 100644 index 0000000..e5d9477 --- /dev/null +++ b/backends/implot_gpu.h @@ -0,0 +1,154 @@ +// MIT License + +// Copyright (c) 2021 Evan Pezent + +// 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. + +// ImPlot v0.10 WIP + +#pragma once + +#include "../implot.h" + +namespace ImPlot { +namespace Backend { + +/** + * @brief Struct to hold backend-related context data + * + * A backend may store in this struct any data it needs, with no constraints. A + * pointer to this struct will be stored inside ImPlot's context and can be + * accessed at any time. This pointer will be set to the returned value of @ref + * CreateContext(). All resources held by this struct must be freed inside @ref + * DestroyContext(). + */ +struct ContextData; + +/** + * @brief Create backend context + * + * Creates and intializes the backend context. The returned pointer will be saved + * in ImPlot's context and can be accessed later. + */ +IMPLOT_API void* CreateContext(); + +/** + * @brief Destroy backend context + * + * Destroys and frees any memory or resources needed by the backend. After this + * call returns, no more calls to any backend function will be performed. + */ +IMPLOT_API void DestroyContext(); + +/** + * @brief Add a colormap + * + * Adds a colormap to be handled by the backend. + * + * @param keys Colors for this colormap, in RGBA format + * @param count Number of colors in this colormap + * @param qual Qualitative: whether the colormap is continuous (`false`) or + * not (`true`) + */ +IMPLOT_API void AddColormap(const ImU32* keys, int count, bool qual); + +/** + * @brief Set heatmap data + * + * Sets the data of the heatmap with the given plot ID. + * + * @param plotID ID of the heatmap to update. This ID is unique, but it is not + * continuous nor always positive. + * @param values Data of the heatmap to be set.`values[0]` corresponds with the + * top-left corner of the data. + * @param rows Number of rows of this heatmap + * @param cols Number of columns of this heatmap + */ +IMPLOT_API void SetHeatmapData(int plotID, const ImS8* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const ImU8*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const ImU8* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const ImS16*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const ImS16* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const ImU16*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const ImU16* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const ImS32*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const ImS32* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const ImU32*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const ImU32* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const float*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const float* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const double*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const double* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const ImS64*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const ImS64* values, int rows, int cols); + +/** @copydoc SetHeatmapData(int,const ImU64*,int,int) */ +IMPLOT_API void SetHeatmapData(int plotID, const ImU64* values, int rows, int cols); + +/** + * @brief Render heatmap + * + * Renders the heatmap by submitting the appropriate commands to the current + * draw list. + * + * @param plotID ID of the heatmap to be rendered + * @param DrawList Draw list where to submit the render commands + * @param bounds_min Minimum bounds of the heatmap (without clipping) + * @param bounds_max Maximum bounds of the heatmap (without clipping) + * @param scale_min Minimum value of the heatmap + * @param scale_max Maximum value of the heatmap + * @param colormap Colormap to be used when rendering this heatmap + * + * @note There might be values greater than `scale_max` or lower than `scale_min`. + * The shader used for rendering should clamp this values appropriately. + */ +IMPLOT_API void RenderHeatmap( + int plotID, ImDrawList& DrawList, const ImVec2& bounds_min, const ImVec2& bounds_max, + float scale_min, float scale_max, ImPlotColormap colormap); + +/** @brief Bust plot cache. Called from @ref ImPlot::BustPlotCache() */ +IMPLOT_API void BustPlotCache(); + +/** @brief Bust item cache. Called from @ref ImPlot::BustItemCache() */ +IMPLOT_API void BustItemCache(); + + +#if !defined(IMPLOT_ENABLE_OPENGL3_ACCELERATION) + +// Dummy implementation for backend functions +inline void* CreateContext() { return nullptr; } +inline void DestroyContext() {} + +inline void AddColormap(const ImU32*, int, bool) {} + +inline void BustPlotCache() {} +inline void BustItemCache() {} + +#endif + +} +} diff --git a/backends/implot_opengl3.cpp b/backends/implot_opengl3.cpp index be70f1b..15ea30a 100644 --- a/backends/implot_opengl3.cpp +++ b/backends/implot_opengl3.cpp @@ -2,6 +2,7 @@ #include "../implot.h" #include "../implot_internal.h" +#include "implot_gpu.h" #if defined(IMGUI_IMPL_OPENGL_ES2) #include @@ -32,7 +33,7 @@ using namespace gl; #endif namespace ImPlot { -namespace Backends { +namespace Backend { struct HeatmapData { @@ -42,7 +43,7 @@ struct HeatmapData float MaxValue; }; -struct OpenGLContextData +struct ContextData { GLuint g_ShaderProgram = 0; ///< Shader ID for the heatmap shader GLuint g_AttribLocationHeatmapSampler = 0; ///< Attribute location for the heatmap texture @@ -62,10 +63,29 @@ struct OpenGLContextData ImVector temp3; }; -static OpenGLContextData Context; +void* CreateContext() +{ + return new ContextData; +} + +void DestroyContext() +{ + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + + for(const HeatmapData& data : Context.HeatmapDataList) + glDeleteTextures(1, &data.HeatmapTexID); + + for(GLuint texID : Context.ColormapIDs) + glDeleteTextures(1, &texID); + + Context.HeatmapDataList.clear(); + Context.PlotIDs.Clear(); +} static void CreateShader(const ImDrawList*, const ImDrawCmd*) { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + GLuint CurrentShader; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&CurrentShader); @@ -73,14 +93,12 @@ static void CreateShader(const ImDrawList*, const ImDrawCmd*) GLuint g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(CurrentShader, "Position"); GLuint g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(CurrentShader, "UV"); - GLuint g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(CurrentShader, "Color"); const GLchar* VertexShaderCode_t = "#version 330 core\n" "precision mediump float;\n" "layout (location = %d) in vec2 Position;\n" "layout (location = %d) in vec2 UV;\n" - "layout (location = %d) in vec4 Color;\n" "\n" "uniform mat4 ProjMtx;\n" "out vec2 Frag_UV;\n" @@ -110,7 +128,7 @@ static void CreateShader(const ImDrawList*, const ImDrawCmd*) "}\n"; GLchar* VertexShaderCode = new GLchar[512]; - snprintf(VertexShaderCode, 512, VertexShaderCode_t, g_AttribLocationVtxPos, g_AttribLocationVtxUV, g_AttribLocationVtxColor); + snprintf(VertexShaderCode, 512, VertexShaderCode_t, g_AttribLocationVtxPos, g_AttribLocationVtxUV); GLuint g_VertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(g_VertexShader, 1, &VertexShaderCode, nullptr); @@ -145,6 +163,8 @@ static void CreateShader(const ImDrawList*, const ImDrawCmd*) static void RenderCallback(const ImDrawList*, const ImDrawCmd* cmd) { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + int plotID = (int)(intptr_t)cmd->UserCallbackData; int plotIdx = Context.PlotIDs.GetInt(plotID, -1); HeatmapData& data = Context.HeatmapDataList[plotIdx]; @@ -175,6 +195,8 @@ static void UnbindTexture(const ImDrawList*, const ImDrawCmd*) static void SetTextureData(int plotID, const void* data, GLsizei rows, GLsizei cols, GLenum type) { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + int idx = Context.PlotIDs.GetInt(plotID, -1); GLuint texID = Context.HeatmapDataList[idx].HeatmapTexID; @@ -183,7 +205,7 @@ static void SetTextureData(int plotID, const void* data, GLsizei rows, GLsizei c glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cols, rows, 0, GL_RED, type, data); } -void OpenGL3_AddColormap(const ImU32* keys, int count, bool qual) +void AddColormap(const ImU32* keys, int count, bool qual) { GLuint texID; glGenTextures(1, &texID); @@ -195,6 +217,7 @@ void OpenGL3_AddColormap(const ImU32* keys, int count, bool qual) glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, qual ? GL_NEAREST : GL_LINEAR); glBindTexture(GL_TEXTURE_1D, 0); + ContextData& Context = *((ContextData*)GImPlot->backendCtx); // PETA AQUI (GImPlot es NULL) Context.ColormapIDs.push_back(texID); } @@ -210,16 +233,18 @@ static GLuint CreateHeatmapTexture() return textureID; } -void OpenGL3_SetHeatmapData(int plotID, const ImS8* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_BYTE); } -void OpenGL3_SetHeatmapData(int plotID, const ImU8* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_UNSIGNED_BYTE); } -void OpenGL3_SetHeatmapData(int plotID, const ImS16* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_SHORT); } -void OpenGL3_SetHeatmapData(int plotID, const ImU16* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_UNSIGNED_SHORT); } -void OpenGL3_SetHeatmapData(int plotID, const ImS32* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_INT); } -void OpenGL3_SetHeatmapData(int plotID, const ImU32* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_UNSIGNED_INT); } -void OpenGL3_SetHeatmapData(int plotID, const float* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_FLOAT); } +void SetHeatmapData(int plotID, const ImS8* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_BYTE); } +void SetHeatmapData(int plotID, const ImU8* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_UNSIGNED_BYTE); } +void SetHeatmapData(int plotID, const ImS16* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_SHORT); } +void SetHeatmapData(int plotID, const ImU16* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_UNSIGNED_SHORT); } +void SetHeatmapData(int plotID, const ImS32* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_INT); } +void SetHeatmapData(int plotID, const ImU32* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_UNSIGNED_INT); } +void SetHeatmapData(int plotID, const float* values, int rows, int cols) { SetTextureData(plotID, values, rows, cols, GL_FLOAT); } -void OpenGL3_SetHeatmapData(int plotID, const double* values, int rows, int cols) +void SetHeatmapData(int plotID, const double* values, int rows, int cols) { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + if(Context.temp1.Size < rows * cols) Context.temp1.resize(rows * cols); @@ -229,8 +254,10 @@ void OpenGL3_SetHeatmapData(int plotID, const double* values, int rows, int cols SetTextureData(plotID, Context.temp1.Data, rows, cols, GL_FLOAT); } -void OpenGL3_SetHeatmapData(int plotID, const ImS64* values, int rows, int cols) +void SetHeatmapData(int plotID, const ImS64* values, int rows, int cols) { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + if(Context.temp2.Size < rows * cols) Context.temp2.resize(rows * cols); @@ -240,8 +267,10 @@ void OpenGL3_SetHeatmapData(int plotID, const ImS64* values, int rows, int cols) SetTextureData(plotID, Context.temp2.Data, rows, cols, GL_INT); } -void OpenGL3_SetHeatmapData(int plotID, const ImU64* values, int rows, int cols) +void SetHeatmapData(int plotID, const ImU64* values, int rows, int cols) { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + if(Context.temp3.Size < rows * cols) Context.temp3.resize(rows * cols); @@ -251,8 +280,9 @@ void OpenGL3_SetHeatmapData(int plotID, const ImU64* values, int rows, int cols) SetTextureData(plotID, Context.temp3.Data, rows, cols, GL_UNSIGNED_INT); } -void OpenGL3_RenderHeatmap(int plotID, ImDrawList& DrawList, const ImVec2& bounds_min, const ImVec2& bounds_max, float scale_min, float scale_max, ImPlotColormap colormap) +void RenderHeatmap(int plotID, ImDrawList& DrawList, const ImVec2& bounds_min, const ImVec2& bounds_max, float scale_min, float scale_max, ImPlotColormap colormap) { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); int idx = Context.PlotIDs.GetInt(plotID, -1); if(idx < 0) @@ -285,8 +315,10 @@ void OpenGL3_RenderHeatmap(int plotID, ImDrawList& DrawList, const ImVec2& bound DrawList.AddCallback(ImDrawCallback_ResetRenderState, nullptr); } -void OpenGL3_BustPlotCache() +void BustPlotCache() { + ContextData& Context = *((ContextData*)GImPlot->backendCtx); + for(const HeatmapData& data : Context.HeatmapDataList) glDeleteTextures(1, &data.HeatmapTexID); @@ -294,6 +326,8 @@ void OpenGL3_BustPlotCache() Context.PlotIDs.Clear(); } +void BustItemCache() {} + } } diff --git a/implot.cpp b/implot.cpp index e3374f7..862d945 100644 --- a/implot.cpp +++ b/implot.cpp @@ -88,16 +88,6 @@ You can read releases logs https://github.com/epezent/implot/releases for more d #define GetBufSize GetSize // A little bit ugly since 'GetBufSize' could technically be used elsewhere (but currently isn't). Could use a proxy define if needed. #endif -#ifdef IMPLOT_ENABLE_OPENGL3_ACCELERATION -namespace ImPlot { -namespace Backends { - -void OpenGL3_BustPlotCache(); - -} -} -#endif - // Global plot context ImPlotContext* GImPlot = NULL; @@ -384,13 +374,15 @@ void SetImGuiContext(ImGuiContext* ctx) { ImPlotContext* CreateContext() { ImPlotContext* ctx = IM_NEW(ImPlotContext)(); - Initialize(ctx); if (GImPlot == NULL) SetCurrentContext(ctx); + ctx->backendCtx = Backend::CreateContext(); + Initialize(ctx); return ctx; } void DestroyContext(ImPlotContext* ctx) { + Backend::DestroyContext(); if (ctx == NULL) ctx = GImPlot; if (GImPlot == ctx) @@ -498,9 +490,7 @@ ImPlotPlot* GetCurrentPlot() { void BustPlotCache() { GImPlot->Plots.Clear(); -#ifdef IMPLOT_ENABLE_OPENGL3_ACCELERATION - Backends::OpenGL3_BustPlotCache(); -#endif + Backend::BustPlotCache(); } void PushLinkedAxis(ImPlotAxis& axis) { diff --git a/implot_internal.h b/implot_internal.h index cc2f4b6..866148f 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -37,21 +37,12 @@ #include #include "imgui_internal.h" +#include "backends/implot_gpu.h" #ifndef IMPLOT_VERSION #error Must include implot.h before implot_internal.h #endif -#ifdef IMPLOT_ENABLE_OPENGL3_ACCELERATION -namespace ImPlot { -namespace Backends { - -void OpenGL3_AddColormap(const ImU32* keys, int count, bool qual); - -} -} -#endif - //----------------------------------------------------------------------------- // [SECTION] Constants //----------------------------------------------------------------------------- @@ -386,9 +377,7 @@ struct ImPlotColormapData { int idx = Count++; Map.SetInt(id,idx); _AppendTable(idx); -#ifdef IMPLOT_ENABLE_OPENGL3_ACCELERATION - ImPlot::Backends::OpenGL3_AddColormap(keys, count, qual); -#endif + ImPlot::Backend::AddColormap(keys, count, qual); return idx; } @@ -929,6 +918,9 @@ struct ImPlotContext { ImPlotNextItemData NextItemData; ImPlotInputMap InputMap; ImPlotPoint MousePos[IMPLOT_Y_AXES]; + + // Backend + void* backendCtx; }; //----------------------------------------------------------------------------- diff --git a/implot_items.cpp b/implot_items.cpp index 2483566..0cf8d28 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -24,6 +24,7 @@ #include "implot.h" #include "implot_internal.h" +#include "backends/implot_gpu.h" #ifdef _MSC_VER #define sprintf sprintf_s @@ -53,26 +54,6 @@ #endif -#ifdef IMPLOT_ENABLE_OPENGL3_ACCELERATION -namespace ImPlot { -namespace Backends { - void OpenGL3_SetHeatmapData(int texID, const ImS8* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const ImU8* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const ImS16* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const ImU16* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const ImS32* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const ImU32* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const ImS64* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const ImU64* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const float* values, int rows, int cols); - void OpenGL3_SetHeatmapData(int texID, const double* values, int rows, int cols); - - void OpenGL3_RenderHeatmap(int plotID, ImDrawList& DrawList, const ImVec2& bounds_min, const ImVec2& bounds_max, float scale_min, float scale_max, ImPlotColormap colormap); -} -} -#endif - - namespace ImPlot { //----------------------------------------------------------------------------- @@ -158,6 +139,7 @@ void HideNextItem(bool hidden, ImGuiCond cond) { void BustItemCache() { ImPlotContext& gp = *GImPlot; + Backend::BustItemCache(); for (int p = 0; p < gp.Plots.GetBufSize(); ++p) { ImPlotPlot& plot = *gp.Plots.GetByIndex(p); plot.ColormapIdx = 0; @@ -1915,8 +1897,8 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value ImVec2 bmin = transformer(bounds_min); ImVec2 bmax = transformer(bounds_max); - Backends::OpenGL3_RenderHeatmap(gp.CurrentPlot->ID, DrawList, bmin, bmax, scale_min, scale_max, gp.Style.Colormap); - Backends::OpenGL3_SetHeatmapData(gp.CurrentPlot->ID, values, rows, cols); + Backend::RenderHeatmap(gp.CurrentPlot->ID, DrawList, bmin, bmax, scale_min, scale_max, gp.Style.Colormap); + Backend::SetHeatmapData(gp.CurrentPlot->ID, values, rows, cols); #else GetterHeatmap getter(values, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir); switch (GetCurrentScale()) {