Compare commits

...

10 Commits
v1.01 ... v1.02

5 changed files with 127 additions and 126 deletions

View File

@ -5,7 +5,7 @@ ImGui is a bloat-free graphical user interface library for C++. It is portable,
ImGui is designed to allow programmers to create "content creation" or "debug" tools (as opposed to tools for the average end-user). It favors simplicity and thus lacks certain features normally found in more high-level libraries, such as string localisation. ImGui is designed to allow programmers to create "content creation" or "debug" tools (as opposed to tools for the average end-user). It favors simplicity and thus lacks certain features normally found in more high-level libraries, such as string localisation.
Usage example: After ImGui is setup in your application, you can use it like in this example:
![screenshot of sample code alongside its output with ImGui](/web/code_sample_01.png?raw=true) ![screenshot of sample code alongside its output with ImGui](/web/code_sample_01.png?raw=true)

View File

@ -12,16 +12,15 @@ static LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
static LPDIRECT3DTEXTURE9 g_pTexture = NULL; // Our texture static LPDIRECT3DTEXTURE9 g_pTexture = NULL; // Our texture
struct CUSTOMVERTEX struct CUSTOMVERTEX
{ {
D3DXVECTOR3 position; D3DXVECTOR3 position;
D3DCOLOR color; D3DCOLOR color;
float tu, tv; float tu, tv;
}; };
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structuer)
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;
@ -30,31 +29,13 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
if (total_vtx_count == 0) if (total_vtx_count == 0)
return; return;
ImVector<ImVec4> clip_rect_stack; // Copy and convert all vertices into a single contiguous buffer
clip_rect_stack.push_back(ImVec4(-9999,-9999,+9999,+9999));
// Setup orthographic projection
// Set up world matrix
D3DXMATRIXA16 mat;
D3DXMatrixIdentity(&mat);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &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);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat);
D3DSURFACE_DESC texture_desc;
g_pTexture->GetLevelDesc(0, &texture_desc);
// Fill the vertex buffer
CUSTOMVERTEX* vtx_dst; CUSTOMVERTEX* vtx_dst;
if (g_pVB->Lock(0, total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) if (g_pVB->Lock(0, total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
return; return;
for (int n = 0; n < cmd_lists_count; n++) for (int n = 0; n < cmd_lists_count; n++)
{ {
const ImDrawList* cmd_list = cmd_lists[n]; const ImDrawList* cmd_list = cmd_lists[n];
if (cmd_list->commands.empty() || cmd_list->vtx_buffer.empty())
continue;
const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0]; const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0];
for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++) for (size_t i = 0; i < cmd_list->vtx_buffer.size(); i++)
{ {
@ -73,11 +54,10 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) ); g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
// Setup render state: alpha-blending enabled, no face culling, no depth testing // Setup render state: alpha-blending, no face culling, no depth testing
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false ); g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false );
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false ); g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false );
g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true ); g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );
g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false ); g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false );
@ -94,42 +74,46 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
int vtx_consumed = 0; // offset in vertex buffer. each command consume ImDrawCmd::vtx_count of those // Setup orthographic projection matrix
bool clip_rect_dirty = true; D3DXMATRIXA16 mat;
D3DXMatrixIdentity(&mat);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &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);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat);
// Render command lists
int vtx_offset = 0;
for (int n = 0; n < cmd_lists_count; n++) for (int n = 0; n < cmd_lists_count; n++)
{ {
// Setup stack of clipping rectangles
int clip_rect_buf_offset = 0;
ImVector<ImVec4> clip_rect_stack;
clip_rect_stack.push_back(ImVec4(-9999,-9999,+9999,+9999));
// Render command list
const ImDrawList* cmd_list = cmd_lists[n]; const ImDrawList* cmd_list = cmd_lists[n];
if (cmd_list->commands.empty() || cmd_list->vtx_buffer.empty()) const ImDrawCmd* pcmd_end = cmd_list->commands.end();
continue; for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
const ImDrawCmd* pcmd = &cmd_list->commands.front();
const ImDrawCmd* pcmd_end = &cmd_list->commands.back();
int clip_rect_buf_consumed = 0; // offset in cmd_list->clip_rect_buffer. each PushClipRect command consume 1 of those.
while (pcmd <= pcmd_end)
{ {
const ImDrawCmd& cmd = *pcmd++; switch (pcmd->cmd_type)
switch (cmd.cmd_type)
{ {
case ImDrawCmdType_DrawTriangleList: case ImDrawCmdType_DrawTriangleList:
if (clip_rect_dirty)
{ {
const ImVec4& clip_rect = clip_rect_stack.back(); const ImVec4& clip_rect = clip_rect_stack.back();
const RECT r = { (LONG)clip_rect.x, (LONG)clip_rect.y, (LONG)clip_rect.z, (LONG)clip_rect.w }; const RECT r = { (LONG)clip_rect.x, (LONG)clip_rect.y, (LONG)clip_rect.z, (LONG)clip_rect.w };
g_pd3dDevice->SetScissorRect(&r); g_pd3dDevice->SetScissorRect(&r);
clip_rect_dirty = false; g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
vtx_offset += pcmd->vtx_count;
} }
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_consumed, cmd.vtx_count/3);
vtx_consumed += cmd.vtx_count;
break; break;
case ImDrawCmdType_PushClipRect: case ImDrawCmdType_PushClipRect:
clip_rect_stack.push_back(cmd_list->clip_rect_buffer[clip_rect_buf_consumed++]); clip_rect_stack.push_back(cmd_list->clip_rect_buffer[clip_rect_buf_offset++]);
clip_rect_dirty = true;
break; break;
case ImDrawCmdType_PopClipRect: case ImDrawCmdType_PopClipRect:
clip_rect_stack.pop_back(); clip_rect_stack.pop_back();
clip_rect_dirty = true;
break; break;
} }
} }
@ -290,7 +274,6 @@ void InitImGui()
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn; io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn; io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
// Create the vertex buffer // Create the vertex buffer
if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
{ {
@ -396,13 +379,15 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int)
ImGui::End(); ImGui::End();
} }
// 3) Render // 3) Rendering
// Clear frame buffer
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false); g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(204, 153, 153), 1.0f, 0); // Clear the backbuffer and the zbuffer g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(204, 153, 153), 1.0f, 0);
if (g_pd3dDevice->BeginScene() >= 0) if (g_pd3dDevice->BeginScene() >= 0)
{ {
// Render ImGui
ImGui::Render(); ImGui::Render();
g_pd3dDevice->EndScene(); g_pd3dDevice->EndScene();
} }

View File

@ -15,9 +15,8 @@ static GLuint vertexShader;
static GLuint fragmentShader; static GLuint fragmentShader;
static GLuint shaderProgram; static GLuint shaderProgram;
static GLuint fontTex; static GLuint fontTex;
static GLint uniMVP;
static GLint uniClipRect;
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structuer)
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;
@ -26,92 +25,83 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
if (total_vtx_count == 0) if (total_vtx_count == 0)
return; return;
int read_pos_clip_rect_buf = 0; // offset in 'clip_rect_buffer'. each PushClipRect command consume 1 of those. // Copy all vertices into a single contiguous GL buffer
ImVector<ImVec4> clip_rect_stack;
clip_rect_stack.push_back(ImVec4(-9999,-9999,+9999,+9999));
// Setup orthographic projection
const float L = 0.0f;
const float R = ImGui::GetIO().DisplaySize.x;
const float B = ImGui::GetIO().DisplaySize.y;
const float T = 0.0f;
const float mvp[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ -(R+L)/(R-L), -(T+B)/(T-B), 0.0f, 1.0f },
};
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindVertexArray(vao); glBindVertexArray(vao);
glBufferData(GL_ARRAY_BUFFER, total_vtx_count * sizeof(ImDrawVert), NULL, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, total_vtx_count * sizeof(ImDrawVert), NULL, GL_STREAM_DRAW);
unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
if (!buffer_data) if (!buffer_data)
return; return;
int vtx_consumed = 0;
for (int n = 0; n < cmd_lists_count; n++) for (int n = 0; n < cmd_lists_count; n++)
{ {
const ImDrawList* cmd_list = cmd_lists[n]; const ImDrawList* cmd_list = cmd_lists[n];
if (!cmd_list->vtx_buffer.empty())
{
memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert)); memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert); buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert);
vtx_consumed += cmd_list->vtx_buffer.size();
}
} }
glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ARRAY_BUFFER);
glUseProgram(shaderProgram);
glUniformMatrix4fv(uniMVP, 1, GL_FALSE, &mvp[0][0]);
// Setup render state: alpha-blending enabled, no face culling, no depth testing // Setup render state: alpha-blending enabled, no face culling, no depth testing
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
// Bind texture and enable our shader
glBindTexture(GL_TEXTURE_2D, fontTex); glBindTexture(GL_TEXTURE_2D, fontTex);
glUseProgram(shaderProgram);
const GLint uniMVP = glGetUniformLocation(shaderProgram, "MVP");
const GLint uniClipRect = glGetUniformLocation(shaderProgram, "ClipRect");
vtx_consumed = 0; // offset in vertex buffer. each command consume ImDrawCmd::vtx_count of those // Setup orthographic projection matrix
bool clip_rect_dirty = true; const float width = ImGui::GetIO().DisplaySize.x;
const float height = ImGui::GetIO().DisplaySize.y;
const float mvp[4][4] =
{
{ 2.0f/width, 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/-height, 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ -1.0f, 1.0f, 0.0f, 1.0f },
};
glUniformMatrix4fv(uniMVP, 1, GL_FALSE, &mvp[0][0]);
// Render command lists
int vtx_offset = 0;
for (int n = 0; n < cmd_lists_count; n++) for (int n = 0; n < cmd_lists_count; n++)
{ {
// Setup stack of clipping rectangles
int clip_rect_buf_offset = 0;
ImVector<ImVec4> clip_rect_stack;
clip_rect_stack.push_back(ImVec4(-9999,-9999,+9999,+9999));
// Render command list
const ImDrawList* cmd_list = cmd_lists[n]; const ImDrawList* cmd_list = cmd_lists[n];
if (cmd_list->commands.empty() || cmd_list->vtx_buffer.empty()) const ImDrawCmd* pcmd_end = cmd_list->commands.end();
continue; for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
const ImDrawCmd* pcmd = &cmd_list->commands.front();
const ImDrawCmd* pcmd_end = &cmd_list->commands.back();
int clip_rect_buf_consumed = 0; // offset in cmd_list->clip_rect_buffer. each PushClipRect command consume 1 of those.
while (pcmd <= pcmd_end)
{ {
const ImDrawCmd& cmd = *pcmd++; switch (pcmd->cmd_type)
switch (cmd.cmd_type)
{ {
case ImDrawCmdType_DrawTriangleList: case ImDrawCmdType_DrawTriangleList:
if (clip_rect_dirty)
{
glUniform4fv(uniClipRect, 1, (float*)&clip_rect_stack.back()); glUniform4fv(uniClipRect, 1, (float*)&clip_rect_stack.back());
clip_rect_dirty = false; glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
} vtx_offset += pcmd->vtx_count;
glDrawArrays(GL_TRIANGLES, vtx_consumed, cmd.vtx_count);
vtx_consumed += cmd.vtx_count;
break; break;
case ImDrawCmdType_PushClipRect: case ImDrawCmdType_PushClipRect:
clip_rect_stack.push_back(cmd_list->clip_rect_buffer[clip_rect_buf_consumed++]); clip_rect_stack.push_back(cmd_list->clip_rect_buffer[clip_rect_buf_offset++]);
clip_rect_dirty = true;
break; break;
case ImDrawCmdType_PopClipRect: case ImDrawCmdType_PopClipRect:
clip_rect_stack.pop_back(); clip_rect_stack.pop_back();
clip_rect_dirty = true;
break; break;
} }
} }
} }
// Cleanup GL state
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
} }
static const char* ImImpl_GetClipboardTextFn() static const char* ImImpl_GetClipboardTextFn()
@ -124,6 +114,7 @@ static void ImImpl_SetClipboardTextFn(const char* text, const char* text_end)
if (!text_end) if (!text_end)
text_end = text + strlen(text); text_end = text + strlen(text);
// Add a zero-terminator because glfw function doesn't take a size
char* buf = (char*)malloc(text_end - text + 1); char* buf = (char*)malloc(text_end - text + 1);
memcpy(buf, text, text_end-text); memcpy(buf, text, text_end-text);
buf[text_end-text] = '\0'; buf[text_end-text] = '\0';
@ -132,7 +123,6 @@ static void ImImpl_SetClipboardTextFn(const char* text, const char* text_end)
} }
// Shader sources // Shader sources
// FIXME-OPT: clip at vertex level
const GLchar* vertexSource = const GLchar* vertexSource =
"#version 150 core\n" "#version 150 core\n"
"uniform mat4 MVP;" "uniform mat4 MVP;"
@ -164,6 +154,7 @@ const GLchar* fragmentSource =
" o_col.w *= (step(ClipRect.x,pixel_pos.x) * step(ClipRect.y,pixel_pos.y) * step(pixel_pos.x,ClipRect.z) * step(pixel_pos.y,ClipRect.w));" // Clipping: branch-less, set alpha 0.0f " o_col.w *= (step(ClipRect.x,pixel_pos.x) * step(ClipRect.y,pixel_pos.y) * step(pixel_pos.x,ClipRect.z) * step(pixel_pos.y,ClipRect.w));" // Clipping: branch-less, set alpha 0.0f
"}"; "}";
// GLFW callbacks to get events
static void glfw_error_callback(int error, const char* description) static void glfw_error_callback(int error, const char* description)
{ {
fputs(description, stderr); fputs(description, stderr);
@ -200,13 +191,13 @@ void InitGL()
if (!glfwInit()) if (!glfwInit())
exit(1); exit(1);
//glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_REFRESH_RATE, 60); glfwWindowHint(GLFW_REFRESH_RATE, 60);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(1280, 720, "ImGui OpenGL example", nullptr, nullptr); window = glfwCreateWindow(1280, 720, "ImGui OpenGL example", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, glfw_key_callback); glfwSetKeyCallback(window, glfw_key_callback);
@ -216,8 +207,10 @@ void InitGL()
glewExperimental = GL_TRUE; glewExperimental = GL_TRUE;
glewInit(); glewInit();
GLenum err = GL_NO_ERROR; // After calling glewInit() our GL error state may be GL_INVALID_ENUM
err = glGetError(); IM_ASSERT(err == GL_NO_ERROR); const GLenum err = glGetError();
(void)err;
IM_ASSERT(err == GL_NO_ERROR || err == GL_INVALID_ENUM);
} }
void InitImGui() void InitImGui()
@ -251,7 +244,6 @@ void InitImGui()
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn; io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn; io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
// Setup graphics backend // Setup graphics backend
GLint status = GL_TRUE; GLint status = GL_TRUE;
GLenum err = GL_NO_ERROR; GLenum err = GL_NO_ERROR;
@ -286,9 +278,6 @@ void InitImGui()
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status);
IM_ASSERT(status == GL_TRUE); IM_ASSERT(status == GL_TRUE);
uniMVP = glGetUniformLocation(shaderProgram, "MVP");
uniClipRect = glGetUniformLocation(shaderProgram, "ClipRect");
// Create Vertex Buffer Objects & Vertex Array Objects // Create Vertex Buffer Objects & Vertex Array Objects
glGenBuffers(1, &vbo); glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo);
@ -308,6 +297,9 @@ void InitImGui()
glEnableVertexAttribArray(colAttrib); glEnableVertexAttribArray(colAttrib);
err = glGetError(); IM_ASSERT(err == GL_NO_ERROR); err = glGetError(); IM_ASSERT(err == GL_NO_ERROR);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Load font texture // Load font texture
glGenTextures(1, &fontTex); glGenTextures(1, &fontTex);
glBindTexture(GL_TEXTURE_2D, fontTex); glBindTexture(GL_TEXTURE_2D, fontTex);
@ -394,7 +386,7 @@ int main(int argc, char** argv)
ImGui::End(); ImGui::End();
} }
// 3) Render // 3) Rendering
glClearColor(0.8f, 0.6f, 0.6f, 1.0f); glClearColor(0.8f, 0.6f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
ImGui::Render(); ImGui::Render();
@ -403,6 +395,5 @@ int main(int argc, char** argv)
} }
Shutdown(); Shutdown();
return 0; return 0;
} }

View File

@ -158,7 +158,6 @@
#include "imgui.h" #include "imgui.h"
#include <ctype.h> // toupper #include <ctype.h> // toupper
#include <limits.h> // INT_MAX
#include <math.h> // sqrt #include <math.h> // sqrt
#include <stdint.h> // intptr_t #include <stdint.h> // intptr_t
#include <stdio.h> // vsnprintf #include <stdio.h> // vsnprintf
@ -227,6 +226,7 @@ ImGuiStyle::ImGuiStyle()
Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f); Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f);
Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f); Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f);
Colors[ImGuiCol_CheckHovered] = ImVec4(0.60f, 0.40f, 0.40f, 0.45f);
Colors[ImGuiCol_CheckActive] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); Colors[ImGuiCol_CheckActive] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f); Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
@ -292,6 +292,12 @@ void ImGuiIO::AddInputCharacter(char c)
#undef PI #undef PI
const float PI = 3.14159265358979323846f; const float PI = 3.14159265358979323846f;
#ifdef INT_MAX
#define IM_INT_MAX INT_MAX
#else
#define IM_INT_MAX 2147483647
#endif
// Math bits // Math bits
// We are keeping those static in the .cpp file so as not to leak them outside, in the case the user has implicit cast operators between ImVec2 and its own types. // We are keeping those static in the .cpp file so as not to leak them outside, in the case the user has implicit cast operators between ImVec2 and its own types.
static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); }
@ -688,6 +694,7 @@ public:
static ImGuiWindow* GetCurrentWindow() static ImGuiWindow* GetCurrentWindow()
{ {
IM_ASSERT(GImGui.CurrentWindow != NULL); // ImGui::NewFrame() hasn't been called yet?
GImGui.CurrentWindow->Accessed = true; GImGui.CurrentWindow->Accessed = true;
return GImGui.CurrentWindow; return GImGui.CurrentWindow;
} }
@ -907,8 +914,8 @@ ImGuiWindow::ImGuiWindow(const char* name, ImVec2 default_pos, ImVec2 default_si
AutoFitFrames = 3; AutoFitFrames = 3;
FocusIdxCounter = -1; FocusIdxCounter = -1;
FocusIdxRequestCurrent = INT_MAX; FocusIdxRequestCurrent = IM_INT_MAX;
FocusIdxRequestNext = INT_MAX; FocusIdxRequestNext = IM_INT_MAX;
DrawList = new ImDrawList(); DrawList = new ImDrawList();
} }
@ -949,7 +956,7 @@ bool ImGuiWindow::FocusItemRegister(bool is_active, int* out_idx)
return false; return false;
// Process input at this point: TAB, Shift-TAB switch focus // Process input at this point: TAB, Shift-TAB switch focus
if (FocusIdxRequestNext == INT_MAX && is_active && ImGui::IsKeyPressedMap(ImGuiKey_Tab)) if (FocusIdxRequestNext == IM_INT_MAX && is_active && ImGui::IsKeyPressedMap(ImGuiKey_Tab))
{ {
// Modulo on index will be applied at the end of frame once we've got the total counter of items. // Modulo on index will be applied at the end of frame once we've got the total counter of items.
FocusIdxRequestNext = FocusIdxCounter + (g.IO.KeyShift ? -1 : +1); FocusIdxRequestNext = FocusIdxCounter + (g.IO.KeyShift ? -1 : +1);
@ -1826,9 +1833,9 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
window->ItemWidthDefault = (float)(int)(window->Size.x > 0.0f ? window->Size.x * 0.65f : 250.0f); window->ItemWidthDefault = (float)(int)(window->Size.x > 0.0f ? window->Size.x * 0.65f : 250.0f);
// Prepare for focus requests // Prepare for focus requests
if (window->FocusIdxRequestNext == INT_MAX || window->FocusIdxCounter == -1) if (window->FocusIdxRequestNext == IM_INT_MAX || window->FocusIdxCounter == -1)
{ {
window->FocusIdxRequestCurrent = INT_MAX; window->FocusIdxRequestCurrent = IM_INT_MAX;
} }
else else
{ {
@ -1836,7 +1843,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
window->FocusIdxRequestCurrent = (window->FocusIdxRequestNext + mod) % mod; window->FocusIdxRequestCurrent = (window->FocusIdxRequestNext + mod) % mod;
} }
window->FocusIdxCounter = -1; window->FocusIdxCounter = -1;
window->FocusIdxRequestNext = INT_MAX; window->FocusIdxRequestNext = IM_INT_MAX;
ImGuiAabb title_bar_aabb = window->TitleBarAabb(); ImGuiAabb title_bar_aabb = window->TitleBarAabb();
@ -2117,6 +2124,12 @@ void PopItemWidth()
window->DC.ItemWidth.pop_back(); window->DC.ItemWidth.pop_back();
} }
float GetItemWidth()
{
ImGuiWindow* window = GetCurrentWindow();
return window->DC.ItemWidth.back();
}
void PushAllowKeyboardFocus(bool allow_keyboard_focus) void PushAllowKeyboardFocus(bool allow_keyboard_focus)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -2168,6 +2181,7 @@ const char* GetStyleColorName(ImGuiCol idx)
case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
case ImGuiCol_ComboBg: return "ComboBg"; case ImGuiCol_ComboBg: return "ComboBg";
case ImGuiCol_CheckHovered: return "CheckHovered";
case ImGuiCol_CheckActive: return "CheckActive"; case ImGuiCol_CheckActive: return "CheckActive";
case ImGuiCol_SliderGrab: return "SliderGrab"; case ImGuiCol_SliderGrab: return "SliderGrab";
case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
@ -3300,13 +3314,12 @@ void Checkbox(const char* label, bool* v)
const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + text_size); const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + text_size);
ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight())); ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()));
const ImGuiAabb total_bb(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
if (ClipAdvance(check_bb)) if (ClipAdvance(total_bb))
return; return;
RenderFrame(check_bb.Min, check_bb.Max, window->Color(ImGuiCol_FrameBg)); const bool hovered = (g.HoveredWindow == window) && (g.HoveredId == 0) && IsMouseHoveringBox(total_bb);
const bool hovered = (g.HoveredWindow == window) && (g.HoveredId == 0) && IsMouseHoveringBox(check_bb);
const bool pressed = hovered && g.IO.MouseClicked[0]; const bool pressed = hovered && g.IO.MouseClicked[0];
if (hovered) if (hovered)
g.HoveredId = id; g.HoveredId = id;
@ -3316,6 +3329,7 @@ void Checkbox(const char* label, bool* v)
g.ActiveId = 0; // Clear focus g.ActiveId = 0; // Clear focus
} }
RenderFrame(check_bb.Min, check_bb.Max, window->Color(hovered ? ImGuiCol_CheckHovered : ImGuiCol_FrameBg));
if (*v) if (*v)
{ {
window->DrawList->AddRectFilled(check_bb.Min+ImVec2(4,4), check_bb.Max-ImVec2(4,4), window->Color(ImGuiCol_CheckActive)); window->DrawList->AddRectFilled(check_bb.Min+ImVec2(4,4), check_bb.Max-ImVec2(4,4), window->Color(ImGuiCol_CheckActive));
@ -3354,8 +3368,9 @@ bool RadioButton(const char* label, bool active)
const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + text_size); const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + text_size);
ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight())); ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()));
const ImGuiAabb total_bb(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
if (ClipAdvance(check_bb)) if (ClipAdvance(total_bb))
return false; return false;
ImVec2 center = check_bb.GetCenter(); ImVec2 center = check_bb.GetCenter();
@ -3363,12 +3378,12 @@ bool RadioButton(const char* label, bool active)
center.y = (float)(int)center.y + 0.5f; center.y = (float)(int)center.y + 0.5f;
const float radius = check_bb.GetHeight() * 0.5f; const float radius = check_bb.GetHeight() * 0.5f;
const bool hovered = (g.HoveredWindow == window) && (g.HoveredId == 0) && IsMouseHoveringBox(check_bb); const bool hovered = (g.HoveredWindow == window) && (g.HoveredId == 0) && IsMouseHoveringBox(total_bb);
const bool pressed = hovered && g.IO.MouseClicked[0]; const bool pressed = hovered && g.IO.MouseClicked[0];
if (hovered) if (hovered)
g.HoveredId = id; g.HoveredId = id;
window->DrawList->AddCircleFilled(center, radius, window->Color(ImGuiCol_FrameBg), 16); window->DrawList->AddCircleFilled(center, radius, window->Color(hovered ? ImGuiCol_CheckHovered : ImGuiCol_FrameBg), 16);
if (active) if (active)
window->DrawList->AddCircleFilled(center, radius-2, window->Color(ImGuiCol_CheckActive), 16); window->DrawList->AddCircleFilled(center, radius-2, window->Color(ImGuiCol_CheckActive), 16);
@ -5135,11 +5150,17 @@ void ShowStyleEditor(ImGuiStyle* ref)
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton("HEX", &edit_mode, ImGuiColorEditMode_HEX); ImGui::RadioButton("HEX", &edit_mode, ImGuiColorEditMode_HEX);
static ImGuiTextFilter filter;
filter.Draw("Filter colors", 200);
ImGui::ColorEditMode(edit_mode); ImGui::ColorEditMode(edit_mode);
for (size_t i = 0; i < ImGuiCol_COUNT; i++) for (size_t i = 0; i < ImGuiCol_COUNT; i++)
{ {
const char* name = GetStyleColorName(i);
if (!filter.PassFilter(name))
continue;
ImGui::PushID(i); ImGui::PushID(i);
ImGui::ColorEdit4(GetStyleColorName(i), (float*)&style.Colors[i], true); ImGui::ColorEdit4(name, (float*)&style.Colors[i], true);
if (memcmp(&style.Colors[i], (ref ? &ref->Colors[i] : &def.Colors[i]), sizeof(ImVec4)) != 0) if (memcmp(&style.Colors[i], (ref ? &ref->Colors[i] : &def.Colors[i]), sizeof(ImVec4)) != 0)
{ {
ImGui::SameLine(); if (ImGui::Button("Revert")) style.Colors[i] = ref ? ref->Colors[i] : def.Colors[i]; ImGui::SameLine(); if (ImGui::Button("Revert")) style.Colors[i] = ref ? ref->Colors[i] : def.Colors[i];

View File

@ -145,6 +145,7 @@ namespace ImGui
void SetTreeStateStorage(ImGuiStorage* tree); void SetTreeStateStorage(ImGuiStorage* tree);
void PushItemWidth(float item_width); void PushItemWidth(float item_width);
void PopItemWidth(); void PopItemWidth();
float GetItemWidth();
void PushAllowKeyboardFocus(bool v); void PushAllowKeyboardFocus(bool v);
void PopAllowKeyboardFocus(); void PopAllowKeyboardFocus();
void PushStyleColor(ImGuiCol idx, ImVec4 col); void PushStyleColor(ImGuiCol idx, ImVec4 col);
@ -302,6 +303,7 @@ enum ImGuiCol_
ImGuiCol_ScrollbarGrabHovered, ImGuiCol_ScrollbarGrabHovered,
ImGuiCol_ScrollbarGrabActive, ImGuiCol_ScrollbarGrabActive,
ImGuiCol_ComboBg, ImGuiCol_ComboBg,
ImGuiCol_CheckHovered,
ImGuiCol_CheckActive, ImGuiCol_CheckActive,
ImGuiCol_SliderGrab, ImGuiCol_SliderGrab,
ImGuiCol_SliderGrabActive, ImGuiCol_SliderGrabActive,
@ -389,10 +391,13 @@ struct ImGuiIO
bool KeysDown[512]; // Keyboard keys that are pressed (in whatever order user naturally has access to keyboard data) bool KeysDown[512]; // Keyboard keys that are pressed (in whatever order user naturally has access to keyboard data)
char InputCharacters[16]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. char InputCharacters[16]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper.
// Output - Retrieve after calling NewFrame(), you can use them to discard inputs for the rest of your application // Output - Retrieve after calling NewFrame(), you can use them to discard inputs or hide them from the rest of your application
bool WantCaptureMouse; // ImGui is using your mouse input (= window is being hovered or widget is active). bool WantCaptureMouse; // ImGui is using your mouse input (= window is being hovered or widget is active).
bool WantCaptureKeyboard; // imGui is using your keyboard input (= widget is active). bool WantCaptureKeyboard; // imGui is using your keyboard input (= widget is active).
// Function
void AddInputCharacter(char c); // Helper to add a new character into InputCharacters[]
// [Internal] ImGui will maintain those fields for you // [Internal] ImGui will maintain those fields for you
ImVec2 MousePosPrev; ImVec2 MousePosPrev;
ImVec2 MouseDelta; ImVec2 MouseDelta;
@ -404,7 +409,6 @@ struct ImGuiIO
float KeysDownTime[512]; float KeysDownTime[512];
ImGuiIO(); ImGuiIO();
void AddInputCharacter(char c); // Helper to add a new character into InputCharacters[]
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------