1
0
mirror of https://github.com/wolfpld/tracy.git synced 2025-03-20 07:40:02 +08:00

Update imgui to 1.67. Also update imguicolortextedit.

This commit is contained in:
Bartosz Taudul
2019-01-19 14:05:54 +01:00
parent 32f0a27d3b
commit ac791fd19f
16 changed files with 6461 additions and 3818 deletions
+370 -178
View File
@@ -1,6 +1,6 @@
// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
// Original code by @Vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut
// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained and v0.60+ by @ocornut.
// Changelog:
// - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
@@ -10,6 +10,7 @@
// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member
// - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX
// - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
// Gamma Correct Blending:
// FreeType assumes blending in linear space rather than gamma space.
@@ -17,18 +18,16 @@
// For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
// The default imgui styles will be impacted by this change (alpha values will need tweaking).
// TODO:
// - Output texture has excessive resolution (lots of vertical waste).
// - FreeType's memory allocator is not overridden.
// - cfg.OversampleH, OversampleV are ignored (but perhaps not so necessary with this rasterizer).
// FIXME: FreeType's memory allocator is not overridden.
// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).
#include "imgui_freetype.h"
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
#include <stdint.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_SYNTHESIS_H
#include FT_FREETYPE_H // <freetype/freetype.h>
#include FT_GLYPH_H // <freetype/ftglyph.h>
#include FT_SYNTHESIS_H // <freetype/ftsynth.h>
#ifdef _MSC_VER
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
@@ -74,15 +73,15 @@ namespace
/// A structure that describe a glyph.
struct GlyphInfo
{
float Width; // Glyph's width in pixels.
float Height; // Glyph's height in pixels.
float OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
float OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
int Width; // Glyph's width in pixels.
int Height; // Glyph's height in pixels.
FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
};
// Font parameters and metrics.
struct FontInfo
struct FontInfo
{
uint32_t PixelHeight; // Size this font was generated with.
float Ascender; // The pixel extents above the baseline in pixels (typically positive).
@@ -96,82 +95,80 @@ namespace
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
struct FreeTypeFont
{
bool Init(const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
void Shutdown();
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
bool CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap);
void BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);
bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
void CloseFont();
void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
void BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);
~FreeTypeFont() { CloseFont(); }
// [Internals]
FontInfo Info; // Font descriptor of the current font.
FT_Face Face;
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
FT_Library FreetypeLibrary;
FT_Face FreetypeFace;
FT_Int32 FreetypeLoadFlags;
FT_Int32 LoadFlags;
};
// From SDL_ttf: Handy routines for converting from fixed point
#define FT_CEIL(X) (((X + 63) & -64) / 64)
bool FreeTypeFont::Init(const ImFontConfig& cfg, unsigned int extra_user_flags)
bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags)
{
// FIXME: substitute allocator
FT_Error error = FT_Init_FreeType(&FreetypeLibrary);
FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
if (error != 0)
return false;
error = FT_New_Memory_Face(FreetypeLibrary, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &FreetypeFace);
if (error != 0)
return false;
error = FT_Select_Charmap(FreetypeFace, FT_ENCODING_UNICODE);
error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
if (error != 0)
return false;
memset(&Info, 0, sizeof(Info));
SetPixelHeight((uint32_t)cfg.SizePixels);
// Convert to freetype flags (nb: Bold and Oblique are processed separately)
// Convert to FreeType flags (NB: Bold and Oblique are processed separately)
UserFlags = cfg.RasterizerFlags | extra_user_flags;
FreetypeLoadFlags = FT_LOAD_NO_BITMAP;
if (UserFlags & ImGuiFreeType::NoHinting) FreetypeLoadFlags |= FT_LOAD_NO_HINTING;
if (UserFlags & ImGuiFreeType::NoAutoHint) FreetypeLoadFlags |= FT_LOAD_NO_AUTOHINT;
if (UserFlags & ImGuiFreeType::ForceAutoHint) FreetypeLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
if (UserFlags & ImGuiFreeType::LightHinting)
FreetypeLoadFlags |= FT_LOAD_TARGET_LIGHT;
else if (UserFlags & ImGuiFreeType::MonoHinting)
FreetypeLoadFlags |= FT_LOAD_TARGET_MONO;
LoadFlags = FT_LOAD_NO_BITMAP;
if (UserFlags & ImGuiFreeType::NoHinting)
LoadFlags |= FT_LOAD_NO_HINTING;
if (UserFlags & ImGuiFreeType::NoAutoHint)
LoadFlags |= FT_LOAD_NO_AUTOHINT;
if (UserFlags & ImGuiFreeType::ForceAutoHint)
LoadFlags |= FT_LOAD_FORCE_AUTOHINT;
if (UserFlags & ImGuiFreeType::LightHinting)
LoadFlags |= FT_LOAD_TARGET_LIGHT;
else if (UserFlags & ImGuiFreeType::MonoHinting)
LoadFlags |= FT_LOAD_TARGET_MONO;
else
FreetypeLoadFlags |= FT_LOAD_TARGET_NORMAL;
LoadFlags |= FT_LOAD_TARGET_NORMAL;
return true;
}
void FreeTypeFont::Shutdown()
void FreeTypeFont::CloseFont()
{
if (FreetypeFace)
if (Face)
{
FT_Done_Face(FreetypeFace);
FreetypeFace = NULL;
FT_Done_FreeType(FreetypeLibrary);
FreetypeLibrary = NULL;
FT_Done_Face(Face);
Face = NULL;
}
}
void FreeTypeFont::SetPixelHeight(int pixel_height)
{
// I'm not sure how to deal with font sizes properly.
// As far as I understand, currently ImGui assumes that the 'pixel_height' is a maximum height of an any given glyph,
// i.e. it's the sum of font's ascender and descender. Seems strange to me.
// Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
// is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
// NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.
FT_Size_RequestRec req;
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
req.width = 0;
req.height = (uint32_t)pixel_height * 64;
req.horiResolution = 0;
req.vertResolution = 0;
FT_Request_Size(FreetypeFace, &req);
FT_Request_Size(Face, &req);
// update font info
FT_Size_Metrics metrics = FreetypeFace->size->metrics;
// Update font info
FT_Size_Metrics metrics = Face->size->metrics;
Info.PixelHeight = (uint32_t)pixel_height;
Info.Ascender = (float)FT_CEIL(metrics.ascender);
Info.Descender = (float)FT_CEIL(metrics.descender);
@@ -180,52 +177,58 @@ namespace
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance);
}
bool FreeTypeFont::CalcGlyphInfo(uint32_t codepoint, GlyphInfo &glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap)
const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)
{
uint32_t glyph_index = FT_Get_Char_Index(FreetypeFace, codepoint);
uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
if (glyph_index == 0)
return false;
FT_Error error = FT_Load_Glyph(FreetypeFace, glyph_index, FreetypeLoadFlags);
return NULL;
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
if (error)
return false;
return NULL;
// Need an outline for this to work
FT_GlyphSlot slot = FreetypeFace->glyph;
FT_GlyphSlot slot = Face->glyph;
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE);
// Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting)
if (UserFlags & ImGuiFreeType::Bold)
FT_GlyphSlot_Embolden(slot);
if (UserFlags & ImGuiFreeType::Oblique)
{
FT_GlyphSlot_Oblique(slot);
//FT_BBox bbox;
//FT_Outline_Get_BBox(&slot->outline, &bbox);
//slot->metrics.width = bbox.xMax - bbox.xMin;
//slot->metrics.height = bbox.yMax - bbox.yMin;
}
// Retrieve the glyph
error = FT_Get_Glyph(slot, &ft_glyph);
if (error != 0)
return false;
// Rasterize
error = FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, NULL, true);
if (error != 0)
return false;
ft_bitmap = (FT_BitmapGlyph)ft_glyph;
glyph_info.AdvanceX = (float)FT_CEIL(slot->advance.x);
glyph_info.OffsetX = (float)ft_bitmap->left;
glyph_info.OffsetY = -(float)ft_bitmap->top;
glyph_info.Width = (float)ft_bitmap->bitmap.width;
glyph_info.Height = (float)ft_bitmap->bitmap.rows;
return true;
return &slot->metrics;
}
void FreeTypeFont::BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
{
FT_GlyphSlot slot = Face->glyph;
FT_Error error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
if (error != 0)
return NULL;
FT_Bitmap* ft_bitmap = &Face->glyph->bitmap;
out_glyph_info->Width = (int)ft_bitmap->width;
out_glyph_info->Height = (int)ft_bitmap->rows;
out_glyph_info->OffsetX = Face->glyph->bitmap_left;
out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x);
return ft_bitmap;
}
void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
{
IM_ASSERT(ft_bitmap != NULL);
const uint32_t w = ft_bitmap->bitmap.width;
const uint32_t h = ft_bitmap->bitmap.rows;
const uint8_t* src = ft_bitmap->bitmap.buffer;
const uint32_t src_pitch = ft_bitmap->bitmap.pitch;
const uint32_t w = ft_bitmap->width;
const uint32_t h = ft_bitmap->rows;
const uint8_t* src = ft_bitmap->buffer;
const uint32_t src_pitch = ft_bitmap->pitch;
if (multiply_table == NULL)
{
@@ -246,143 +249,332 @@ namespace
#define STB_RECT_PACK_IMPLEMENTATION
#include "imstb_rectpack.h"
bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
struct ImFontBuildSrcGlyphFT
{
GlyphInfo Info;
uint32_t Codepoint;
unsigned char* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array
};
struct ImFontBuildSrcDataFT
{
FreeTypeFont Font;
stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
int GlyphsHighest; // Highest requested codepoint
int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
ImVector<ImFontBuildSrcGlyphFT> GlyphsList;
};
// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
struct ImFontBuildDstDataFT
{
int SrcCount; // Number of source fonts targeting this destination font.
int GlyphsHighest;
int GlyphsCount;
ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
};
bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
{
IM_ASSERT(atlas->ConfigData.Size > 0);
IM_ASSERT(atlas->TexGlyphPadding == 1); // Not supported
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
atlas->TexID = NULL;
// Clear atlas
atlas->TexID = (ImTextureID)NULL;
atlas->TexWidth = atlas->TexHeight = 0;
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
atlas->ClearTexData();
ImVector<FreeTypeFont> fonts;
fonts.resize(atlas->ConfigData.Size);
// Temporary storage for building
ImVector<ImFontBuildSrcDataFT> src_tmp_array;
ImVector<ImFontBuildDstDataFT> dst_tmp_array;
src_tmp_array.resize(atlas->ConfigData.Size);
dst_tmp_array.resize(atlas->Fonts.Size);
memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
ImVec2 max_glyph_size(1.0f, 1.0f);
// Count glyphs/ranges, initialize font
int total_glyphs_count = 0;
int total_ranges_count = 0;
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
// 1. Initialize font loading structure, check font data validity
for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
{
ImFontConfig& cfg = atlas->ConfigData[input_i];
FreeTypeFont& font_face = fonts[input_i];
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
ImFontConfig& cfg = atlas->ConfigData[src_i];
FreeTypeFont& font_face = src_tmp.Font;
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
if (!font_face.Init(cfg, extra_flags))
// Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
src_tmp.DstIndex = -1;
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
if (cfg.DstFont == atlas->Fonts[output_i])
src_tmp.DstIndex = output_i;
IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
if (src_tmp.DstIndex == -1)
return false;
max_glyph_size.x = ImMax(max_glyph_size.x, font_face.Info.MaxAdvanceWidth);
max_glyph_size.y = ImMax(max_glyph_size.y, font_face.Info.Ascender - font_face.Info.Descender);
// Load font
if (!font_face.InitFont(ft_library, cfg, extra_flags))
return false;
if (!cfg.GlyphRanges)
cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[ 1 ]; in_range += 2, total_ranges_count++)
total_glyphs_count += (in_range[1] - in_range[0]) + 1;
// Measure highest codepoints
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
dst_tmp.SrcCount++;
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
}
// We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
// Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
// 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
int total_glyphs_count = 0;
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
ImFontConfig& cfg = atlas->ConfigData[src_i];
src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty())
dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
// We don't do the original first pass to determine texture height, but just rough estimate.
// Looks ugly inaccurate and excessive, but AFAIK with FreeType we actually need to render glyphs to get exact sizes.
// Alternatively, we could just render all glyphs into a big shadow buffer, get their sizes, do the rectangle packing and just copy back from the
// shadow buffer to the texture buffer. Will give us an accurate texture height, but eat a lot of temp memory. Probably no one will notice.)
const int total_rects = total_glyphs_count + atlas->CustomRects.size();
float min_rects_per_row = ceilf((atlas->TexWidth / (max_glyph_size.x + 1.0f)));
float min_rects_per_column = ceilf(total_rects / min_rects_per_row);
atlas->TexHeight = (int)(min_rects_per_column * (max_glyph_size.y + 1.0f));
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
{
if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
continue;
uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
if (glyph_index == 0)
continue;
// Create texture
// Add to avail set/counters
src_tmp.GlyphsCount++;
dst_tmp.GlyphsCount++;
src_tmp.GlyphsSet.SetBit(codepoint, true);
if (dst_tmp.SrcCount > 1)
dst_tmp.GlyphsSet.SetBit(codepoint, true);
total_glyphs_count++;
}
}
// 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(int));
const int* it_begin = src_tmp.GlyphsSet.Storage.begin();
const int* it_end = src_tmp.GlyphsSet.Storage.end();
for (const int* it = it_begin; it < it_end; it++)
if (int entries_32 = *it)
for (int bit_n = 0; bit_n < 32; bit_n++)
if (entries_32 & (1 << bit_n))
{
ImFontBuildSrcGlyphFT src_glyph;
memset(&src_glyph, 0, sizeof(src_glyph));
src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);
//src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..
src_tmp.GlyphsList.push_back(src_glyph);
}
src_tmp.GlyphsSet.Clear();
IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
}
for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
dst_tmp_array[dst_i].GlyphsSet.Clear();
dst_tmp_array.clear();
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
// (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
ImVector<stbrp_rect> buf_rects;
buf_rects.resize(total_glyphs_count);
memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
// Allocate temporary rasterization data buffers.
// We could not find a way to retrieve accurate glyph size without rendering them.
// (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
// We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations.
const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
int buf_bitmap_current_used_bytes = 0;
ImVector<unsigned char*> buf_bitmap_buffers;
buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(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
int total_surface = 0;
int buf_rects_out_n = 0;
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
ImFontConfig& cfg = atlas->ConfigData[src_i];
if (src_tmp.GlyphsCount == 0)
continue;
src_tmp.Rects = &buf_rects[buf_rects_out_n];
buf_rects_out_n += src_tmp.GlyphsCount;
// Compute multiply table if requested
const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
unsigned char multiply_table[256];
if (multiply_enabled)
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
// Gather the sizes of all rectangles we will need to pack
const int padding = atlas->TexGlyphPadding;
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
{
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);
IM_ASSERT(metrics != NULL);
if (metrics == NULL)
continue;
// Render glyph into a bitmap (currently held by FreeType)
const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
IM_ASSERT(ft_bitmap);
// Allocate new temporary chunk if needed
const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height;
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));
}
// Blit rasterized pixels to our temporary buffer and keep a pointer to it.
src_glyph.BitmapData = buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes;
buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width * 1, multiply_enabled ? multiply_table : NULL);
src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding);
src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding);
total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
}
}
// We need a width for the skyline algorithm, any width!
// The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
// User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
atlas->TexHeight = 0;
if (atlas->TexDesiredWidth > 0)
atlas->TexWidth = atlas->TexDesiredWidth;
else
atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
// 5. Start packing
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
const int TEX_HEIGHT_MAX = 1024 * 32;
const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;
ImVector<stbrp_node> pack_nodes;
pack_nodes.resize(num_nodes_for_packing_algorithm);
stbrp_context pack_context;
stbrp_init_target(&pack_context, atlas->TexWidth, TEX_HEIGHT_MAX, pack_nodes.Data, pack_nodes.Size);
ImFontAtlasBuildPackCustomRects(atlas, &pack_context);
// 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
if (src_tmp.GlyphsCount == 0)
continue;
stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount);
// Extend texture height and mark missing glyphs as non-packed so we won't render them.
// FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
if (src_tmp.Rects[glyph_i].was_packed)
atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
}
// 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);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
// Start packing
ImVector<stbrp_node> pack_nodes;
pack_nodes.resize(total_rects);
stbrp_context context;
stbrp_init_target(&context, atlas->TexWidth, atlas->TexHeight, pack_nodes.Data, total_rects);
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
ImFontAtlasBuildPackCustomRects(atlas, &context);
// Render characters, setup ImFont and glyphs for runtime
for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
// 8. Copy rasterized font characters back into the main texture
// 9. Setup ImFont and glyphs for runtime
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
ImFontConfig& cfg = atlas->ConfigData[input_i];
FreeTypeFont& font_face = fonts[input_i];
ImFont* dst_font = cfg.DstFont;
if (cfg.MergeMode)
dst_font->BuildLookupTable();
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
if (src_tmp.GlyphsCount == 0)
continue;
const float ascent = font_face.Info.Ascender;
const float descent = font_face.Info.Descender;
ImFontConfig& cfg = atlas->ConfigData[src_i];
ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
const float ascent = src_tmp.Font.Info.Ascender;
const float descent = src_tmp.Font.Info.Descender;
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
const float font_off_x = cfg.GlyphOffset.x;
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
unsigned char multiply_table[256];
if (multiply_enabled)
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2)
const int padding = atlas->TexGlyphPadding;
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
{
for (uint32_t codepoint = in_range[0]; codepoint <= in_range[1]; ++codepoint)
{
if (cfg.MergeMode && dst_font->FindGlyphNoFallback((unsigned short)codepoint))
continue;
ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
stbrp_rect& pack_rect = src_tmp.Rects[glyph_i];
IM_ASSERT(pack_rect.was_packed);
FT_Glyph ft_glyph = NULL;
FT_BitmapGlyph ft_glyph_bitmap = NULL; // NB: will point to bitmap within FT_Glyph
GlyphInfo glyph_info;
if (!font_face.CalcGlyphInfo(codepoint, glyph_info, ft_glyph, ft_glyph_bitmap))
continue;
GlyphInfo& info = src_glyph.Info;
IM_ASSERT(info.Width + padding <= pack_rect.w);
IM_ASSERT(info.Height + padding <= pack_rect.h);
const int tx = pack_rect.x + padding;
const int ty = pack_rect.y + padding;
// Pack rectangle
stbrp_rect rect;
rect.w = (uint16_t)glyph_info.Width + 1; // Account for texture filtering
rect.h = (uint16_t)glyph_info.Height + 1;
stbrp_pack_rects(&context, &rect, 1);
// Blit from temporary buffer to final texture
size_t blit_src_stride = (size_t)src_glyph.Info.Width;
size_t blit_dst_stride = (size_t)atlas->TexWidth;
unsigned char* blit_src = src_glyph.BitmapData;
unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
for (int y = info.Height; y > 0; y--, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
memcpy(blit_dst, blit_src, blit_src_stride);
// Copy rasterized pixels to main texture
uint8_t* blit_dst = atlas->TexPixelsAlpha8 + rect.y * atlas->TexWidth + rect.x;
font_face.BlitGlyph(ft_glyph_bitmap, blit_dst, atlas->TexWidth, multiply_enabled ? multiply_table : NULL);
FT_Done_Glyph(ft_glyph);
float char_advance_x_org = glyph_info.AdvanceX;
float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
float char_off_x = font_off_x;
if (char_advance_x_org != char_advance_x_mod)
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
// Register glyph
dst_font->AddGlyph((ImWchar)codepoint,
glyph_info.OffsetX + char_off_x,
glyph_info.OffsetY + font_off_y,
glyph_info.OffsetX + char_off_x + glyph_info.Width,
glyph_info.OffsetY + font_off_y + glyph_info.Height,
rect.x / (float)atlas->TexWidth,
rect.y / (float)atlas->TexHeight,
(rect.x + glyph_info.Width) / (float)atlas->TexWidth,
(rect.y + glyph_info.Height) / (float)atlas->TexHeight,
char_advance_x_mod);
}
float char_advance_x_org = info.AdvanceX;
float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
float char_off_x = font_off_x;
if (char_advance_x_org != char_advance_x_mod)
char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
// Register glyph
float x0 = info.OffsetX + char_off_x;
float y0 = info.OffsetY + font_off_y;
float x1 = x0 + info.Width;
float y1 = y0 + info.Height;
float u0 = (tx) / (float)atlas->TexWidth;
float v0 = (ty) / (float)atlas->TexHeight;
float u1 = (tx + info.Width) / (float)atlas->TexWidth;
float v1 = (ty + info.Height) / (float)atlas->TexHeight;
dst_font->AddGlyph((ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, char_advance_x_mod);
}
src_tmp.Rects = NULL;
}
// Cleanup
for (int n = 0; n < fonts.Size; n++)
fonts[n].Shutdown();
for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
ImGui::MemFree(buf_bitmap_buffers[buf_i]);
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
src_tmp_array[src_i].~ImFontBuildSrcDataFT();
ImFontAtlasBuildFinish(atlas);
return true;
}
bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
{
FT_Library ft_library;
FT_Error error = FT_Init_FreeType(&ft_library);
if (error != 0)
return false;
bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags);
FT_Done_FreeType(ft_library);
return ret;
}
+1 -1
View File
@@ -1,4 +1,4 @@
// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
// Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut
+47 -23
View File
@@ -1,10 +1,11 @@
// ImGui Platform Binding for: GLFW
// dear imgui: Platform Binding for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
@@ -14,6 +15,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
@@ -51,11 +54,17 @@ enum GlfwClientApi
GlfwClientApi_OpenGL,
GlfwClientApi_Vulkan
};
static GLFWwindow* g_Window = NULL;
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
static double g_Time = 0.0;
static bool g_MouseJustPressed[5] = { false, false, false, false, false };
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };
static GLFWwindow* g_Window = NULL;
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
static double g_Time = 0.0;
static bool g_MouseJustPressed[5] = { false, false, false, false, false };
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
static GLFWcharfun g_PrevUserCallbackChar = NULL;
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
@@ -67,49 +76,53 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
glfwSetClipboardString((GLFWwindow*)user_data, text);
}
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/)
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
if (g_PrevUserCallbackMousebutton != NULL)
g_PrevUserCallbackMousebutton(window, button, action, mods);
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
g_MouseJustPressed[button] = true;
}
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow*, double xoffset, double yoffset)
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
if (g_PrevUserCallbackScroll != NULL)
g_PrevUserCallbackScroll(window, xoffset, yoffset);
ImGuiIO& io = ImGui::GetIO();
io.MouseWheelH += (float)xoffset;
io.MouseWheel += (float)yoffset;
}
void ImGui_ImplGlfw_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (g_PrevUserCallbackKey != NULL)
g_PrevUserCallbackKey(window, key, scancode, action, mods);
ImGuiIO& io = ImGui::GetIO();
if (action == GLFW_PRESS)
io.KeysDown[key] = true;
if (action == GLFW_RELEASE)
io.KeysDown[key] = false;
(void)mods; // Modifiers are not reliable across systems
// Modifiers are not reliable across systems
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
}
void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c)
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
{
if (g_PrevUserCallbackChar != NULL)
g_PrevUserCallbackChar(window, c);
ImGuiIO& io = ImGui::GetIO();
if (c > 0 && c < 0x10000)
io.AddInputCharacter((unsigned short)c);
}
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
{
glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
}
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
g_Window = window;
@@ -119,6 +132,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendPlatformName = "imgui_impl_glfw";
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
@@ -159,8 +173,18 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
g_PrevUserCallbackMousebutton = NULL;
g_PrevUserCallbackScroll = NULL;
g_PrevUserCallbackKey = NULL;
g_PrevUserCallbackChar = NULL;
if (install_callbacks)
ImGui_ImplGlfw_InstallCallbacks(window);
{
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
}
g_ClientApi = client_api;
return true;
@@ -244,9 +268,9 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
void ImGui_ImplGlfw_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame()
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
glfwGetWindowSize(g_Window, &w, &h);
+6 -5
View File
@@ -1,10 +1,10 @@
// ImGui Platform Binding for: GLFW
// dear imgui: Platform Binding for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
@@ -16,6 +16,8 @@
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
#pragma once
struct GLFWwindow;
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
@@ -23,9 +25,8 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool in
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization)
// Provided here if you want to chain callbacks.
// You can also handle inputs yourself and use those as a reference.
// InitXXX function with 'install_callbacks=true': install GLFW callbacks. They will call user's previously installed callbacks, if any.
// InitXXX function with 'install_callbacks=false': do not install GLFW callbacks. You will need to call them yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
+25 -10
View File
@@ -1,4 +1,4 @@
// ImGui Renderer for: OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
// dear imgui: Renderer for OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
@@ -11,6 +11,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT).
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
@@ -99,6 +101,9 @@ static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
// Functions
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl3";
// Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
#ifdef USE_GL_ES3
if (glsl_version == NULL)
@@ -110,6 +115,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
strcpy(g_GlslVersionString, glsl_version);
strcat(g_GlslVersionString, "\n");
return true;
}
@@ -162,6 +168,12 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
bool clip_origin_lower_left = true;
#ifdef GL_CLIP_ORIGIN
GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
if (last_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false;
#endif
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
@@ -175,7 +187,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
#endif
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
@@ -234,7 +246,10 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
if (clip_origin_lower_left)
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
else
glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
@@ -306,13 +321,13 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture()
}
}
// If you get an error please report on github. You may try different GL context version or GLSL version.
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
static bool CheckShader(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if (status == GL_FALSE)
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
if (log_length > 0)
{
@@ -321,17 +336,17 @@ static bool CheckShader(GLuint handle, const char* desc)
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return status == GL_TRUE;
return (GLboolean)status == GL_TRUE;
}
// If you get an error please report on github. You may try different GL context version or GLSL version.
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
static bool CheckProgram(GLuint handle, const char* desc)
{
GLint status = 0, log_length = 0;
glGetProgramiv(handle, GL_LINK_STATUS, &status);
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
if (status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s!\n", desc);
if ((GLboolean)status == GL_FALSE)
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
if (log_length > 0)
{
ImVector<char> buf;
@@ -339,7 +354,7 @@ static bool CheckProgram(GLuint handle, const char* desc)
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
fprintf(stderr, "%s\n", buf.begin());
}
return status == GL_TRUE;
return (GLboolean)status == GL_TRUE;
}
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
+3 -1
View File
@@ -1,4 +1,4 @@
// ImGui Renderer for: OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
// dear imgui: Renderer for OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
@@ -19,6 +19,8 @@
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
#pragma once
// Set default OpenGL loader to be gl3w
#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \