diff options
author | chai <chaifix@163.com> | 2021-12-13 00:07:19 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-12-13 00:07:19 +0800 |
commit | 60cbbdec07ab7a5636eac5b3c024ae44e937f4d4 (patch) | |
tree | b2c7b0a868f18159dbc43d8954e1bd7668549a88 /Client/ThirdParty/Box2D/testbed/main.cpp |
+init
Diffstat (limited to 'Client/ThirdParty/Box2D/testbed/main.cpp')
-rw-r--r-- | Client/ThirdParty/Box2D/testbed/main.cpp | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/Client/ThirdParty/Box2D/testbed/main.cpp b/Client/ThirdParty/Box2D/testbed/main.cpp new file mode 100644 index 0000000..c5969e3 --- /dev/null +++ b/Client/ThirdParty/Box2D/testbed/main.cpp @@ -0,0 +1,651 @@ +// MIT License + +// Copyright (c) 2019 Erin Catto + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#define _CRT_SECURE_NO_WARNINGS +#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 1 + +#include "imgui/imgui.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_opengl3.h" +#include "draw.h" +#include "settings.h" +#include "test.h" + +#include <algorithm> +#include <stdio.h> +#include <thread> +#include <chrono> + +#if defined(_WIN32) +#include <crtdbg.h> +#endif + +GLFWwindow* g_mainWindow = nullptr; +static int32 s_testSelection = 0; +static Test* s_test = nullptr; +static Settings s_settings; +static bool s_rightMouseDown = false; +static b2Vec2 s_clickPointWS = b2Vec2_zero; + +void glfwErrorCallback(int error, const char* description) +{ + fprintf(stderr, "GLFW error occured. Code: %d. Description: %s\n", error, description); +} + +static inline bool CompareTests(const TestEntry& a, const TestEntry& b) +{ + int result = strcmp(a.category, b.category); + if (result == 0) + { + result = strcmp(a.name, b.name); + } + + return result < 0; +} + +static void SortTests() +{ + std::sort(g_testEntries, g_testEntries + g_testCount, CompareTests); +} + +static void CreateUI(GLFWwindow* window, const char* glslVersion = NULL) +{ + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + bool success; + success = ImGui_ImplGlfw_InitForOpenGL(window, false); + if (success == false) + { + printf("ImGui_ImplGlfw_InitForOpenGL failed\n"); + assert(false); + } + + success = ImGui_ImplOpenGL3_Init(glslVersion); + if (success == false) + { + printf("ImGui_ImplOpenGL3_Init failed\n"); + assert(false); + } + + // Search for font file + const char* fontPath1 = "data/droid_sans.ttf"; + const char* fontPath2 = "../data/droid_sans.ttf"; + const char* fontPath = nullptr; + FILE* file1 = fopen(fontPath1, "rb"); + FILE* file2 = fopen(fontPath2, "rb"); + if (file1) + { + fontPath = fontPath1; + fclose(file1); + } + + if (file2) + { + fontPath = fontPath2; + fclose(file2); + } + + if (fontPath) + { + ImGui::GetIO().Fonts->AddFontFromFileTTF(fontPath, 13.0f); + } +} + +static void ResizeWindowCallback(GLFWwindow*, int width, int height) +{ + g_camera.m_width = width; + g_camera.m_height = height; + s_settings.m_windowWidth = width; + s_settings.m_windowHeight = height; +} + +static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods); + if (ImGui::GetIO().WantCaptureKeyboard) + { + return; + } + + if (action == GLFW_PRESS) + { + switch (key) + { + case GLFW_KEY_ESCAPE: + // Quit + glfwSetWindowShouldClose(g_mainWindow, GL_TRUE); + break; + + case GLFW_KEY_LEFT: + // Pan left + if (mods == GLFW_MOD_CONTROL) + { + b2Vec2 newOrigin(2.0f, 0.0f); + s_test->ShiftOrigin(newOrigin); + } + else + { + g_camera.m_center.x -= 0.5f; + } + break; + + case GLFW_KEY_RIGHT: + // Pan right + if (mods == GLFW_MOD_CONTROL) + { + b2Vec2 newOrigin(-2.0f, 0.0f); + s_test->ShiftOrigin(newOrigin); + } + else + { + g_camera.m_center.x += 0.5f; + } + break; + + case GLFW_KEY_DOWN: + // Pan down + if (mods == GLFW_MOD_CONTROL) + { + b2Vec2 newOrigin(0.0f, 2.0f); + s_test->ShiftOrigin(newOrigin); + } + else + { + g_camera.m_center.y -= 0.5f; + } + break; + + case GLFW_KEY_UP: + // Pan up + if (mods == GLFW_MOD_CONTROL) + { + b2Vec2 newOrigin(0.0f, -2.0f); + s_test->ShiftOrigin(newOrigin); + } + else + { + g_camera.m_center.y += 0.5f; + } + break; + + case GLFW_KEY_HOME: + // Reset view + g_camera.m_zoom = 1.0f; + g_camera.m_center.Set(0.0f, 20.0f); + break; + + case GLFW_KEY_Z: + // Zoom out + g_camera.m_zoom = b2Min(1.1f * g_camera.m_zoom, 20.0f); + break; + + case GLFW_KEY_X: + // Zoom in + g_camera.m_zoom = b2Max(0.9f * g_camera.m_zoom, 0.02f); + break; + + case GLFW_KEY_R: + // Reset test + delete s_test; + s_test = g_testEntries[s_settings.m_testIndex].createFcn(); + break; + + case GLFW_KEY_SPACE: + // Launch a bomb. + if (s_test) + { + s_test->LaunchBomb(); + } + break; + + case GLFW_KEY_O: + s_settings.m_singleStep = true; + break; + + case GLFW_KEY_P: + s_settings.m_pause = !s_settings.m_pause; + break; + + case GLFW_KEY_LEFT_BRACKET: + // Switch to previous test + --s_testSelection; + if (s_testSelection < 0) + { + s_testSelection = g_testCount - 1; + } + break; + + case GLFW_KEY_RIGHT_BRACKET: + // Switch to next test + ++s_testSelection; + if (s_testSelection == g_testCount) + { + s_testSelection = 0; + } + break; + + case GLFW_KEY_TAB: + g_debugDraw.m_showUI = !g_debugDraw.m_showUI; + + default: + if (s_test) + { + s_test->Keyboard(key); + } + } + } + else if (action == GLFW_RELEASE) + { + s_test->KeyboardUp(key); + } + // else GLFW_REPEAT +} + +static void CharCallback(GLFWwindow* window, unsigned int c) +{ + ImGui_ImplGlfw_CharCallback(window, c); +} + +static void MouseButtonCallback(GLFWwindow* window, int32 button, int32 action, int32 mods) +{ + ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods); + + double xd, yd; + glfwGetCursorPos(g_mainWindow, &xd, &yd); + b2Vec2 ps((float)xd, (float)yd); + + // Use the mouse to move things around. + if (button == GLFW_MOUSE_BUTTON_1) + { + //<##> + //ps.Set(0, 0); + b2Vec2 pw = g_camera.ConvertScreenToWorld(ps); + if (action == GLFW_PRESS) + { + if (mods == GLFW_MOD_SHIFT) + { + s_test->ShiftMouseDown(pw); + } + else + { + s_test->MouseDown(pw); + } + } + + if (action == GLFW_RELEASE) + { + s_test->MouseUp(pw); + } + } + else if (button == GLFW_MOUSE_BUTTON_2) + { + if (action == GLFW_PRESS) + { + s_clickPointWS = g_camera.ConvertScreenToWorld(ps); + s_rightMouseDown = true; + } + + if (action == GLFW_RELEASE) + { + s_rightMouseDown = false; + } + } +} + +static void MouseMotionCallback(GLFWwindow*, double xd, double yd) +{ + b2Vec2 ps((float)xd, (float)yd); + + b2Vec2 pw = g_camera.ConvertScreenToWorld(ps); + s_test->MouseMove(pw); + + if (s_rightMouseDown) + { + b2Vec2 diff = pw - s_clickPointWS; + g_camera.m_center.x -= diff.x; + g_camera.m_center.y -= diff.y; + s_clickPointWS = g_camera.ConvertScreenToWorld(ps); + } +} + +static void ScrollCallback(GLFWwindow* window, double dx, double dy) +{ + ImGui_ImplGlfw_ScrollCallback(window, dx, dy); + if (ImGui::GetIO().WantCaptureMouse) + { + return; + } + + if (dy > 0) + { + g_camera.m_zoom /= 1.1f; + } + else + { + g_camera.m_zoom *= 1.1f; + } +} + +static void RestartTest() +{ + delete s_test; + s_test = g_testEntries[s_settings.m_testIndex].createFcn(); +} + +static void UpdateUI() +{ + int menuWidth = 180; + if (g_debugDraw.m_showUI) + { + ImGui::SetNextWindowPos(ImVec2((float)g_camera.m_width - menuWidth - 10, 10)); + ImGui::SetNextWindowSize(ImVec2((float)menuWidth, (float)g_camera.m_height - 20)); + + ImGui::Begin("Tools", &g_debugDraw.m_showUI, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + if (ImGui::BeginTabBar("ControlTabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Controls")) + { + ImGui::SliderInt("Vel Iters", &s_settings.m_velocityIterations, 0, 50); + ImGui::SliderInt("Pos Iters", &s_settings.m_positionIterations, 0, 50); + ImGui::SliderFloat("Hertz", &s_settings.m_hertz, 5.0f, 120.0f, "%.0f hz"); + + ImGui::Separator(); + + ImGui::Checkbox("Sleep", &s_settings.m_enableSleep); + ImGui::Checkbox("Warm Starting", &s_settings.m_enableWarmStarting); + ImGui::Checkbox("Time of Impact", &s_settings.m_enableContinuous); + ImGui::Checkbox("Sub-Stepping", &s_settings.m_enableSubStepping); + + ImGui::Separator(); + + ImGui::Checkbox("Shapes", &s_settings.m_drawShapes); + ImGui::Checkbox("Joints", &s_settings.m_drawJoints); + ImGui::Checkbox("AABBs", &s_settings.m_drawAABBs); + ImGui::Checkbox("Contact Points", &s_settings.m_drawContactPoints); + ImGui::Checkbox("Contact Normals", &s_settings.m_drawContactNormals); + ImGui::Checkbox("Contact Impulses", &s_settings.m_drawContactImpulse); + ImGui::Checkbox("Friction Impulses", &s_settings.m_drawFrictionImpulse); + ImGui::Checkbox("Center of Masses", &s_settings.m_drawCOMs); + ImGui::Checkbox("Statistics", &s_settings.m_drawStats); + ImGui::Checkbox("Profile", &s_settings.m_drawProfile); + + ImVec2 button_sz = ImVec2(-1, 0); + if (ImGui::Button("Pause (P)", button_sz)) + { + s_settings.m_pause = !s_settings.m_pause; + } + + if (ImGui::Button("Single Step (O)", button_sz)) + { + s_settings.m_singleStep = !s_settings.m_singleStep; + } + + if (ImGui::Button("Restart (R)", button_sz)) + { + RestartTest(); + } + + if (ImGui::Button("Quit", button_sz)) + { + glfwSetWindowShouldClose(g_mainWindow, GL_TRUE); + } + + ImGui::EndTabItem(); + } + + ImGuiTreeNodeFlags leafNodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; + leafNodeFlags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; + + ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; + + if (ImGui::BeginTabItem("Tests")) + { + int categoryIndex = 0; + const char* category = g_testEntries[categoryIndex].category; + int i = 0; + while (i < g_testCount) + { + bool categorySelected = strcmp(category, g_testEntries[s_settings.m_testIndex].category) == 0; + ImGuiTreeNodeFlags nodeSelectionFlags = categorySelected ? ImGuiTreeNodeFlags_Selected : 0; + bool nodeOpen = ImGui::TreeNodeEx(category, nodeFlags | nodeSelectionFlags); + + if (nodeOpen) + { + while (i < g_testCount && strcmp(category, g_testEntries[i].category) == 0) + { + ImGuiTreeNodeFlags selectionFlags = 0; + if (s_settings.m_testIndex == i) + { + selectionFlags = ImGuiTreeNodeFlags_Selected; + } + ImGui::TreeNodeEx((void*)(intptr_t)i, leafNodeFlags | selectionFlags, "%s", g_testEntries[i].name); + if (ImGui::IsItemClicked()) + { + delete s_test; + s_settings.m_testIndex = i; + s_test = g_testEntries[i].createFcn(); + s_testSelection = i; + } + ++i; + } + ImGui::TreePop(); + } + else + { + while (i < g_testCount && strcmp(category, g_testEntries[i].category) == 0) + { + ++i; + } + } + + if (i < g_testCount) + { + category = g_testEntries[i].category; + categoryIndex = i; + } + } + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + + ImGui::End(); + + s_test->UpdateUI(); + } +} + +// +int main(int, char**) +{ +#if defined(_WIN32) + // Enable memory-leak reports + _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); +#endif + + char buffer[128]; + + s_settings.Load(); + SortTests(); + + glfwSetErrorCallback(glfwErrorCallback); + + g_camera.m_width = s_settings.m_windowWidth; + g_camera.m_height = s_settings.m_windowHeight; + + if (glfwInit() == 0) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + return -1; + } + +#if __APPLE__ + const char* glslVersion = "#version 150"; +#else + const char* glslVersion = NULL; +#endif + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + sprintf(buffer, "Box2D Testbed Version %d.%d.%d", b2_version.major, b2_version.minor, b2_version.revision); + + bool fullscreen = false; + if (fullscreen) + { + g_mainWindow = glfwCreateWindow(1920, 1080, buffer, glfwGetPrimaryMonitor(), NULL); + } + else + { + g_mainWindow = glfwCreateWindow(g_camera.m_width, g_camera.m_height, buffer, NULL, NULL); + } + + if (g_mainWindow == NULL) + { + fprintf(stderr, "Failed to open GLFW g_mainWindow.\n"); + glfwTerminate(); + return -1; + } + + glfwMakeContextCurrent(g_mainWindow); + + // Load OpenGL functions using glad + int version = gladLoadGL(glfwGetProcAddress); + printf("GL %d.%d\n", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)); + printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION)); + + glfwSetScrollCallback(g_mainWindow, ScrollCallback); + glfwSetWindowSizeCallback(g_mainWindow, ResizeWindowCallback); + glfwSetKeyCallback(g_mainWindow, KeyCallback); + glfwSetCharCallback(g_mainWindow, CharCallback); + glfwSetMouseButtonCallback(g_mainWindow, MouseButtonCallback); + glfwSetCursorPosCallback(g_mainWindow, MouseMotionCallback); + glfwSetScrollCallback(g_mainWindow, ScrollCallback); + + g_debugDraw.Create(); + + CreateUI(g_mainWindow, glslVersion); + + s_settings.m_testIndex = b2Clamp(s_settings.m_testIndex, 0, g_testCount - 1); + s_testSelection = s_settings.m_testIndex; + s_test = g_testEntries[s_settings.m_testIndex].createFcn(); + + // Control the frame rate. One draw per monitor refresh. + //glfwSwapInterval(1); + + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + + std::chrono::duration<double> frameTime(0.0); + std::chrono::duration<double> sleepAdjust(0.0); + + while (!glfwWindowShouldClose(g_mainWindow)) + { + std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); + + glfwGetWindowSize(g_mainWindow, &g_camera.m_width, &g_camera.m_height); + + int bufferWidth, bufferHeight; + glfwGetFramebufferSize(g_mainWindow, &bufferWidth, &bufferHeight); + glViewport(0, 0, bufferWidth, bufferHeight); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + + ImGui::NewFrame(); + + if (g_debugDraw.m_showUI) + { + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(float(g_camera.m_width), float(g_camera.m_height))); + ImGui::SetNextWindowBgAlpha(0.0f); + ImGui::Begin("Overlay", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); + ImGui::End(); + + const TestEntry& entry = g_testEntries[s_settings.m_testIndex]; + sprintf(buffer, "%s : %s", entry.category, entry.name); + s_test->DrawTitle(buffer); + } + + s_test->Step(s_settings); + + UpdateUI(); + + // ImGui::ShowDemoWindow(); + + if (g_debugDraw.m_showUI) + { + sprintf(buffer, "%.1f ms", 1000.0 * frameTime.count()); + g_debugDraw.DrawString(5, g_camera.m_height - 20, buffer); + } + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + glfwSwapBuffers(g_mainWindow); + + if (s_testSelection != s_settings.m_testIndex) + { + s_settings.m_testIndex = s_testSelection; + delete s_test; + s_test = g_testEntries[s_settings.m_testIndex].createFcn(); + g_camera.m_zoom = 1.0f; + g_camera.m_center.Set(0.0f, 20.0f); + } + + glfwPollEvents(); + + // Throttle to cap at 60Hz. This adaptive using a sleep adjustment. This could be improved by + // using mm_pause or equivalent for the last millisecond. + std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now(); + std::chrono::duration<double> target(1.0 / 60.0); + std::chrono::duration<double> timeUsed = t2 - t1; + std::chrono::duration<double> sleepTime = target - timeUsed + sleepAdjust; + if (sleepTime > std::chrono::duration<double>(0)) + { + std::this_thread::sleep_for(sleepTime); + } + + std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now(); + frameTime = t3 - t1; + + // Compute the sleep adjustment using a low pass filter + sleepAdjust = 0.9 * sleepAdjust + 0.1 * (target - frameTime); + } + + delete s_test; + s_test = nullptr; + + g_debugDraw.Destroy(); + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + glfwTerminate(); + + s_settings.Save(); + + return 0; +} |