Brett 2024-11-14 11:26:37 -05:00
parent f75cbbb10c
commit 1afe267163
9 changed files with 343 additions and 222 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
include(FetchContent) include(FetchContent)
set(BLT_GRAPHICS_VERSION 1.0.11) set(BLT_GRAPHICS_VERSION 1.0.12)
set(BLT_GRAPHICS_TEST_VERSION 0.0.1) set(BLT_GRAPHICS_TEST_VERSION 0.0.1)
project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION}) project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION})

View File

@ -8,83 +8,87 @@
namespace ImGui namespace ImGui
{ {
namespace Spectrum
{
extern const unsigned int SourceSansProRegular_compressed_size;
extern const unsigned int SourceSansProRegular_compressed_data[]; // defined later in the file
}
inline void SetupImGuiStyle( bool bStyleDark_, float alpha_ ) inline void SetupImGuiStyle(bool bStyleDark_, float alpha_)
{ {
ImGuiStyle& style = ImGui::GetStyle(); ImGuiStyle& style = ImGui::GetStyle();
// light style from Pacôme Danhiez (user itamago) https://github.com/ocornut/imgui/pull/511#issuecomment-175719267 // light style from Pacôme Danhiez (user itamago) https://github.com/ocornut/imgui/pull/511#issuecomment-175719267
style.Alpha = 1.0f; style.Alpha = 1.0f;
style.FrameRounding = 3.0f; style.FrameRounding = 3.0f;
style.Colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); style.Colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 0.94f); style.Colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 0.94f);
//style.Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); //style.Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.94f); style.Colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.94f);
style.Colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.39f); style.Colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.39f);
style.Colors[ImGuiCol_BorderShadow] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f); style.Colors[ImGuiCol_BorderShadow] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
style.Colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.94f); style.Colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.94f);
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); style.Colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 1.00f); style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.59f, 0.59f, 0.59f, 1.00f); style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.59f, 0.59f, 0.59f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
//style.Colors[ImGuiCol_ComboBg] = ImVec4(0.86f, 0.86f, 0.86f, 0.99f); //style.Colors[ImGuiCol_ComboBg] = ImVec4(0.86f, 0.86f, 0.86f, 0.99f);
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); style.Colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
style.Colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); style.Colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
style.Colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); style.Colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
//style.Colors[ImGuiCol_Column] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); //style.Colors[ImGuiCol_Column] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
//style.Colors[ImGuiCol_ColumnHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); //style.Colors[ImGuiCol_ColumnHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
//style.Colors[ImGuiCol_ColumnActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); //style.Colors[ImGuiCol_ColumnActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f); style.Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f);
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
//style.Colors[ImGuiCol_CloseButton] = ImVec4(0.59f, 0.59f, 0.59f, 0.50f); //style.Colors[ImGuiCol_CloseButton] = ImVec4(0.59f, 0.59f, 0.59f, 0.50f);
//style.Colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f); //style.Colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
//style.Colors[ImGuiCol_CloseButtonActive] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f); //style.Colors[ImGuiCol_CloseButtonActive] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); style.Colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
//style.Colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); //style.Colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
if( bStyleDark_ ) if (bStyleDark_)
{ {
for (int i = 0; i < ImGuiCol_COUNT; i++) for (int i = 0; i < ImGuiCol_COUNT; i++)
{ {
ImVec4& col = style.Colors[i]; ImVec4& col = style.Colors[i];
float H, S, V; float H, S, V;
ImGui::ColorConvertRGBtoHSV( col.x, col.y, col.z, H, S, V ); ImGui::ColorConvertRGBtoHSV(col.x, col.y, col.z, H, S, V);
if( S < 0.1f ) if (S < 0.1f)
{ {
V = 1.0f - V; V = 1.0f - V;
} }
ImGui::ColorConvertHSVtoRGB( H, S, V, col.x, col.y, col.z ); ImGui::ColorConvertHSVtoRGB(H, S, V, col.x, col.y, col.z);
if( col.w < 1.00f ) if (col.w < 1.00f)
{ {
col.w *= alpha_; col.w *= alpha_;
} }
} }
} } else
else
{ {
for (int i = 0; i < ImGuiCol_COUNT; i++) for (int i = 0; i < ImGuiCol_COUNT; i++)
{ {
ImVec4& col = style.Colors[i]; ImVec4& col = style.Colors[i];
if( col.w < 1.00f ) if (col.w < 1.00f)
{ {
col.x *= alpha_; col.x *= alpha_;
col.y *= alpha_; col.y *= alpha_;
@ -94,208 +98,207 @@ namespace ImGui
} }
} }
} }
inline bool CheckBoxFont( const char* name_, bool* pB_, const char* pOn_ = "[X]", const char* pOff_="[ ]" ) inline bool CheckBoxFont(const char* name_, bool* pB_, const char* pOn_ = "[X]", const char* pOff_ = "[ ]")
{ {
if( *pB_ ) if (*pB_)
{ {
ImGui::Text("%s", pOn_); ImGui::Text("%s", pOn_);
} } else
else
{ {
ImGui::Text("%s", pOff_); ImGui::Text("%s", pOff_);
} }
bool bHover = false; bool bHover = false;
bHover = bHover || ImGui::IsItemHovered(); bHover = bHover || ImGui::IsItemHovered();
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text( "%s", name_ ); ImGui::Text("%s", name_);
bHover = bHover || ImGui::IsItemHovered(); bHover = bHover || ImGui::IsItemHovered();
if( bHover && ImGui::IsMouseClicked(0) ) if (bHover && ImGui::IsMouseClicked(0))
{ {
*pB_ = ! *pB_; *pB_ = !*pB_;
return true; return true;
} }
return false; return false;
} }
inline bool CheckBoxTick( const char* name_, bool* pB_ ) inline bool CheckBoxTick(const char* name_, bool* pB_)
{ {
return CheckBoxFont( name_, pB_, ICON_FA_CHECK_SQUARE, ICON_FA_SQUARE ); return CheckBoxFont(name_, pB_, ICON_FA_CHECK_SQUARE, ICON_FA_SQUARE);
} }
inline bool MenuItemCheckbox( const char* name_, bool* pB_ ) inline bool MenuItemCheckbox(const char* name_, bool* pB_)
{ {
bool retval = ImGui::MenuItem( name_ ); bool retval = ImGui::MenuItem(name_);
ImGui::SameLine(); ImGui::SameLine();
if( *pB_ ) if (*pB_)
{ {
ImGui::Text(ICON_FA_CHECK_SQUARE); ImGui::Text(ICON_FA_CHECK_SQUARE);
} } else
else
{ {
ImGui::Text(ICON_FA_SQUARE); ImGui::Text(ICON_FA_SQUARE);
} }
if( retval ) if (retval)
{ {
*pB_ = ! *pB_; *pB_ = !*pB_;
} }
return retval; return retval;
} }
struct FrameTimeHistogram struct FrameTimeHistogram
{ {
// configuration params - modify these at will // configuration params - modify these at will
static const int NUM = 101; //last value is from T-1 to inf. static const int NUM = 101; //last value is from T-1 to inf.
float dT = 0.001f; // in seconds, default 1ms float dT = 0.001f; // in seconds, default 1ms
float refresh = 1.0f/60.0f;// set this to your target refresh rate float refresh = 1.0f / 60.0f;// set this to your target refresh rate
static const int NUM_MARKERS = 2; static const int NUM_MARKERS = 2;
float markers[NUM_MARKERS] = { 0.99f, 0.999f }; float markers[NUM_MARKERS] = {0.99f, 0.999f};
// data // data
ImVec2 size = ImVec2( 3.0f * NUM, 40.0f ); ImVec2 size = ImVec2(3.0f * NUM, 40.0f);
float lastdT = 0.0f; float lastdT = 0.0f;
float timesTotal; float timesTotal;
float countsTotal; float countsTotal;
float times[ NUM]; float times[NUM];
float counts[NUM]; float counts[NUM];
float hitchTimes[ NUM]; float hitchTimes[NUM];
float hitchCounts[NUM]; float hitchCounts[NUM];
FrameTimeHistogram() FrameTimeHistogram()
{ {
Clear(); Clear();
} }
void Clear() void Clear()
{ {
timesTotal = 0.0f; timesTotal = 0.0f;
countsTotal = 0.0f; countsTotal = 0.0f;
memset(times, 0, sizeof(times) ); memset(times, 0, sizeof(times));
memset(counts, 0, sizeof(counts) ); memset(counts, 0, sizeof(counts));
memset(hitchTimes, 0, sizeof(hitchTimes) ); memset(hitchTimes, 0, sizeof(hitchTimes));
memset(hitchCounts, 0, sizeof(hitchCounts) ); memset(hitchCounts, 0, sizeof(hitchCounts));
} }
int GetBin( float time_ ) int GetBin(float time_)
{ {
int bin = (int)std::floor( time_ / dT ); int bin = (int) std::floor(time_ / dT);
if( bin >= NUM ) if (bin >= NUM)
{ {
bin = NUM - 1; bin = NUM - 1;
} }
return bin; return bin;
} }
void Update( float deltaT_ ) void Update(float deltaT_)
{ {
if( deltaT_ < 0.0f ) if (deltaT_ < 0.0f)
{ {
assert(false); assert(false);
return; return;
} }
int bin = GetBin( deltaT_ ); int bin = GetBin(deltaT_);
times[ bin] += deltaT_; times[bin] += deltaT_;
timesTotal += deltaT_; timesTotal += deltaT_;
counts[bin] += 1.0f; counts[bin] += 1.0f;
countsTotal += 1.0f; countsTotal += 1.0f;
float hitch = abs( lastdT - deltaT_ ); float hitch = abs(lastdT - deltaT_);
int deltaBin = GetBin( hitch ); int deltaBin = GetBin(hitch);
hitchTimes[ deltaBin] += hitch; hitchTimes[deltaBin] += hitch;
hitchCounts[deltaBin] += 1.0f; hitchCounts[deltaBin] += 1.0f;
lastdT = deltaT_; lastdT = deltaT_;
} }
void PlotRefreshLines( float total_ = 0.0f, float* pValues_ = NULL) void PlotRefreshLines(float total_ = 0.0f, float* pValues_ = NULL)
{ {
ImDrawList* draw = ImGui::GetWindowDrawList(); ImDrawList* draw = ImGui::GetWindowDrawList();
const ImGuiStyle& style = ImGui::GetStyle(); const ImGuiStyle& style = ImGui::GetStyle();
ImVec2 pad = style.FramePadding; ImVec2 pad = style.FramePadding;
ImVec2 min = ImGui::GetItemRectMin(); ImVec2 min = ImGui::GetItemRectMin();
min.x += pad.x; min.x += pad.x;
ImVec2 max = ImGui::GetItemRectMax(); ImVec2 max = ImGui::GetItemRectMax();
max.x -= pad.x; max.x -= pad.x;
float xRefresh = (max.x - min.x) * refresh / ( dT * NUM ); float xRefresh = (max.x - min.x) * refresh / (dT * NUM);
float xCurr = xRefresh + min.x; float xCurr = xRefresh + min.x;
while( xCurr < max.x ) while (xCurr < max.x)
{ {
float xP = ceil( xCurr ); // use ceil to get integer coords or else lines look odd float xP = ceil(xCurr); // use ceil to get integer coords or else lines look odd
draw->AddLine( ImVec2( xP, min.y ), ImVec2( xP, max.y ), 0x50FFFFFF ); draw->AddLine(ImVec2(xP, min.y), ImVec2(xP, max.y), 0x50FFFFFF);
xCurr += xRefresh; xCurr += xRefresh;
} }
if( pValues_ ) if (pValues_)
{ {
// calc markers // calc markers
float currTotal = 0.0f; float currTotal = 0.0f;
int mark = 0; int mark = 0;
for( int i = 0; i < NUM && mark < NUM_MARKERS; ++i ) for (int i = 0; i < NUM && mark < NUM_MARKERS; ++i)
{ {
currTotal += pValues_[i]; currTotal += pValues_[i];
if( total_ * markers[mark] < currTotal ) if (total_ * markers[mark] < currTotal)
{ {
float xP = ceil( (float)(i+1)/(float)NUM * ( max.x - min.x ) + min.x ); // use ceil to get integer coords or else lines look odd float xP = ceil(
draw->AddLine( ImVec2( xP, min.y ), ImVec2( xP, max.y ), 0xFFFF0000 ); (float) (i + 1) / (float) NUM * (max.x - min.x) + min.x); // use ceil to get integer coords or else lines look odd
draw->AddLine(ImVec2(xP, min.y), ImVec2(xP, max.y), 0xFFFF0000);
++mark; ++mark;
} }
} }
} }
} }
void CalcHistogramSize( int numShown_ ) void CalcHistogramSize(int numShown_)
{ {
ImVec2 wRegion = ImGui::GetContentRegionMax(); ImVec2 wRegion = ImGui::GetContentRegionMax();
float heightGone = 7.0f * ImGui::GetTextLineHeightWithSpacing(); float heightGone = 7.0f * ImGui::GetTextLineHeightWithSpacing();
wRegion.y -= heightGone; wRegion.y -= heightGone;
wRegion.y /= (float) numShown_; wRegion.y /= (float) numShown_;
const ImGuiStyle& style = ImGui::GetStyle(); const ImGuiStyle& style = ImGui::GetStyle();
ImVec2 pad = style.FramePadding; ImVec2 pad = style.FramePadding;
wRegion.x -= 2.0f * pad.x; wRegion.x -= 2.0f * pad.x;
size = wRegion; size = wRegion;
} }
void Draw(const char* name_, bool* pOpen_ = NULL ) void Draw(const char* name_, bool* pOpen_ = NULL)
{ {
if (ImGui::Begin( name_, pOpen_ )) if (ImGui::Begin(name_, pOpen_))
{ {
int numShown = 0; int numShown = 0;
if(ImGui::CollapsingHeader("Time Histogram")) if (ImGui::CollapsingHeader("Time Histogram"))
{ {
++numShown; ++numShown;
ImGui::PlotHistogram("", times, NUM, 0, NULL, FLT_MAX, FLT_MAX, size ); ImGui::PlotHistogram("", times, NUM, 0, NULL, FLT_MAX, FLT_MAX, size);
PlotRefreshLines( timesTotal, times ); PlotRefreshLines(timesTotal, times);
} }
if(ImGui::CollapsingHeader("Count Histogram")) if (ImGui::CollapsingHeader("Count Histogram"))
{ {
++numShown; ++numShown;
ImGui::PlotHistogram("", counts, NUM, 0, NULL, FLT_MAX, FLT_MAX, size ); ImGui::PlotHistogram("", counts, NUM, 0, NULL, FLT_MAX, FLT_MAX, size);
PlotRefreshLines( countsTotal, counts ); PlotRefreshLines(countsTotal, counts);
} }
if(ImGui::CollapsingHeader("Hitch Time Histogram")) if (ImGui::CollapsingHeader("Hitch Time Histogram"))
{ {
++numShown; ++numShown;
ImGui::PlotHistogram("", hitchTimes, NUM, 0, NULL, FLT_MAX, FLT_MAX, size ); ImGui::PlotHistogram("", hitchTimes, NUM, 0, NULL, FLT_MAX, FLT_MAX, size);
PlotRefreshLines(); PlotRefreshLines();
} }
if(ImGui::CollapsingHeader("Hitch Count Histogram")) if (ImGui::CollapsingHeader("Hitch Count Histogram"))
{ {
++numShown; ++numShown;
ImGui::PlotHistogram("", hitchCounts, NUM, 0, NULL, FLT_MAX, FLT_MAX, size ); ImGui::PlotHistogram("", hitchCounts, NUM, 0, NULL, FLT_MAX, FLT_MAX, size);
PlotRefreshLines(); PlotRefreshLines();
} }
if( ImGui::Button("Clear") ) if (ImGui::Button("Clear"))
{ {
Clear(); Clear();
} }
CalcHistogramSize( numShown ); CalcHistogramSize(numShown);
} }
ImGui::End(); ImGui::End();
} }
}; };
}; };

View File

@ -87,7 +87,8 @@ namespace blt::gfx
explicit point2d_t(const vec2f pos): pos(pos) explicit point2d_t(const vec2f pos): pos(pos)
{} {}
point2d_t apply_scale(float s) const { point2d_t apply_scale(float s) const
{
return {pos, scale * s}; return {pos, scale * s};
} }
}; };

View File

@ -23,6 +23,7 @@
#include <blt/gfx/texture.h> #include <blt/gfx/texture.h>
#include <blt/gfx/shader.h> #include <blt/gfx/shader.h>
#include <blt/gfx/model.h> #include <blt/gfx/model.h>
#include <blt/gfx/framebuffer.h>
#include <blt/std/hashmap.h> #include <blt/std/hashmap.h>
#include <blt/std/binary_tree.h> #include <blt/std/binary_tree.h>
@ -118,6 +119,24 @@ namespace blt::gfx
class font_renderer_t class font_renderer_t
{ {
public: public:
struct render_context
{
blt::vec2f position, bounds;
blt::vec2f scale;
blt::vec4 color;
};
struct text_index_t
{
std::string text;
float size;
std::string font;
bool operator==(const text_index_t& rhs) const;
bool operator!=(const text_index_t& rhs) const;
};
struct compiled_text_t struct compiled_text_t
{ {
friend font_renderer_t; friend font_renderer_t;
@ -135,22 +154,21 @@ namespace blt::gfx
compiled_text_t& setBounds(const blt::vec2f& limit) compiled_text_t& setBounds(const blt::vec2f& limit)
{ {
bounds = limit; bounds = limit;
recompile();
return *this; return *this;
} }
compiled_text_t& setBounds(float width, float height)
{
return setBounds({width, height});
}
compiled_text_t& setUnrestrictedBounds() compiled_text_t& setUnrestrictedBounds()
{ {
bounds = {}; bounds = {};
return *this; return *this;
} }
compiled_text_t& setSize(float size)
{
current_size = size;
scale = {size / generator.get_generated_size(), size / generator.get_generated_size()};
return *this;
}
compiled_text_t& setColor(const blt::vec4f& c) compiled_text_t& setColor(const blt::vec4f& c)
{ {
color = c; color = c;
@ -169,6 +187,14 @@ namespace blt::gfx
return *this; return *this;
} }
compiled_text_t& setSize(float size)
{
current_size = size;
scale = {size / generator.get_generated_size(), size / generator.get_generated_size()};
recompile();
return *this;
}
compiled_text_t& setZIndex(float s) compiled_text_t& setZIndex(float s)
{ {
z_index = s; z_index = s;
@ -212,7 +238,7 @@ namespace blt::gfx
std::vector<text_render_info_t> renders; std::vector<text_render_info_t> renders;
blt::vec2f position, bounds; blt::vec2f position, bounds;
blt::vec2f scale = {1, 1}; blt::vec2f scale = {1, 1};
blt::vec4 color = blt::make_color(1, 1, 1); blt::vec4 color = blt::make_color(0.8, 0.8, 0.8);
float z_index = 0; float z_index = 0;
float current_size = 0; float current_size = 0;
}; };
@ -237,19 +263,52 @@ namespace blt::gfx
compiled_text_t* create_text(std::string_view str, float size, std::string_view font = "__default"); compiled_text_t* create_text(std::string_view str, float size, std::string_view font = "__default");
compiled_text_t* render_text(std::string_view str, float size, std::string_view font = "__default");
void destroy_text(compiled_text_t* text); void destroy_text(compiled_text_t* text);
void render(); void render();
private: private:
std::unique_ptr<compiled_text_t> allocate_text();
std::unique_ptr<font_generator_t> generator; std::unique_ptr<font_generator_t> generator;
std::unique_ptr<shader_t> font_shader; std::unique_ptr<shader_t> font_shader;
blt::hashmap_t<text_index_t, compiled_text_t*> rendered_strings;
blt::hashmap_t<compiled_text_t*, text_index_t> text_ptr_to_text_index;
blt::hashset_t<compiled_text_t*> last_rendered_strings;
blt::hashset_t<compiled_text_t*> currently_rendered_strings;
blt::hashmap_t<compiled_text_t*, blt::size_t> text_ptr_to_index; blt::hashmap_t<compiled_text_t*, blt::size_t> text_ptr_to_index;
std::vector<std::unique_ptr<compiled_text_t>> added_texts; std::vector<std::unique_ptr<compiled_text_t>> added_texts;
std::vector<std::unique_ptr<compiled_text_t>> cached_text_objects; std::vector<std::unique_ptr<compiled_text_t>> cached_deallocated_text_objects;
}; };
} }
namespace blt::gfx::detail
{
inline void hash_combine(std::size_t& seed, const std::size_t& value)
{
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
}
// Specialization of std::hash for text_index_t
template<>
struct std::hash<blt::gfx::font_renderer_t::text_index_t>
{
std::size_t operator()(const blt::gfx::font_renderer_t::text_index_t& key) const
{
blt::size_t hash = 0;
blt::gfx::detail::hash_combine(hash, std::hash<std::string>{}(key.text));
blt::gfx::detail::hash_combine(hash, std::hash<float>{}(key.size));
blt::gfx::detail::hash_combine(hash, std::hash<std::string>{}(key.font));
return hash;
}
};
#endif //BLT_WITH_GRAPHICS_FONT_RENDERER_H #endif //BLT_WITH_GRAPHICS_FONT_RENDERER_H

View File

@ -11,9 +11,14 @@ const std::string shader_2d_font_frag = R"("
uniform vec4 color; uniform vec4 color;
void main() { void main() {
FragColor = texture(tex, uv).r * color; if (texture(tex, uv).r > 0.2)
if (FragColor.a < 0.2) FragColor = color;
else
discard; discard;
// if (FragColor.a < 0.2)
// discard;
// else
// FragColor.a = 1.0;
} }
")"; ")";

View File

@ -18,7 +18,10 @@
#include <blt/gfx/renderer/font_renderer.h> #include <blt/gfx/renderer/font_renderer.h>
#include <blt/gfx/renderer/shaders/2d_font.vert> #include <blt/gfx/renderer/shaders/2d_font.vert>
#include <blt/gfx/renderer/shaders/2d_font.frag> #include <blt/gfx/renderer/shaders/2d_font.frag>
#include "blt/gfx/window.h"
#include <blt/gfx/shader.h> #include <blt/gfx/shader.h>
#include <blt/gfx/imgui/ImGuiUtils.h>
#include <cctype> #include <cctype>
// TODO: signed distance fonts // TODO: signed distance fonts
@ -147,18 +150,20 @@ namespace blt::gfx
void font_renderer_t::create_default(float gen_size, blt::i32 dimensions) void font_renderer_t::create_default(float gen_size, blt::i32 dimensions)
{ {
create(gen_size, dimensions); create(gen_size, dimensions);
add_default_font(reinterpret_cast<const blt::u8*>(font::default_font_compressed_data), font::default_font_compressed_size, true); // add_default_font(reinterpret_cast<const blt::u8*>(font::default_font_compressed_data), font::default_font_compressed_size, true);
add_default_font(reinterpret_cast<const blt::u8*>(ImGui::Spectrum::SourceSansProRegular_compressed_data),
ImGui::Spectrum::SourceSansProRegular_compressed_size, true);
} }
void font_renderer_t::cleanup() void font_renderer_t::cleanup()
{ {
for (auto& n : added_texts) for (auto& n : added_texts)
n = nullptr; n = nullptr;
for (auto& c : cached_text_objects) for (auto& c : cached_deallocated_text_objects)
c = nullptr; c = nullptr;
added_texts.clear(); added_texts.clear();
cached_text_objects.clear(); cached_deallocated_text_objects.clear();
text_ptr_to_index.clear(); text_ptr_to_index.clear();
font_shader = nullptr; font_shader = nullptr;
generator = nullptr; generator = nullptr;
@ -167,15 +172,7 @@ namespace blt::gfx
font_renderer_t::compiled_text_t* font_renderer_t::create_text(std::string_view str, float size, std::string_view font) font_renderer_t::compiled_text_t* font_renderer_t::create_text(std::string_view str, float size, std::string_view font)
{ {
std::unique_ptr<font_renderer_t::compiled_text_t> ptr; std::unique_ptr<font_renderer_t::compiled_text_t> ptr = allocate_text();
if (!cached_text_objects.empty())
{
ptr = std::move(*cached_text_objects.begin());
cached_text_objects.erase(cached_text_objects.begin());
} else
{
ptr = std::unique_ptr<compiled_text_t>(new compiled_text_t{*generator});
}
ptr->setText(str, size, font); ptr->setText(str, size, font);
auto index = added_texts.size(); auto index = added_texts.size();
added_texts.push_back(std::move(ptr)); added_texts.push_back(std::move(ptr));
@ -187,18 +184,22 @@ namespace blt::gfx
{ {
auto index = text_ptr_to_index[text]; auto index = text_ptr_to_index[text];
text_ptr_to_index.erase(text); text_ptr_to_index.erase(text);
cached_text_objects.push_back(std::move(added_texts[index])); cached_deallocated_text_objects.push_back(std::move(added_texts[index]));
added_texts[index] = nullptr; added_texts[index] = nullptr;
added_texts.erase(added_texts.begin() + static_cast<blt::ptrdiff_t>(index)); added_texts.erase(added_texts.begin() + static_cast<blt::ptrdiff_t>(index));
} }
void font_renderer_t::render() void font_renderer_t::render()
{ {
#ifndef __EMSCRIPTEN__
glDisable(GL_MULTISAMPLE);
#endif
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
font_shader->bind(); font_shader->bind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
for (auto& text : added_texts) for (auto [text, index] : text_ptr_to_index)
{ {
blt::mat4x4 transform; blt::mat4x4 transform;
transform.translate(text->position); transform.translate(text->position);
@ -208,22 +209,87 @@ namespace blt::gfx
font_shader->setVec4("color", text->color); font_shader->setVec4("color", text->color);
text->draw(); text->draw();
} }
for (auto& text : currently_rendered_strings)
{
blt::mat4x4 transform;
transform.translate(text->position);
transform.scale(text->scale);
font_shader->setMatrix("transform", transform);
font_shader->setFloat("z_index", text->z_index);
font_shader->setVec4("color", text->color);
text->draw();
if (last_rendered_strings.find(text) != last_rendered_strings.end())
last_rendered_strings.erase(text);
}
for (auto& text : last_rendered_strings)
{
rendered_strings.erase(text_ptr_to_text_index[text]);
text_ptr_to_text_index.erase(text);
cached_deallocated_text_objects.emplace_back(std::move(added_texts[text_ptr_to_index[text]]));
text_ptr_to_index.erase(text);
}
for (auto& text : currently_rendered_strings)
last_rendered_strings.insert(text);
currently_rendered_strings.clear();
#ifndef __EMSCRIPTEN__
glEnable(GL_MULTISAMPLE);
#endif
} }
void font_renderer_t::add_default_font(std::string_view path, std::string_view name) void font_renderer_t::add_default_font(std::string_view path, std::string_view name)
{ {
font::font_face_t default_font_face{path, name}; font::font_face_t default_font_face{path, name};
font::font_file_t default_font{default_font_face, 0, 128}; font::font_file_t default_font{default_font_face, 0, 256};
add_font(default_font); add_font(default_font);
} }
void font_renderer_t::add_default_font(const blt::u8* data, blt::size_t size, bool compressed, std::string_view name) void font_renderer_t::add_default_font(const blt::u8* data, blt::size_t size, bool compressed, std::string_view name)
{ {
font::font_face_t default_font_face{name, data, size, compressed}; font::font_face_t default_font_face{name, data, size, compressed};
font::font_file_t default_font{default_font_face, 0, 128}; font::font_file_t default_font{default_font_face, 0, 256};
add_font(default_font); add_font(default_font);
} }
std::unique_ptr<font_renderer_t::compiled_text_t> font_renderer_t::allocate_text()
{
std::unique_ptr<font_renderer_t::compiled_text_t> ptr;
if (!cached_deallocated_text_objects.empty())
{
ptr = std::move(*cached_deallocated_text_objects.begin());
cached_deallocated_text_objects.erase(cached_deallocated_text_objects.begin());
} else
{
ptr = std::unique_ptr<compiled_text_t>(new compiled_text_t{*generator});
}
return ptr;
}
font_renderer_t::compiled_text_t* font_renderer_t::render_text(std::string_view str, float size, std::string_view font)
{
auto str_iter = rendered_strings.find(text_index_t{std::string(str), size, std::string(font)});
if (str_iter != rendered_strings.end())
{
currently_rendered_strings.insert(str_iter->second);
return str_iter->second;
}
auto index = added_texts.size();
added_texts.emplace_back(allocate_text());
auto ptr = added_texts.back().get();
ptr->setText(str, size);
text_ptr_to_text_index[ptr] = text_index_t{std::string(str), size, std::string(font)};
rendered_strings[text_index_t{std::string(str), size, std::string(font)}] = ptr;
text_ptr_to_index[ptr] = index;
currently_rendered_strings.insert(ptr);
return ptr;
}
font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::setText(std::string_view str, float size, std::string_view f) font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::setText(std::string_view str, float size, std::string_view f)
{ {
if (str == contents) if (str == contents)
@ -262,40 +328,9 @@ namespace blt::gfx
} }
} }
struct word_t
{
std::vector<float> vertices;
float x = 0;
void apply(std::vector<float>& out)
{
for (float v : vertices)
out.push_back(v + x);
vertices.clear();
x = 0;
}
};
struct position_tracker_t
{
float global_x = 0, global_y = 0;
void newline(float line_size)
{
global_y -= line_size;
global_x = 0;
}
void advance(blt::u64 size)
{
global_x += static_cast<float>(size >> 6);
}
};
font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::recompile() font_renderer_t::compiled_text_t& font_renderer_t::compiled_text_t::recompile()
{ {
static std::vector<float> vertices; static std::vector<float> vertices;
static word_t current_word;
vertices.clear(); vertices.clear();
renders.clear(); renders.clear();
@ -303,27 +338,33 @@ namespace blt::gfx
blt::size_t draw_start = 0; blt::size_t draw_start = 0;
blt::size_t draw_count = 0; blt::size_t draw_count = 0;
position_tracker_t current_pos; const float sc = generator.get_generated_size() / current_size;
float global_x = 0;
float global_y = 0;
// TODO: parker UTF8 // TODO: parker UTF8
for (const auto& c : contents) for (const auto& c : contents)
{ {
// std::cout << "C: " << c << " || " << static_cast<int>(c) << std::endl; if (bounds.y() > 0 && std::abs(global_y) >= bounds.y() * sc)
continue;
if (c == '\n') if (c == '\n')
{ {
current_pos.newline(generator.get_generated_size()); global_x = 0;
global_y -= generator.get_generated_size();
continue; continue;
} }
auto& texture = generator.get_texture(std::string(font), c); auto& texture = generator.get_texture(std::string(font), c);
auto& ch = texture.get_glyph(c, font); auto& ch = texture.get_glyph(c, font);
// if (std::isblank(c)) if (std::isblank(c))
// { {
// if (bounds.x() > 0 && current_pos.global_x + current_word.x > bounds.x()) if (bounds.x() > 0 && global_x > bounds.x() * sc)
// current_pos.newline(generator.get_generated_size()); {
// global_x = 0;
// } global_y -= generator.get_generated_size();
if (std::isspace(c)) continue;
current_word.apply(vertices); }
}
if (last_texture == nullptr) if (last_texture == nullptr)
last_texture = &texture; last_texture = &texture;
@ -336,8 +377,8 @@ namespace blt::gfx
auto dims = static_cast<float>(generator.get_dimensions()); auto dims = static_cast<float>(generator.get_dimensions());
float x_pos = current_pos.global_x + static_cast<float>(ch.glyph.bearing.x()); float x_pos = global_x + static_cast<float>(ch.glyph.bearing.x());
float y_pos = current_pos.global_y - static_cast<float>(ch.glyph.size.y() - ch.glyph.bearing.y()); float y_pos = global_y - static_cast<float>(ch.glyph.size.y() - ch.glyph.bearing.y());
auto w = static_cast<float>(ch.glyph.size.x()); auto w = static_cast<float>(ch.glyph.size.x());
auto h = static_cast<float>(ch.glyph.size.y()); auto h = static_cast<float>(ch.glyph.size.y());
@ -358,12 +399,11 @@ namespace blt::gfx
x_pos + w, y_pos, texture_max_x, texture_max_y, x_pos + w, y_pos, texture_max_x, texture_max_y,
x_pos + w, y_pos + h, texture_max_x, texture_min_y x_pos + w, y_pos + h, texture_max_x, texture_min_y
}; };
current_word.vertices.insert(current_word.vertices.end(), local_vert.begin(), local_vert.end()); vertices.insert(vertices.end(), local_vert.begin(), local_vert.end());
draw_count += 6; draw_count += 6;
current_pos.advance(ch.glyph.advance); global_x += static_cast<float>(ch.glyph.advance >> 6);
} }
current_word.apply(vertices);
// BLT_TRACE("size: %ld %ld %ld", draw_count, vertices.size(), vertices.size() / 4); // BLT_TRACE("size: %ld %ld %ld", draw_count, vertices.size(), vertices.size() / 4);
@ -373,4 +413,13 @@ namespace blt::gfx
} }
bool font_renderer_t::text_index_t::operator==(const font_renderer_t::text_index_t& rhs) const
{
return text == rhs.text && blt::f_equal(size, rhs.size) && font == rhs.font;
}
bool font_renderer_t::text_index_t::operator!=(const font_renderer_t::text_index_t& rhs) const
{
return !(rhs == *this);
}
} }

View File

@ -76,10 +76,13 @@ namespace blt::gfx
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} while (true); } while (true);
#else #else
for (const auto& texture : textures_to_load) for (const auto& [destination, texture] : textures_to_load)
{ {
BLT_DEBUG("Loading texture file %s", texture.path.c_str()); auto path = resource_prefix + texture.get_path();
loaded_textures.push_back(new texture_file(texture.path, texture.name)); auto* file = new texture_file(path, texture.get_name(), texture.get_desired_channels());
file->resize(texture.get_desired_width(), texture.get_desired_height());
BLT_DEBUG("Loading texture file %s", path.c_str());
destination.add(file);
} }
textures_to_load.clear(); textures_to_load.clear();
#endif #endif

View File

@ -136,7 +136,7 @@ namespace blt::gfx
// Setup Dear ImGui style // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
//ImGui::Spectrum::StyleColorsSpectrum(); // ImGui::Spectrum::StyleColorsSpectrum();
ImGui::Spectrum::LoadFont(); ImGui::Spectrum::LoadFont();
ImGui::SetupImGuiStyle(true, 1.0); ImGui::SetupImGuiStyle(true, 1.0);
@ -157,7 +157,7 @@ namespace blt::gfx
// Setup Platform/Renderer backends // Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window_state.window, true); ImGui_ImplGlfw_InitForOpenGL(window_state.window, true);
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas"); // ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas");
#endif #endif
ImGui_ImplOpenGL3_Init(glsl_version); ImGui_ImplOpenGL3_Init(glsl_version);

View File

@ -19,8 +19,8 @@
namespace ImGui::Spectrum namespace ImGui::Spectrum
{ {
extern const unsigned int SourceSansProRegular_compressed_size = 149392; // extern const unsigned int SourceSansProRegular_compressed_size;
extern const unsigned int SourceSansProRegular_compressed_data[]; // defined later in the file // extern const unsigned int SourceSansProRegular_compressed_data[]; // defined later in the file
void StyleColorsSpectrum() void StyleColorsSpectrum()
{ {
@ -81,6 +81,7 @@ namespace ImGui::Spectrum
io.FontDefault = font; io.FontDefault = font;
} }
const unsigned int SourceSansProRegular_compressed_size = 149392;
const unsigned int SourceSansProRegular_compressed_data[149392 / 4] = const unsigned int SourceSansProRegular_compressed_data[149392 / 4] =
{ {
0x0000bc57, 0x00000000, 0x7ce00300, 0x00000400, 0x00010037, 0x000f0000, 0x00030080, 0x53414270, 0x5d1e6545, 0x2d0200bd, 0x0000bc57, 0x00000000, 0x7ce00300, 0x00000400, 0x00010037, 0x000f0000, 0x00030080, 0x53414270, 0x5d1e6545, 0x2d0200bd,