202 lines
6.5 KiB
C++
202 lines
6.5 KiB
C++
internal
|
|
b8 init_imgui(GLFWwindow* window) {
|
|
IMGUI_CHECKVERSION();
|
|
ImGui::CreateContext();
|
|
ImGuiIO& io = ImGui::GetIO(); (void) io;
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
io.IniFilename = nullptr;
|
|
io.LogFilename = nullptr;
|
|
|
|
ImGui::StyleColorsDark();
|
|
|
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
|
ImGui_ImplOpenGL3_Init("#version 330");
|
|
|
|
return true;
|
|
}
|
|
|
|
internal
|
|
void glfw_error_callback(i32 error, const char *description) {
|
|
fprintf(stderr, "GLFW error %d: %s\n", error, description);
|
|
}
|
|
|
|
internal
|
|
void glfw_key_callback(GLFWwindow *window, i32 key, i32 /*scancode*/, i32 action, i32 /*mods*/)
|
|
{
|
|
App_State *app = (App_State *)glfwGetWindowUserPointer(window);
|
|
Input_Key ikey = app->viewer.glfw_key_mapping[key];
|
|
if (ikey == KEY_INVALID)
|
|
return;
|
|
|
|
u8 &state = app->user_input.key_state[ikey];
|
|
switch (action) {
|
|
case GLFW_PRESS:
|
|
if (!(state & KEY_STATE_IS_DOWN))
|
|
state |= KEY_STATE_JUST_PRESSED;
|
|
state |= KEY_STATE_IS_DOWN;
|
|
break;
|
|
|
|
case GLFW_RELEASE:
|
|
if (state & KEY_STATE_IS_DOWN)
|
|
state |= KEY_STATE_JUST_RELEASED;
|
|
state &= ~KEY_STATE_IS_DOWN;
|
|
break;
|
|
|
|
case GLFW_REPEAT:
|
|
state |= KEY_STATE_JUST_PRESSED;
|
|
break;
|
|
|
|
default:;
|
|
}
|
|
}
|
|
|
|
internal
|
|
void glfw_init_key_mapping(Viewer &viewer)
|
|
{
|
|
viewer.glfw_key_mapping[GLFW_KEY_Q] = KEY_Q;
|
|
viewer.glfw_key_mapping[GLFW_KEY_UP] = KEY_UP;
|
|
viewer.glfw_key_mapping[GLFW_KEY_DOWN] = KEY_DOWN;
|
|
viewer.glfw_key_mapping[GLFW_KEY_LEFT] = KEY_LEFT;
|
|
viewer.glfw_key_mapping[GLFW_KEY_RIGHT] = KEY_RIGHT;
|
|
viewer.glfw_key_mapping[GLFW_KEY_LEFT_ALT] = KEY_ALT;
|
|
viewer.glfw_key_mapping[GLFW_KEY_TAB] = KEY_TAB;
|
|
viewer.glfw_key_mapping[GLFW_KEY_LEFT_SHIFT] = KEY_SHIFT;
|
|
viewer.glfw_key_mapping[GLFW_KEY_KP_ADD] = KEY_PLUS;
|
|
viewer.glfw_key_mapping[GLFW_KEY_KP_SUBTRACT] = KEY_MINUS;
|
|
viewer.glfw_key_mapping[GLFW_KEY_ESCAPE] = KEY_ESC;
|
|
}
|
|
|
|
internal
|
|
GLFWwindow *init_glfw(App_State &app, i32 desired_win_width, i32 desired_win_height)
|
|
{
|
|
glfw_init_key_mapping(app.viewer);
|
|
|
|
glfwSetErrorCallback(glfw_error_callback);
|
|
glfwInit();
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
|
glfwWindowHint(GLFW_DECORATED, GLFW_TRUE);
|
|
glfwWindowHint(GLFW_DEPTH_BITS, 32);
|
|
#ifndef NDEBUG
|
|
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true);
|
|
#endif
|
|
|
|
GLFWwindow *window = glfwCreateWindow(
|
|
desired_win_width, desired_win_height,
|
|
"RNTuple Viewer " V_MAJOR "." V_MINOR,
|
|
nullptr,
|
|
nullptr
|
|
);
|
|
|
|
glfwSetWindowUserPointer(window, &app);
|
|
glfwSetKeyCallback(window, glfw_key_callback);
|
|
glfwMakeContextCurrent(window);
|
|
|
|
return window;
|
|
}
|
|
|
|
internal
|
|
void monitor_mouse_btn(GLFWwindow *window, u8 *mouse_btn_state, i32 glfw_btn, Mouse_Button btn)
|
|
{
|
|
u8 *state = &mouse_btn_state[btn];
|
|
if (glfwGetMouseButton(window, glfw_btn) == GLFW_PRESS) {
|
|
if (!(*state & MOUSE_BTN_STATE_IS_DOWN))
|
|
*state |= MOUSE_BTN_STATE_JUST_PRESSED;
|
|
*state |= MOUSE_BTN_STATE_IS_DOWN;
|
|
} else if (glfwGetMouseButton(window, glfw_btn) == GLFW_RELEASE) {
|
|
if (*state & MOUSE_BTN_STATE_IS_DOWN)
|
|
*state |= MOUSE_BTN_STATE_JUST_RELEASED;
|
|
*state &= ~MOUSE_BTN_STATE_IS_DOWN;
|
|
}
|
|
}
|
|
|
|
internal
|
|
void reset_user_input(User_Input &input)
|
|
{
|
|
for (u32 i = 0; i < KEY_COUNT; ++i)
|
|
input.key_state[i] &= ~(KEY_STATE_JUST_PRESSED|KEY_STATE_JUST_RELEASED);
|
|
|
|
for (u32 i = 0; i < MOUSE_BTN_COUNT; ++i)
|
|
input.mouse_btn_state[i] &= ~(MOUSE_BTN_STATE_JUST_PRESSED|MOUSE_BTN_STATE_JUST_RELEASED);
|
|
}
|
|
|
|
internal
|
|
void run_main_loop(GLFWwindow *window, Arena *arena, App_State &app)
|
|
{
|
|
f32 delta_time_ms;
|
|
chr::time_point last_saved_time = chr::high_resolution_clock::now();
|
|
|
|
app.delta_time_accum.max = 100;
|
|
app.delta_time_accum.base = arena_push_array<f32>(arena, app.delta_time_accum.max);
|
|
|
|
while (!app.should_quit) {
|
|
chr::time_point frame_start = chr::high_resolution_clock::now();
|
|
u64 time_since_prev_frame_us = chr::duration_cast<chr::microseconds>(frame_start - last_saved_time).count();
|
|
delta_time_ms = time_since_prev_frame_us * 0.001f;
|
|
last_saved_time = frame_start;
|
|
|
|
reset_user_input(app.user_input);
|
|
|
|
glfwPollEvents();
|
|
|
|
// Update window size
|
|
{
|
|
Window_Data &wdata = app.win_data;
|
|
glfwGetWindowSize(window, &wdata.width, &wdata.height);
|
|
}
|
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
ImGui_ImplGlfw_NewFrame();
|
|
ImGui::NewFrame();
|
|
|
|
// Check if the inspected file changed
|
|
{
|
|
if (file_has_changed(app.inspected_file.inot)) {
|
|
u64 prev_size = app.inspected_file.size;
|
|
app.inspected_file.size = file_size(app.inspected_file.stream);
|
|
int fd = fileno(app.inspected_file.stream);
|
|
os_remap_file(fd, app.inspected_file.mem, prev_size, app.inspected_file.size);
|
|
// reset memory for loaded file data
|
|
arena_pop_to(app.fdata.arena, 0);
|
|
memset(&app.fdata.rndata, 0, sizeof(app.fdata.rndata));
|
|
memset(&app.fdata.tfile_data, 0, sizeof(app.fdata.tfile_data));
|
|
b8 success = get_tfile_data(app.fdata.arena, app.inspected_file, app.walk_tkeys_flags, app.ntpl_name, app.fdata.tfile_data);
|
|
if (success)
|
|
app.fdata.rndata = get_rntuple_data(app.fdata.arena, app.inspected_file, app.fdata.tfile_data, app.extended_info);
|
|
compute_tot_sections_size(app.fdata.tfile_data.sections);
|
|
init_viewer_title(app.viewer, app.fdata, app.inspected_file.name);
|
|
}
|
|
}
|
|
|
|
if ((app.user_input.key_state[KEY_ESC] & KEY_STATE_IS_DOWN) || glfwWindowShouldClose(window)) {
|
|
app.should_quit = true;
|
|
break;
|
|
}
|
|
|
|
b32 focused = glfwGetWindowAttrib(window, GLFW_FOCUSED);
|
|
if (focused) {
|
|
// NOTE: keyboard is updated via the callback because that's the only way to intercept GLFW_REPEAT events
|
|
|
|
// Update mouse
|
|
f64 mposx, mposy;
|
|
glfwGetCursorPos(window, &mposx, &mposy);
|
|
|
|
u8 *mouse_btn_state = app.user_input.mouse_btn_state;
|
|
monitor_mouse_btn(window, mouse_btn_state, GLFW_MOUSE_BUTTON_LEFT, MOUSE_BTN_LEFT);
|
|
monitor_mouse_btn(window, mouse_btn_state, GLFW_MOUSE_BUTTON_RIGHT, MOUSE_BTN_RIGHT);
|
|
|
|
app.user_input.mouse_pos.x = static_cast<i32>(mposx);
|
|
app.user_input.mouse_pos.y = static_cast<i32>(mposy);
|
|
}
|
|
|
|
update_and_render(arena, app, delta_time_ms);
|
|
|
|
ImGui::Render();
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
|
|
glfwSwapBuffers(window);
|
|
}
|
|
}
|