Browse Source

Fixes to allow clean 1-pixel thick lines in more use cases. PixelCenterOffset not the same as previously!

pull/33/merge
ocornut 10 years ago
parent
commit
88c33ecc29
  1. 4
      examples/directx9_example/main.cpp
  2. 4
      examples/opengl_example/main.cpp
  3. 77
      imgui.cpp
  4. 2
      imgui.h

4
examples/directx9_example/main.cpp

@ -22,8 +22,8 @@ struct CUSTOMVERTEX
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
// If text or lines are blurry when integrating ImGui in your engine: // If text or lines are blurry when integrating ImGui in your engine:
// - try adjusting ImGui::GetIO().PixelCenterOffset to 0.0f or 0.5f
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
// - try adjusting ImGui::GetIO().PixelCenterOffset to 0.5f or 0.375f
static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
{ {
size_t total_vtx_count = 0; size_t total_vtx_count = 0;
@ -82,7 +82,7 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
D3DXMatrixIdentity(&mat); D3DXMatrixIdentity(&mat);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat); g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat); g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat);
D3DXMatrixOrthoOffCenterLH(&mat, 0.0f, ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y, 0.0f, -1.0f, +1.0f); D3DXMatrixOrthoOffCenterLH(&mat, 0.5f, ImGui::GetIO().DisplaySize.x+0.5f, ImGui::GetIO().DisplaySize.y+0.5f, 0.5f, -1.0f, +1.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat); g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat);
// Render command lists // Render command lists

4
examples/opengl_example/main.cpp

@ -13,8 +13,8 @@ static GLuint fontTex;
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
// If text or lines are blurry when integrating ImGui in your engine: // If text or lines are blurry when integrating ImGui in your engine:
// - try adjusting ImGui::GetIO().PixelCenterOffset to 0.0f or 0.5f
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
// - try adjusting ImGui::GetIO().PixelCenterOffset to 0.5f or 0.375f
static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
{ {
if (cmd_lists_count == 0) if (cmd_lists_count == 0)
@ -151,7 +151,7 @@ void InitImGui()
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2((float)w, (float)h); // Display size, in pixels. For clamping windows positions. io.DisplaySize = ImVec2((float)w, (float)h); // Display size, in pixels. For clamping windows positions.
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable) io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable)
io.PixelCenterOffset = 0.5f; // Align OpenGL texels io.PixelCenterOffset = 0.0f; // Align OpenGL texels
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;

77
imgui.cpp

@ -88,8 +88,8 @@
} }
- if text or lines are blurry when integrating ImGui in your engine: - if text or lines are blurry when integrating ImGui in your engine:
- try adjusting ImGui::GetIO().PixelCenterOffset to 0.0f or 0.5f
- in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
- try adjusting ImGui::GetIO().PixelCenterOffset to 0.5f or 0.375f
- some widgets carry state and requires an unique ID to do so. - some widgets carry state and requires an unique ID to do so.
- unique ID are typically derived from a string label, an indice or a pointer. - unique ID are typically derived from a string label, an indice or a pointer.
@ -280,7 +280,7 @@ ImGuiIO::ImGuiIO()
LogFilename = "imgui_log.txt"; LogFilename = "imgui_log.txt";
Font = NULL; Font = NULL;
FontAllowScaling = false; FontAllowScaling = false;
PixelCenterOffset = 0.5f; PixelCenterOffset = 0.0f;
MousePos = ImVec2(-1,-1); MousePos = ImVec2(-1,-1);
MousePosPrev = ImVec2(-1,-1); MousePosPrev = ImVec2(-1,-1);
MouseDoubleClickTime = 0.30f; MouseDoubleClickTime = 0.30f;
@ -1560,8 +1560,10 @@ static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border,
window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
if (border && (window->Flags & ImGuiWindowFlags_ShowBorders)) if (border && (window->Flags & ImGuiWindowFlags_ShowBorders))
{ {
window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), rounding); // FIXME: I have no idea how this is working correctly but it is the best I've found that works on multiple rendering
window->DrawList->AddRect(p_min, p_max, window->Color(ImGuiCol_Border), rounding); const float offset = GImGui.IO.PixelCenterOffset;
window->DrawList->AddRect(p_min+ImVec2(1.5f-offset,1.5f-offset), p_max+ImVec2(1.0f-offset*2,1.0f-offset*2), window->Color(ImGuiCol_BorderShadow), rounding);
window->DrawList->AddRect(p_min+ImVec2(0.5f-offset,0.5f-offset), p_max+ImVec2(0.0f-offset*2,0.0f-offset*2), window->Color(ImGuiCol_Border), rounding);
} }
} }
@ -2768,20 +2770,21 @@ static bool CloseWindowButton(bool* open)
const ImGuiID id = window->GetID("##CLOSE"); const ImGuiID id = window->GetID("##CLOSE");
const float size = window->TitleBarHeight() - 4.0f; const float size = window->TitleBarHeight() - 4.0f;
const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-2.0f-size,2.0f), window->Aabb().GetTR() + ImVec2(-2.0f,2.0f+size)); const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-3.0f-size,2.0f), window->Aabb().GetTR() + ImVec2(-3.0f,2.0f+size));
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true);
// Render // Render
const ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); const ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton);
window->DrawList->AddCircleFilled(bb.GetCenter(), ImMax(2.0f,size*0.5f-2.0f), col, 16); const ImVec2 center = bb.GetCenter();
window->DrawList->AddCircleFilled(center, ImMax(2.0f,size*0.5f), col, 16);
const float cross_padding = 4.0f; const float cross_extent = (size * 0.5f * 0.7071f) - 1.0f;
if (hovered && bb.GetWidth() >= (cross_padding+1)*2 && bb.GetHeight() >= (cross_padding+1)*2) if (hovered)
{ {
window->DrawList->AddLine(bb.GetTL()+ImVec2(+cross_padding,+cross_padding), bb.GetBR()+ImVec2(-cross_padding,-cross_padding), window->Color(ImGuiCol_Text)); window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), window->Color(ImGuiCol_Text));
window->DrawList->AddLine(bb.GetBL()+ImVec2(+cross_padding,-cross_padding), bb.GetTR()+ImVec2(-cross_padding,+cross_padding), window->Color(ImGuiCol_Text)); window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), window->Color(ImGuiCol_Text));
} }
if (open != NULL && pressed) if (open != NULL && pressed)
@ -4815,16 +4818,18 @@ void ImDrawList::AddVtx(const ImVec2& pos, ImU32 col)
void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col) void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col)
{ {
const ImVec2 n = (b - a) / ImLength(b - a); const float offset = GImGui.IO.PixelCenterOffset;
const ImVec2 hn = ImVec2(n.y, -n.x) * 0.5f; const ImVec2 hn = (b - a) * (0.50f / ImLength(b - a)); // half normal
const ImVec2 hp0 = ImVec2(offset - hn.y, offset + hn.x); // half perpendiculars + user offset
AddVtx(a - hn, col); const ImVec2 hp1 = ImVec2(offset + hn.y, offset - hn.x);
AddVtx(b - hn, col);
AddVtx(a + hn, col);
AddVtx(b - hn, col); // Two triangles makes up one line. Using triangles allows us to make draw calls.
AddVtx(b + hn, col); AddVtx(a + hp0, col);
AddVtx(a + hn, col); AddVtx(b + hp0, col);
AddVtx(a + hp1, col);
AddVtx(b + hp0, col);
AddVtx(b + hp1, col);
AddVtx(a + hp1, col);
} }
void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col) void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col)
@ -4966,10 +4971,12 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec
if ((col >> 24) == 0) if ((col >> 24) == 0)
return; return;
const ImVec2 offset(GImGui.IO.PixelCenterOffset,GImGui.IO.PixelCenterOffset);
ReserveVertices(3); ReserveVertices(3);
AddVtx(a, col); AddVtx(a + offset, col);
AddVtx(b, col); AddVtx(b + offset, col);
AddVtx(c, col); AddVtx(c + offset, col);
} }
void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments) void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments)
@ -4977,13 +4984,15 @@ void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int nu
if ((col >> 24) == 0) if ((col >> 24) == 0)
return; return;
const ImVec2 offset(GImGui.IO.PixelCenterOffset,GImGui.IO.PixelCenterOffset);
ReserveVertices((unsigned int)num_segments*6); ReserveVertices((unsigned int)num_segments*6);
const float a_step = 2*PI/(float)num_segments; const float a_step = 2*PI/(float)num_segments;
float a0 = 0.0f; float a0 = 0.0f;
for (int i = 0; i < num_segments; i++) for (int i = 0; i < num_segments; i++)
{ {
const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step; const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step;
AddVtxLine(centre + ImVec2(cos(a0),sin(a0))*radius, centre + ImVec2(cos(a1),sin(a1))*radius, col); AddVtxLine(centre + offset + ImVec2(cos(a0),sin(a0))*radius, centre + ImVec2(cos(a1),sin(a1))*radius, col);
a0 = a1; a0 = a1;
} }
} }
@ -4993,15 +5002,17 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col,
if ((col >> 24) == 0) if ((col >> 24) == 0)
return; return;
const ImVec2 offset(GImGui.IO.PixelCenterOffset,GImGui.IO.PixelCenterOffset);
ReserveVertices((unsigned int)num_segments*3); ReserveVertices((unsigned int)num_segments*3);
const float a_step = 2*PI/(float)num_segments; const float a_step = 2*PI/(float)num_segments;
float a0 = 0.0f; float a0 = 0.0f;
for (int i = 0; i < num_segments; i++) for (int i = 0; i < num_segments; i++)
{ {
const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step; const float a1 = (i + 1) == num_segments ? 0.0f : a0 + a_step;
AddVtx(centre + ImVec2(cos(a0),sin(a0))*radius, col); AddVtx(centre + offset + ImVec2(cos(a0),sin(a0))*radius, col);
AddVtx(centre + ImVec2(cos(a1),sin(a1))*radius, col); AddVtx(centre + offset + ImVec2(cos(a1),sin(a1))*radius, col);
AddVtx(centre, col); AddVtx(centre + offset, col);
a0 = a1; a0 = a1;
} }
} }
@ -5231,13 +5242,11 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
const float outline = (float)Info->Outline; const float outline = (float)Info->Outline;
// Align to be pixel perfect // Align to be pixel perfect
pos.x = (float)(int)pos.x + 0.5f; pos.x = (float)(int)pos.x;
pos.y = (float)(int)pos.y + 0.5f; pos.y = (float)(int)pos.y;
const ImVec4 clip_rect = clip_rect_ref; const ImVec4 clip_rect = clip_rect_ref;
const float uv_offset = GImGui.IO.PixelCenterOffset;
float x = pos.x; float x = pos.x;
float y = pos.y; float y = pos.y;
for (const char* s = text_begin; s < text_end; s++) for (const char* s = text_begin; s < text_end; s++)
@ -5274,10 +5283,10 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
continue; continue;
} }
const float s1 = (uv_offset + glyph->X) * tex_scale_x; const float s1 = (glyph->X) * tex_scale_x;
const float t1 = (uv_offset + glyph->Y) * tex_scale_y; const float t1 = (glyph->Y) * tex_scale_y;
const float s2 = (uv_offset + glyph->X + glyph->Width) * tex_scale_x; const float s2 = (glyph->X + glyph->Width) * tex_scale_x;
const float t2 = (uv_offset + glyph->Y + glyph->Height) * tex_scale_y; const float t2 = (glyph->Y + glyph->Height) * tex_scale_y;
out_vertices[0].pos = ImVec2(x1, y1); out_vertices[0].pos = ImVec2(x1, y1);
out_vertices[0].uv = ImVec2(s1, t1); out_vertices[0].uv = ImVec2(s1, t1);

2
imgui.h

@ -391,7 +391,7 @@ struct ImGuiIO
ImFont Font; // <auto> // Gets passed to text functions. Typedef ImFont to the type you want (ImBitmapFont* or your own font). ImFont Font; // <auto> // Gets passed to text functions. Typedef ImFont to the type you want (ImBitmapFont* or your own font).
float FontHeight; // <auto> // Default font height, must be the vertical distance between two lines of text, aka == CalcTextSize(" ").y float FontHeight; // <auto> // Default font height, must be the vertical distance between two lines of text, aka == CalcTextSize(" ").y
bool FontAllowScaling; // = false // Set to allow scaling text with CTRL+Wheel. bool FontAllowScaling; // = false // Set to allow scaling text with CTRL+Wheel.
float PixelCenterOffset; // = 0.5f // Set to 0.0f for DirectX <= 9, 0.5f for Direct3D >= 10 and OpenGL. float PixelCenterOffset; // = 0.0f // Try to set to 0.5f or 0.375f if rendering is blurry
// Settings - Rendering function (REQUIRED) // Settings - Rendering function (REQUIRED)
// See example code if you are unsure of how to implement this. // See example code if you are unsure of how to implement this.

Loading…
Cancel
Save