diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a4cbd4de..d753375e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,8 @@ Other Changes: - GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419) - GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero. - Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood] +- Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert + to using the ImGui::MemAlloc()/MemFree() calls directly. - Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early, and help users understand what they are missing. (#2421) - Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop. diff --git a/imgui.cpp b/imgui.cpp index c0184541..4cb82e16 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1307,7 +1307,7 @@ void ImStrncpy(char* dst, const char* src, size_t count) char* ImStrdup(const char* str) { size_t len = strlen(str); - void* buf = ImGui::MemAlloc(len + 1); + void* buf = IM_ALLOC(len + 1); return (char*)memcpy(buf, (const void*)str, len + 1); } @@ -1317,8 +1317,8 @@ char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) size_t src_size = strlen(src) + 1; if (dst_buf_size < src_size) { - ImGui::MemFree(dst); - dst = (char*)ImGui::MemAlloc(src_size); + IM_FREE(dst); + dst = (char*)IM_ALLOC(src_size); if (p_dst_size) *p_dst_size = src_size; } @@ -1527,7 +1527,7 @@ FILE* ImFileOpen(const char* filename, const char* mode) } // Load file content into memory -// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree() +// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes) { IM_ASSERT(filename && file_open_mode); @@ -1546,7 +1546,7 @@ void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_ } size_t file_size = (size_t)file_size_signed; - void* file_data = ImGui::MemAlloc(file_size + padding_bytes); + void* file_data = IM_ALLOC(file_size + padding_bytes); if (file_data == NULL) { fclose(f); @@ -1555,7 +1555,7 @@ void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_ if (fread(file_data, 1, file_size, f) != file_size) { fclose(f); - ImGui::MemFree(file_data); + IM_FREE(file_data); return NULL; } if (padding_bytes > 0) @@ -2962,6 +2962,7 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) return ImMax(wrap_pos_x - pos.x, 1.0f); } +// IM_ALLOC() == ImGui::MemAlloc() void* ImGui::MemAlloc(size_t size) { if (ImGuiContext* ctx = GImGui) @@ -2969,6 +2970,7 @@ void* ImGui::MemAlloc(size_t size) return GImAllocatorAllocFunc(size, GImAllocatorUserData); } +// IM_FREE() == ImGui::MemFree() void ImGui::MemFree(void* ptr) { if (ptr) @@ -9093,7 +9095,7 @@ void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) if (!file_data) return; LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); - ImGui::MemFree(file_data); + IM_FREE(file_data); } ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) @@ -9117,7 +9119,7 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. if (ini_size == 0) ini_size = strlen(ini_data); - char* buf = (char*)ImGui::MemAlloc(ini_size + 1); + char* buf = (char*)IM_ALLOC(ini_size + 1); char* buf_end = buf + ini_size; memcpy(buf, ini_data, ini_size); buf[ini_size] = 0; @@ -9164,7 +9166,7 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); } } - ImGui::MemFree(buf); + IM_FREE(buf); g.SettingsLoaded = true; } diff --git a/imgui.h b/imgui.h index 1d907b04..c4400d84 100644 --- a/imgui.h +++ b/imgui.h @@ -13,6 +13,7 @@ Index of this file: // Forward declarations and basic types // ImGui API (Dear ImGui end-user API) // Flags & Enumerations +// Memory allocations macros // ImVector<> // ImGuiStyle // ImGuiIO @@ -1185,6 +1186,22 @@ enum ImGuiCond_ #endif }; +//----------------------------------------------------------------------------- +// Helpers: Memory allocations macros +// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() +// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. +// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +//----------------------------------------------------------------------------- + +struct ImNewDummy {}; +inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; } +inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new() +#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) +#define IM_FREE(_PTR) ImGui::MemFree(_PTR) +#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR) +#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE +template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } + //----------------------------------------------------------------------------- // Helper: ImVector<> // Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). @@ -1210,7 +1227,7 @@ struct ImVector inline ImVector() { Size = Capacity = 0; Data = NULL; } inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } - inline ~ImVector() { if (Data) ImGui::MemFree(Data); } + inline ~ImVector() { if (Data) IM_FREE(Data); } inline bool empty() const { return Size == 0; } inline int size() const { return Size; } @@ -1219,7 +1236,7 @@ struct ImVector inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } - inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } + inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } inline T* begin() { return Data; } inline const T* begin() const { return Data; } inline T* end() { return Data + Size; } @@ -1233,7 +1250,7 @@ struct ImVector inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } - inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; } + inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } @@ -1548,16 +1565,6 @@ typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; // Helpers //----------------------------------------------------------------------------- -// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree -// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. -// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. -struct ImNewDummy {}; -inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; } -inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new() -#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR) -#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE -template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } - // Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame. // Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); struct ImGuiOnceUponAFrame diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 97f25bd4..290fadb8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -130,8 +130,8 @@ namespace IMGUI_STB_NAMESPACE #ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION -#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x)) -#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x)) +#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) +#define STBTT_free(x,u) ((void)(u), IM_FREE(x)) #define STBTT_assert(x) IM_ASSERT(x) #define STBTT_fmod(x,y) ImFmod(x,y) #define STBTT_sqrt(x) ImSqrt(x) @@ -1459,7 +1459,7 @@ void ImFontAtlas::ClearInputData() for (int i = 0; i < ConfigData.Size; i++) if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas) { - ImGui::MemFree(ConfigData[i].FontData); + IM_FREE(ConfigData[i].FontData); ConfigData[i].FontData = NULL; } @@ -1480,9 +1480,9 @@ void ImFontAtlas::ClearTexData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); if (TexPixelsAlpha8) - ImGui::MemFree(TexPixelsAlpha8); + IM_FREE(TexPixelsAlpha8); if (TexPixelsRGBA32) - ImGui::MemFree(TexPixelsRGBA32); + IM_FREE(TexPixelsRGBA32); TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; } @@ -1528,7 +1528,7 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid GetTexDataAsAlpha8(&pixels, NULL, NULL); if (pixels) { - TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4); + TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4); const unsigned char* src = pixels; unsigned int* dst = TexPixelsRGBA32; for (int n = TexWidth * TexHeight; n > 0; n--) @@ -1560,7 +1560,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) new_font_cfg.DstFont = Fonts.back(); if (!new_font_cfg.FontDataOwnedByAtlas) { - new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize); + new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize); new_font_cfg.FontDataOwnedByAtlas = true; memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); } @@ -1645,7 +1645,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float si ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) { const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); - unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size); + unsigned char* buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size); stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); @@ -1657,10 +1657,10 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_d ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) { int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; - void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size); + void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); - ImGui::MemFree(compressed_ttf); + IM_FREE(compressed_ttf); return font; } @@ -1960,7 +1960,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // 7. Allocate texture atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); - atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); + atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); spc.pixels = atlas->TexPixelsAlpha8; spc.height = atlas->TexHeight; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4ebbc1f5..d6d5ac84 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3540,7 +3540,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1; - char* clipboard_data = (char*)MemAlloc(clipboard_data_len * sizeof(char)); + char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char)); ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie); SetClipboardText(clipboard_data); MemFree(clipboard_data); @@ -3559,7 +3559,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Filter pasted buffer const int clipboard_len = (int)strlen(clipboard); - ImWchar* clipboard_filtered = (ImWchar*)MemAlloc((clipboard_len+1) * sizeof(ImWchar)); + ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len+1) * sizeof(ImWchar)); int clipboard_filtered_len = 0; for (const char* s = clipboard; *s; ) { diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 012eae75..4a579ed2 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -398,7 +398,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024; int buf_bitmap_current_used_bytes = 0; ImVector buf_bitmap_buffers; - buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE)); + buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE)); // 4. Gather glyphs sizes so we can pack them in our virtual canvas. // 8. Render/rasterize font characters into the texture @@ -440,7 +440,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE) { buf_bitmap_current_used_bytes = 0; - buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE)); + buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE)); } // Blit rasterized pixels to our temporary buffer and keep a pointer to it. @@ -493,7 +493,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns // 7. Allocate texture atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); - atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); + atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); // 8. Copy rasterized font characters back into the main texture @@ -557,7 +557,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns // Cleanup for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++) - ImGui::MemFree(buf_bitmap_buffers[buf_i]); + IM_FREE(buf_bitmap_buffers[buf_i]); for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) src_tmp_array[src_i].~ImFontBuildSrcDataFT(); @@ -567,8 +567,8 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns } // Default memory allocators -static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return ImGui::MemAlloc(size); } -static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); ImGui::MemFree(ptr); } +static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return IM_ALLOC(size); } +static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_FREE(ptr); } // Current memory allocators static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc; diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 9df5780e..b4b0fd66 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -29,7 +29,7 @@ namespace ImGuiFreeType IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); - // By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree(). + // By default ImGuiFreeType will use IM_ALLOC()/IM_FREE(). // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired: IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); }