Changeset 40eb092 in opengl-game
- Timestamp:
- Mar 9, 2021, 2:47:00 AM (4 years ago)
- Branches:
- feature/imgui-sdl
- Children:
- 20e4c2b
- Parents:
- 429ac01
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
sdl-game.cpp
r429ac01 r40eb092 4 4 #include <iostream> 5 5 #include <set> 6 #include <stdexcept>7 8 #include <SDL2/SDL_vulkan.h>9 6 10 7 #include "IMGUI/imgui_impl_sdl.h" … … 54 51 55 52 shouldRecreateSwapChain = false; 53 54 score = 0; 55 fps = 0.0f; 56 56 } 57 57 … … 60 60 61 61 void VulkanGame::run(int width, int height, unsigned char guiFlags) { 62 // TODO: Maybe call the init code in the constructor instead of in run() 63 // Research this 62 64 cout << "DEBUGGING IS " << (ENABLE_VALIDATION_LAYERS ? "ON" : "OFF") << endl; 63 65 64 66 cout << "Vulkan Game" << endl; 65 67 68 // TODO: Move IMGUI initialization in here 66 69 if (initUI(width, height, guiFlags) == RTWO_ERROR) { 67 70 return; … … 152 155 } 153 156 154 done = false; 155 while (!done) { 156 157 gui->processEvents(); 158 159 UIEvent uiEvent; 160 while (gui->pollEvent(&uiEvent)) { 161 GameEvent& e = uiEvent.event; 162 SDL_Event sdlEvent = uiEvent.rawEvent.sdl; 163 164 ImGui_ImplSDL2_ProcessEvent(&sdlEvent); 165 if (io.WantCaptureMouse && 166 (e.type == UI_EVENT_MOUSEBUTTONDOWN || e.type == UI_EVENT_MOUSEBUTTONUP || e.type == UI_EVENT_UNKNOWN)) { 167 if (sdlEvent.type == SDL_MOUSEWHEEL || sdlEvent.type == SDL_MOUSEBUTTONDOWN || sdlEvent.type == SDL_MOUSEBUTTONUP) { 168 continue; 169 } 170 } 171 if (io.WantCaptureKeyboard && 172 (e.type == UI_EVENT_KEYDOWN || e.type == UI_EVENT_KEYUP)) { 173 if (sdlEvent.type == SDL_KEYDOWN || sdlEvent.type == SDL_KEYUP) { 174 continue; 175 } 176 } 177 if (io.WantTextInput) { 178 // show onscreen keyboard if on mobile 179 } 180 181 if (e.type == UI_EVENT_QUIT) { 182 done = true; 183 } 184 } 185 186 if (shouldRecreateSwapChain) { 187 gui->refreshWindowSize(); 188 const bool isMinimized = gui->getWindowWidth() == 0 || gui->getWindowHeight() == 0; 189 190 if (!isMinimized) { 191 // TODO: This should be used if the min image count changes, presumably because a new surface was created 192 // with a different image count or something like that. Maybe I want to add code to query for a new min image count 193 // during swapchain recreation to take advantage of this 194 ImGui_ImplVulkan_SetMinImageCount(swapChainMinImageCount); 195 196 recreateSwapChain(); 197 198 imageIndex = 0; 199 shouldRecreateSwapChain = false; 200 } 201 } 202 203 // Start the Dear ImGui frame 204 ImGui_ImplVulkan_NewFrame(); 205 ImGui_ImplSDL2_NewFrame(window); 206 ImGui::NewFrame(); 207 208 // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. 209 { 210 static int counter = 0; 211 212 ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. 213 214 ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) 215 216 if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) 217 counter++; 218 ImGui::SameLine(); 219 ImGui::Text("counter = %d", counter); 220 221 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 222 ImGui::End(); 223 } 224 225 ImGui::Render(); 226 227 gui->refreshWindowSize(); 228 const bool isMinimized = gui->getWindowWidth() == 0 || gui->getWindowHeight() == 0; 229 230 if (!isMinimized) { 231 renderFrame(ImGui::GetDrawData()); 232 presentFrame(); 233 } 234 } 235 157 currentRenderScreenFn = &VulkanGame::renderMainScreen; 158 159 initGuiValueLists(valueLists); 160 161 valueLists["stats value list"].push_back(UIValue(UIVALUE_INT, "Score", &score)); 162 valueLists["stats value list"].push_back(UIValue(UIVALUE_DOUBLE, "FPS", &fps)); 163 valueLists["stats value list"].push_back(UIValue(UIVALUE_DOUBLE, "IMGUI FPS", &io.Framerate)); 164 165 renderLoop(); 236 166 cleanup(); 237 167 … … 321 251 322 252 createSyncObjects(); 253 } 254 255 void VulkanGame::renderLoop() { 256 startTime = high_resolution_clock::now(); 257 curTime = duration<float, seconds::period>(high_resolution_clock::now() - startTime).count(); 258 259 fpsStartTime = curTime; 260 frameCount = 0; 261 262 ImGuiIO& io = ImGui::GetIO(); 263 264 done = false; 265 while (!done) { 266 267 curTime = duration<float, seconds::period>(high_resolution_clock::now() - startTime).count(); 268 269 if (curTime - fpsStartTime >= 1.0f) { 270 fps = (float)frameCount / (curTime - fpsStartTime); 271 272 frameCount = 0; 273 fpsStartTime = curTime; 274 } 275 276 frameCount++; 277 278 gui->processEvents(); 279 280 UIEvent uiEvent; 281 while (gui->pollEvent(&uiEvent)) { 282 GameEvent& e = uiEvent.event; 283 SDL_Event sdlEvent = uiEvent.rawEvent.sdl; 284 285 ImGui_ImplSDL2_ProcessEvent(&sdlEvent); 286 if (io.WantCaptureMouse && 287 (e.type == UI_EVENT_MOUSEBUTTONDOWN || e.type == UI_EVENT_MOUSEBUTTONUP || e.type == UI_EVENT_UNKNOWN)) { 288 if (sdlEvent.type == SDL_MOUSEWHEEL || sdlEvent.type == SDL_MOUSEBUTTONDOWN || sdlEvent.type == SDL_MOUSEBUTTONUP) { 289 continue; 290 } 291 } 292 if (io.WantCaptureKeyboard && 293 (e.type == UI_EVENT_KEYDOWN || e.type == UI_EVENT_KEYUP)) { 294 if (sdlEvent.type == SDL_KEYDOWN || sdlEvent.type == SDL_KEYUP) { 295 continue; 296 } 297 } 298 if (io.WantTextInput) { 299 // show onscreen keyboard if on mobile 300 } 301 302 switch (e.type) { 303 case UI_EVENT_MOUSEMOTION: 304 // Currently unused 305 break; 306 case UI_EVENT_WINDOW: 307 // Currently unused 308 break; 309 case UI_EVENT_QUIT: 310 cout << "Quit event detected" << endl; 311 done = true; 312 break; 313 case UI_EVENT_UNHANDLED: 314 cout << "Unhandled event type: 0x" << hex << sdlEvent.type << dec << endl; 315 break; 316 case UI_EVENT_UNKNOWN: 317 default: 318 cout << "Unknown event type: 0x" << hex << sdlEvent.type << dec << endl; 319 break; 320 } 321 } 322 323 if (shouldRecreateSwapChain) { 324 gui->refreshWindowSize(); 325 const bool isMinimized = gui->getWindowWidth() == 0 || gui->getWindowHeight() == 0; 326 327 if (!isMinimized) { 328 // TODO: This should be used if the min image count changes, presumably because a new surface was created 329 // with a different image count or something like that. Maybe I want to add code to query for a new min image count 330 // during swapchain recreation to take advantage of this 331 ImGui_ImplVulkan_SetMinImageCount(swapChainMinImageCount); 332 333 recreateSwapChain(); 334 335 imageIndex = 0; 336 shouldRecreateSwapChain = false; 337 } 338 } 339 340 // Start the Dear ImGui frame 341 ImGui_ImplVulkan_NewFrame(); 342 ImGui_ImplSDL2_NewFrame(window); 343 ImGui::NewFrame(); 344 345 (this->*currentRenderScreenFn)(); 346 347 ImGui::Render(); 348 349 gui->refreshWindowSize(); 350 const bool isMinimized = gui->getWindowWidth() == 0 || gui->getWindowHeight() == 0; 351 352 if (!isMinimized) { 353 renderFrame(ImGui::GetDrawData()); 354 presentFrame(); 355 } 356 } 323 357 } 324 358 … … 964 998 vkDestroySwapchainKHR(device, swapChain, nullptr); 965 999 } 1000 1001 void VulkanGame::renderMainScreen() { 1002 unsigned int windowWidth = 640; 1003 unsigned int windowHeight = 480; 1004 1005 { 1006 int padding = 4; 1007 ImGui::SetNextWindowPos(ImVec2(-padding, -padding), ImGuiCond_Once); 1008 ImGui::SetNextWindowSize(ImVec2(windowWidth + 2 * padding, windowHeight + 2 * padding), ImGuiCond_Always); 1009 ImGui::Begin("WndMain", nullptr, 1010 ImGuiWindowFlags_NoTitleBar | 1011 ImGuiWindowFlags_NoResize | 1012 ImGuiWindowFlags_NoMove); 1013 1014 ImGui::InvisibleButton("", ImVec2(10, 80)); 1015 ImGui::InvisibleButton("", ImVec2(285, 18)); 1016 ImGui::SameLine(); 1017 if (ImGui::Button("New Game")) { 1018 goToScreen(&VulkanGame::renderGameScreen); 1019 } 1020 1021 ImGui::InvisibleButton("", ImVec2(10, 15)); 1022 ImGui::InvisibleButton("", ImVec2(300, 18)); 1023 ImGui::SameLine(); 1024 if (ImGui::Button("Quit")) { 1025 quitGame(); 1026 } 1027 1028 ImGui::End(); 1029 } 1030 } 1031 1032 void VulkanGame::renderGameScreen() { 1033 { 1034 ImGui::SetNextWindowSize(ImVec2(130, 65), ImGuiCond_Once); 1035 ImGui::SetNextWindowPos(ImVec2(10, 50), ImGuiCond_Once); 1036 ImGui::Begin("WndStats", nullptr, 1037 ImGuiWindowFlags_NoTitleBar | 1038 ImGuiWindowFlags_NoResize | 1039 ImGuiWindowFlags_NoMove); 1040 1041 //ImGui::Text(ImGui::GetIO().Framerate); 1042 renderGuiValueList(valueLists["stats value list"]); 1043 1044 ImGui::End(); 1045 } 1046 1047 { 1048 ImGui::SetNextWindowSize(ImVec2(250, 35), ImGuiCond_Once); 1049 ImGui::SetNextWindowPos(ImVec2(380, 10), ImGuiCond_Once); 1050 ImGui::Begin("WndMenubar", nullptr, 1051 ImGuiWindowFlags_NoTitleBar | 1052 ImGuiWindowFlags_NoResize | 1053 ImGuiWindowFlags_NoMove); 1054 ImGui::InvisibleButton("", ImVec2(155, 18)); 1055 ImGui::SameLine(); 1056 if (ImGui::Button("Main Menu")) { 1057 goToScreen(&VulkanGame::renderMainScreen); 1058 } 1059 ImGui::End(); 1060 } 1061 1062 { 1063 ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiCond_Once); 1064 ImGui::SetNextWindowPos(ImVec2(430, 60), ImGuiCond_Once); 1065 ImGui::Begin("WndDebug", nullptr, 1066 ImGuiWindowFlags_NoTitleBar | 1067 ImGuiWindowFlags_NoResize | 1068 ImGuiWindowFlags_NoMove); 1069 1070 renderGuiValueList(valueLists["debug value list"]); 1071 1072 ImGui::End(); 1073 } 1074 } 1075 1076 void VulkanGame::initGuiValueLists(map<string, vector<UIValue>>& valueLists) { 1077 valueLists["stats value list"] = vector<UIValue>(); 1078 valueLists["debug value list"] = vector<UIValue>(); 1079 } 1080 1081 void VulkanGame::renderGuiValueList(vector<UIValue>& values) { 1082 float maxWidth = 0.0f; 1083 float cursorStartPos = ImGui::GetCursorPosX(); 1084 1085 for (vector<UIValue>::iterator it = values.begin(); it != values.end(); it++) { 1086 float textWidth = ImGui::CalcTextSize(it->label.c_str()).x; 1087 1088 if (maxWidth < textWidth) 1089 maxWidth = textWidth; 1090 } 1091 1092 stringstream ss; 1093 1094 // TODO: Possibly implement this based on gui/ui-value.hpp instead and use templates 1095 // to keep track of the type. This should make it a bit easier to use and maintain 1096 // Also, implement this in a way that's agnostic to the UI renderer. 1097 for (vector<UIValue>::iterator it = values.begin(); it != values.end(); it++) { 1098 ss.str(""); 1099 ss.clear(); 1100 1101 switch (it->type) { 1102 case UIVALUE_INT: 1103 ss << it->label << ": " << *(unsigned int*)it->value; 1104 break; 1105 case UIVALUE_DOUBLE: 1106 ss << it->label << ": " << *(double*)it->value; 1107 break; 1108 } 1109 1110 float textWidth = ImGui::CalcTextSize(it->label.c_str()).x; 1111 1112 ImGui::SetCursorPosX(cursorStartPos + maxWidth - textWidth); 1113 //ImGui::Text("%s", ss.str().c_str()); 1114 ImGui::Text("%s: %.1f", it->label.c_str(), *(float*)it->value); 1115 } 1116 } 1117 1118 void VulkanGame::goToScreen(void (VulkanGame::* renderScreenFn)()) { 1119 currentRenderScreenFn = renderScreenFn; 1120 } 1121 1122 void VulkanGame::quitGame() { 1123 done = true; 1124 } -
sdl-game.hpp
r429ac01 r40eb092 2 2 #define _SDL_GAME_H 3 3 4 #include <chrono> 5 #include <map> 4 6 #include <vector> 7 5 8 #include <vulkan/vulkan.h> 6 9 … … 15 18 16 19 using namespace std; 20 using namespace std::chrono; 17 21 18 22 #define VulkanGame NewVulkanGame … … 23 27 const bool ENABLE_VALIDATION_LAYERS = true; 24 28 #endif 29 30 // TODO: Maybe move this to a different header 31 32 enum UIValueType { 33 UIVALUE_INT, 34 UIVALUE_DOUBLE, 35 }; 36 37 struct UIValue { 38 UIValueType type; 39 string label; 40 void* value; 41 42 UIValue(UIValueType _type, string _label, void* _value) : type(_type), label(_label), value(_value) {} 43 }; 25 44 26 45 class VulkanGame { … … 88 107 bool shouldRecreateSwapChain; 89 108 90 // My code, but not complete. Skips creating the SDL renderer, probably because it doesn't use hardware acceleration. 91 // I should try to get uncapped framerate and compare performance w/ and w/out an SDL renderer 109 /*** High-level vars ***/ 110 111 void (VulkanGame::* currentRenderScreenFn)(); 112 113 map<string, vector<UIValue>> valueLists; 114 115 int score; 116 float fps; 117 118 // TODO: Make a separate singleton Timer class 119 // It could also deal with the steady_clock vs high_resolution_clock issue 120 time_point<steady_clock> startTime; 121 float fpsStartTime, curTime; 122 123 int frameCount; 124 125 /*** Functions ***/ 126 92 127 bool initUI(int width, int height, unsigned char guiFlags); 93 void initVulkan(); // Mostly example code 94 void cleanup(); // Mostly example 128 void initVulkan(); 129 void renderLoop(); 130 void cleanup(); 95 131 96 132 void createVulkanInstance(const vector<const char*>& validationLayers); … … 120 156 void cleanupSwapChain(); 121 157 158 /*** High-level functions ***/ 159 160 void renderMainScreen(); 161 void renderGameScreen(); 162 163 void initGuiValueLists(map<string, vector<UIValue>>& valueLists); 164 void renderGuiValueList(vector<UIValue>& values); 165 166 void goToScreen(void (VulkanGame::* renderScreenFn)()); 167 void quitGame(); 168 122 169 // Pipeline variables. Hopefully, I can eventually use the GraphicsPipeline_Vulkan class for the imgui pipeline 123 170 VkDescriptorPool descriptorPool; 124 125 171 }; 126 172
Note:
See TracChangeset
for help on using the changeset viewer.