Changeset 20e4c2b in opengl-game for vulkan-game.cpp
- Timestamp:
- Mar 9, 2021, 2:59:40 AM (4 years ago)
- Branches:
- feature/imgui-sdl
- Children:
- 187b0f5
- Parents:
- 40eb092
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vulkan-game.cpp
r40eb092 r20e4c2b 12 12 13 13 #include "utils.hpp" 14 15 #include "gui/main-screen.hpp"16 #include "gui/game-screen.hpp"17 14 18 15 using namespace std; … … 71 68 laser_VP_mats = {}; 72 69 explosion_UBO = {}; 70 71 score = 0; 72 fps = 0.0f; 73 73 } 74 74 … … 77 77 78 78 void VulkanGame::run(int width, int height, unsigned char guiFlags) { 79 // TODO: Maybe call the init code in the constructor instead of in run() 80 // Research this 79 81 seedRandomNums(); 80 82 … … 83 85 cout << "Vulkan Game" << endl; 84 86 85 this->score = 0; 86 87 // TODO: Move IMGUI initialization in here 87 88 if (initUI(width, height, guiFlags) == RTWO_ERROR) { 88 89 return; 89 90 } 90 91 91 // TODO: Maybe make a struct of properties to share with each screen instead of passing92 // in all of VulkanGame93 screens[SCREEN_MAIN] = new MainScreen(*renderer, *this);94 screens[SCREEN_GAME] = new GameScreen(*renderer, *this);95 96 currentScreen = screens[SCREEN_MAIN];97 98 92 initVulkan(); 99 mainLoop(); 93 94 ImGuiIO& io = ImGui::GetIO(); 95 96 currentRenderScreenFn = &VulkanGame::renderMainScreen; 97 98 initGuiValueLists(valueLists); 99 100 valueLists["stats value list"].push_back(UIValue(UIVALUE_INT, "Score", &score)); 101 valueLists["stats value list"].push_back(UIValue(UIVALUE_DOUBLE, "FPS", &fps)); 102 valueLists["stats value list"].push_back(UIValue(UIVALUE_DOUBLE, "IMGUI FPS", &io.Framerate)); 103 104 renderLoop(); 100 105 cleanup(); 101 106 102 107 close_log(); 103 }104 105 void VulkanGame::goToScreen(Screen* screen) {106 currentScreen = screen;107 currentScreen->init();108 109 // TODO: Maybe just set shouldRecreateSwapChain to true instead. Check this render loop logic110 // to make sure there'd be no issues111 recreateSwapChain();112 }113 114 void VulkanGame::quitGame() {115 done = true;116 108 } 117 109 … … 151 143 cout << "UI library could not be initialized!" << endl; 152 144 cout << gui->getError() << endl; 145 // TODO: Rename RTWO_ERROR to something else 153 146 return RTWO_ERROR; 154 147 } … … 163 156 cout << "Target window size: (" << width << ", " << height << ")" << endl; 164 157 cout << "Actual window size: (" << gui->getWindowWidth() << ", " << gui->getWindowHeight() << ")" << endl; 165 166 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);167 if (renderer == nullptr) {168 cout << "Renderer could not be created!" << endl;169 cout << gui->getError() << endl;170 return RTWO_ERROR;171 }172 173 uiOverlay = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,174 gui->getWindowWidth(), gui->getWindowHeight());175 176 if (uiOverlay == nullptr) {177 cout << "Unable to create blank texture! SDL Error: " << SDL_GetError() << endl;178 return RTWO_ERROR;179 }180 if (SDL_SetTextureBlendMode(uiOverlay, SDL_BLENDMODE_BLEND) != 0) {181 cout << "Unable to set texture blend mode! SDL Error: " << SDL_GetError() << endl;182 return RTWO_ERROR;183 }184 185 SDL_SetRenderTarget(renderer, uiOverlay);186 187 // TODO: Print the filename of the font in the error message188 189 lazyFont = TTF_OpenFont("assets/fonts/lazy.ttf", 28);190 if (lazyFont == nullptr) {191 cout << "Failed to load lazy font! SDL_ttf Error: " << TTF_GetError() << endl;192 return RTWO_ERROR;193 }194 195 proggyFont = TTF_OpenFont("assets/fonts/ProggyClean.ttf", 16);196 if (proggyFont == nullptr) {197 cout << "Failed to load proggy font! SDL_ttf Error: " << TTF_GetError() << endl;198 return RTWO_ERROR;199 }200 158 201 159 return RTWO_SUCCESS; … … 320 278 321 279 initGraphicsPipelines(); 322 323 overlayPipeline.addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&OverlayVertex::pos));324 overlayPipeline.addAttribute(VK_FORMAT_R32G32_SFLOAT, offset_of(&OverlayVertex::texCoord));325 326 overlayPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,327 VK_SHADER_STAGE_FRAGMENT_BIT, &sdlOverlayImageDescriptor);328 329 addObject(overlayObjects, overlayPipeline,330 {331 {{-1.0f, 1.0f, 0.0f}, {0.0f, 1.0f}},332 {{ 1.0f, 1.0f, 0.0f}, {1.0f, 1.0f}},333 {{ 1.0f, -1.0f, 0.0f}, {1.0f, 0.0f}},334 {{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f}}335 }, {336 0, 1, 2, 2, 3, 0337 }, {}, false);338 339 overlayPipeline.createDescriptorSetLayout();340 overlayPipeline.createPipeline("shaders/overlay-vert.spv", "shaders/overlay-frag.spv");341 overlayPipeline.createDescriptorPool(swapChainImages);342 overlayPipeline.createDescriptorSets(swapChainImages);343 280 344 281 modelPipeline.addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&ModelVertex::pos)); … … 713 650 714 651 void VulkanGame::initGraphicsPipelines() { 715 overlayPipeline = GraphicsPipeline_Vulkan<OverlayVertex, void*>(716 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,717 { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 4, 6, 0);718 719 652 modelPipeline = GraphicsPipeline_Vulkan<ModelVertex, SSBO_ModelObject>( 720 653 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass, … … 772 705 } 773 706 774 void VulkanGame:: mainLoop() {775 this->startTime = high_resolution_clock::now();776 curTime = duration<float, seconds::period>(high_resolution_clock::now() - this->startTime).count();777 778 this->fpsStartTime = curTime;779 this->frameCount = 0;707 void VulkanGame::renderLoop() { 708 startTime = high_resolution_clock::now(); 709 curTime = duration<float, seconds::period>(high_resolution_clock::now() - startTime).count(); 710 711 fpsStartTime = curTime; 712 frameCount = 0; 780 713 781 714 lastSpawn_asteroid = curTime; … … 921 854 } 922 855 923 currentScreen->handleEvent(e);856 // currentScreen->handleEvent(e); 924 857 } 925 858 … … 973 906 } 974 907 975 currentScreen->renderUI();976 977 // Copy the UI image to a vulkan texture978 // TODO: I'm pretty sure this severely slows down the pipeline since this functions waits for the copy to be979 // complete before continuing. See if I can find a more efficient method.980 VulkanUtils::populateVulkanImageFromSDLTexture(device, physicalDevice, resourceCommandPool, uiOverlay, renderer,981 sdlOverlayImage, graphicsQueue);982 983 908 updateScene(); 984 909 … … 987 912 ImGui::NewFrame(); 988 913 989 { 990 ImGui::SetNextWindowSize(ImVec2(250, 35), ImGuiCond_Once); 991 ImGui::SetNextWindowPos(ImVec2(380, 10), ImGuiCond_Once); 992 ImGui::Begin("WndMenubar", NULL, 993 ImGuiWindowFlags_NoTitleBar | 994 ImGuiWindowFlags_NoResize | 995 ImGuiWindowFlags_NoMove); 996 ImGui::InvisibleButton("", ImVec2(155, 18)); 997 ImGui::SameLine(); 998 if (ImGui::Button("Main Menu")) { 999 cout << "Clicked on the main button" << endl; 1000 //events.push(Event::GO_TO_MAIN_MENU); 1001 } 1002 ImGui::End(); 1003 } 914 (this->*currentRenderScreenFn)(); 1004 915 1005 916 ImGui::Render(); 1006 1007 // There is already code in renderFrame to render screen-specific things1008 // The imgui code above should be moved to the renderUI function of the particular screen it's needed in1009 // and currentScreen->renderUI should be called in renderFrame.1010 // Since I am no longer drawing the UI to an sdl texture and then rendering that, I don't have to worry1011 // about calling populateVulkanImageFromSDLTexture at all.1012 // If I do ever want to do that again, I can still actually do it inside renderFrame1013 917 1014 918 gui->refreshWindowSize(); … … 1227 1131 cleanupSwapChain(); 1228 1132 1229 VulkanUtils::destroyVulkanImage(device, sdlOverlayImage);1230 1133 VulkanUtils::destroyVulkanImage(device, floorTextureImage); 1231 1134 VulkanUtils::destroyVulkanImage(device, laserTextureImage); … … 1234 1137 1235 1138 modelPipeline.cleanupBuffers(); 1236 overlayPipeline.cleanupBuffers();1237 1139 shipPipeline.cleanupBuffers(); 1238 1140 asteroidPipeline.cleanupBuffers(); … … 1250 1152 1251 1153 vkDestroyInstance(instance, nullptr); 1252 1253 delete screens[SCREEN_MAIN];1254 delete screens[SCREEN_GAME];1255 1256 if (lazyFont != nullptr) {1257 TTF_CloseFont(lazyFont);1258 lazyFont = nullptr;1259 }1260 1261 if (proggyFont != nullptr) {1262 TTF_CloseFont(proggyFont);1263 proggyFont = nullptr;1264 }1265 1266 if (uiOverlay != nullptr) {1267 SDL_DestroyTexture(uiOverlay);1268 uiOverlay = nullptr;1269 }1270 1271 SDL_DestroyRenderer(renderer);1272 renderer = nullptr;1273 1154 1274 1155 gui->destroyWindow(); … … 1668 1549 // TODO: Move all images/textures somewhere into the assets folder 1669 1550 1670 VulkanUtils::createVulkanImageFromSDLTexture(device, physicalDevice, uiOverlay, sdlOverlayImage);1671 1672 sdlOverlayImageDescriptor = {};1673 sdlOverlayImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;1674 sdlOverlayImageDescriptor.imageView = sdlOverlayImage.imageView;1675 sdlOverlayImageDescriptor.sampler = textureSampler;1676 1677 1551 VulkanUtils::createVulkanImageFromFile(device, physicalDevice, resourceCommandPool, "textures/texture.jpg", 1678 1552 floorTextureImage, graphicsQueue); … … 1805 1679 vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); 1806 1680 1807 currentScreen->createRenderCommands(commandBuffers[imageIndex], imageIndex); 1681 // TODO: Find a more elegant, per-screen solution for this 1682 if (currentRenderScreenFn == &VulkanGame::renderGameScreen) { 1683 modelPipeline.createRenderCommands(commandBuffers[imageIndex], imageIndex); 1684 shipPipeline.createRenderCommands(commandBuffers[imageIndex], imageIndex); 1685 asteroidPipeline.createRenderCommands(commandBuffers[imageIndex], imageIndex); 1686 laserPipeline.createRenderCommands(commandBuffers[imageIndex], imageIndex); 1687 explosionPipeline.createRenderCommands(commandBuffers[imageIndex], imageIndex); 1688 } 1808 1689 1809 1690 ImGui_ImplVulkan_RenderDrawData(draw_data, commandBuffers[imageIndex]); … … 2202 2083 modelPipeline.createDescriptorSets(swapChainImages); 2203 2084 2204 overlayPipeline.updateRenderPass(renderPass);2205 overlayPipeline.createPipeline("shaders/overlay-vert.spv", "shaders/overlay-frag.spv");2206 overlayPipeline.createDescriptorPool(swapChainImages);2207 overlayPipeline.createDescriptorSets(swapChainImages);2208 2209 2085 createBufferSet(sizeof(UBO_VP_mats), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 2210 2086 uniformBuffers_shipPipeline, uniformBuffersMemory_shipPipeline, uniformBufferInfoList_shipPipeline); … … 2258 2134 } 2259 2135 2260 overlayPipeline.cleanup();2261 2136 modelPipeline.cleanup(); 2262 2137 shipPipeline.cleanup(); … … 2304 2179 vkDestroySwapchainKHR(device, swapChain, nullptr); 2305 2180 } 2181 2182 void VulkanGame::renderMainScreen() { 2183 unsigned int windowWidth = 640; 2184 unsigned int windowHeight = 480; 2185 2186 { 2187 int padding = 4; 2188 ImGui::SetNextWindowPos(ImVec2(-padding, -padding), ImGuiCond_Once); 2189 ImGui::SetNextWindowSize(ImVec2(windowWidth + 2 * padding, windowHeight + 2 * padding), ImGuiCond_Always); 2190 ImGui::Begin("WndMain", nullptr, 2191 ImGuiWindowFlags_NoTitleBar | 2192 ImGuiWindowFlags_NoResize | 2193 ImGuiWindowFlags_NoMove); 2194 2195 ImGui::InvisibleButton("", ImVec2(10, 80)); 2196 ImGui::InvisibleButton("", ImVec2(285, 18)); 2197 ImGui::SameLine(); 2198 if (ImGui::Button("New Game")) { 2199 goToScreen(&VulkanGame::renderGameScreen); 2200 } 2201 2202 ImGui::InvisibleButton("", ImVec2(10, 15)); 2203 ImGui::InvisibleButton("", ImVec2(300, 18)); 2204 ImGui::SameLine(); 2205 if (ImGui::Button("Quit")) { 2206 quitGame(); 2207 } 2208 2209 ImGui::End(); 2210 } 2211 } 2212 2213 void VulkanGame::renderGameScreen() { 2214 { 2215 ImGui::SetNextWindowSize(ImVec2(130, 65), ImGuiCond_Once); 2216 ImGui::SetNextWindowPos(ImVec2(10, 50), ImGuiCond_Once); 2217 ImGui::Begin("WndStats", nullptr, 2218 ImGuiWindowFlags_NoTitleBar | 2219 ImGuiWindowFlags_NoResize | 2220 ImGuiWindowFlags_NoMove); 2221 2222 //ImGui::Text(ImGui::GetIO().Framerate); 2223 renderGuiValueList(valueLists["stats value list"]); 2224 2225 ImGui::End(); 2226 } 2227 2228 { 2229 ImGui::SetNextWindowSize(ImVec2(250, 35), ImGuiCond_Once); 2230 ImGui::SetNextWindowPos(ImVec2(380, 10), ImGuiCond_Once); 2231 ImGui::Begin("WndMenubar", nullptr, 2232 ImGuiWindowFlags_NoTitleBar | 2233 ImGuiWindowFlags_NoResize | 2234 ImGuiWindowFlags_NoMove); 2235 ImGui::InvisibleButton("", ImVec2(155, 18)); 2236 ImGui::SameLine(); 2237 if (ImGui::Button("Main Menu")) { 2238 goToScreen(&VulkanGame::renderMainScreen); 2239 } 2240 ImGui::End(); 2241 } 2242 2243 { 2244 ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiCond_Once); 2245 ImGui::SetNextWindowPos(ImVec2(430, 60), ImGuiCond_Once); 2246 ImGui::Begin("WndDebug", nullptr, 2247 ImGuiWindowFlags_NoTitleBar | 2248 ImGuiWindowFlags_NoResize | 2249 ImGuiWindowFlags_NoMove); 2250 2251 renderGuiValueList(valueLists["debug value list"]); 2252 2253 ImGui::End(); 2254 } 2255 } 2256 2257 void VulkanGame::initGuiValueLists(map<string, vector<UIValue>>& valueLists) { 2258 valueLists["stats value list"] = vector<UIValue>(); 2259 valueLists["debug value list"] = vector<UIValue>(); 2260 } 2261 2262 void VulkanGame::renderGuiValueList(vector<UIValue>& values) { 2263 float maxWidth = 0.0f; 2264 float cursorStartPos = ImGui::GetCursorPosX(); 2265 2266 for (vector<UIValue>::iterator it = values.begin(); it != values.end(); it++) { 2267 float textWidth = ImGui::CalcTextSize(it->label.c_str()).x; 2268 2269 if (maxWidth < textWidth) 2270 maxWidth = textWidth; 2271 } 2272 2273 stringstream ss; 2274 2275 // TODO: Possibly implement this based on gui/ui-value.hpp instead and use templates 2276 // to keep track of the type. This should make it a bit easier to use and maintain 2277 // Also, implement this in a way that's agnostic to the UI renderer. 2278 for (vector<UIValue>::iterator it = values.begin(); it != values.end(); it++) { 2279 ss.str(""); 2280 ss.clear(); 2281 2282 switch (it->type) { 2283 case UIVALUE_INT: 2284 ss << it->label << ": " << *(unsigned int*)it->value; 2285 break; 2286 case UIVALUE_DOUBLE: 2287 ss << it->label << ": " << *(double*)it->value; 2288 break; 2289 } 2290 2291 float textWidth = ImGui::CalcTextSize(it->label.c_str()).x; 2292 2293 ImGui::SetCursorPosX(cursorStartPos + maxWidth - textWidth); 2294 //ImGui::Text("%s", ss.str().c_str()); 2295 ImGui::Text("%s: %.1f", it->label.c_str(), *(float*)it->value); 2296 } 2297 } 2298 2299 void VulkanGame::goToScreen(void (VulkanGame::* renderScreenFn)()) { 2300 currentRenderScreenFn = renderScreenFn; 2301 2302 // TODO: Maybe just set shouldRecreateSwapChain to true instead. Check this render loop logic 2303 // to make sure there'd be no issues 2304 //recreateSwapChain(); 2305 } 2306 2307 void VulkanGame::quitGame() { 2308 done = true; 2309 }
Note:
See TracChangeset
for help on using the changeset viewer.