source: opengl-game/vulkan-game.hpp@ a3cefaa

feature/imgui-sdl
Last change on this file since a3cefaa was a3cefaa, checked in by Dmitry Portnoy <dportnoy@…>, 4 years ago

Move SSBO resizing and pipeline recreation checks out of addObject() and into updateScene() so that those operations are only done at most once per pipeline per frame, using vkUpdateDescriptorSets() instead of recreating the whole graphics pipeline, and create a VulkanBuffer class for managing data related to uniform buffers and shader storage buffers, move objectCapacity and numObjects out of GraphicsPipeline_vulkan and use VulkanBuffer to manage them instead

  • Property mode set to 100644
File size: 24.4 KB
RevLine 
[99d44b2]1#ifndef _VULKAN_GAME_H
2#define _VULKAN_GAME_H
[e8ebc76]3
[aa7707d]4#include <algorithm>
[0807aeb]5#include <chrono>
[e1f88a9]6#include <map>
[5192672]7#include <vector>
[0807aeb]8
[20e4c2b]9#include <vulkan/vulkan.h>
10
11#include <SDL2/SDL.h>
12#include <SDL2/SDL_ttf.h>
13
[60578ce]14#define GLM_FORCE_RADIANS
15#define GLM_FORCE_DEPTH_ZERO_TO_ONE // Since, in Vulkan, the depth range is 0 to 1 instead of -1 to 1
[a79be34]16#define GLM_FORCE_RIGHT_HANDED
[60578ce]17
[771b33a]18#include <glm/glm.hpp>
[15104a8]19#include <glm/gtc/matrix_transform.hpp>
[771b33a]20
[ea2b4dc]21#include "IMGUI/imgui_impl_vulkan.h"
22
[6bfd91c]23#include "consts.hpp"
[b8efa56]24#include "utils.hpp"
25#include "vulkan-utils.hpp"
[a3cefaa]26#include "vulkan-buffer.hpp"
27#include "graphics-pipeline_vulkan.hpp"
28#include "game-gui-sdl.hpp"
[b794178]29
[15104a8]30using namespace glm;
[0807aeb]31using namespace std::chrono;
[15104a8]32
[2e77b3f]33#ifdef NDEBUG
34 const bool ENABLE_VALIDATION_LAYERS = false;
35#else
36 const bool ENABLE_VALIDATION_LAYERS = true;
37#endif
38
[cefdf23]39// TODO: Consider if there is a better way of dealing with all the vertex types and ssbo types, maybe
40// by consolidating some and trying to keep new ones to a minimum
41
[5a1ace0]42struct OverlayVertex {
[15104a8]43 vec3 pos;
44 vec2 texCoord;
[771b33a]45};
46
[5a1ace0]47struct ModelVertex {
[15104a8]48 vec3 pos;
[5a1ace0]49 vec3 color;
[15104a8]50 vec2 texCoord;
[a00eb06]51 vec3 normal;
[5a1ace0]52 unsigned int objIndex;
[15104a8]53};
54
[237cbec]55struct LaserVertex {
56 vec3 pos;
57 vec2 texCoord;
58 unsigned int objIndex;
59};
60
[4a9416a]61struct ExplosionVertex {
62 vec3 particleStartVelocity;
63 float particleStartTime;
64 unsigned int objIndex;
65};
66
[2d87297]67struct SSBO_ModelObject {
[055750a]68 alignas(16) mat4 model;
69};
70
[2d87297]71struct SSBO_Asteroid {
[3e8cc8b]72 alignas(16) mat4 model;
73 alignas(4) float hp;
[4ece3bf]74 alignas(4) unsigned int deleted;
[3e8cc8b]75};
76
[237cbec]77struct SSBO_Laser {
78 alignas(16) mat4 model;
79 alignas(4) vec3 color;
80 alignas(4) unsigned int deleted;
81};
82
[4a9416a]83struct SSBO_Explosion {
84 alignas(16) mat4 model;
85 alignas(4) float explosionStartTime;
86 alignas(4) float explosionDuration;
87 alignas(4) unsigned int deleted;
88};
89
[52a02e6]90struct UBO_VP_mats {
91 alignas(16) mat4 view;
92 alignas(16) mat4 proj;
93};
94
[4a9416a]95struct UBO_Explosion {
96 alignas(16) mat4 view;
97 alignas(16) mat4 proj;
98 alignas(4) float cur_time;
99};
100
[996dd3e]101// TODO: Use this struct for uniform buffers as well and probably combine it with the VulkanBuffer class
102// Also, probably better to make this a vector of structs where each struct
103// has a VkBuffer, VkDeviceMemory, and VkDescriptorBufferInfo
[a3cefaa]104// TODO: Maybe change the structure here since VkDescriptorBufferInfo already stores a reference to the VkBuffer
[996dd3e]105struct StorageBufferSet {
106 vector<VkBuffer> buffers;
107 vector<VkDeviceMemory> memory;
108 vector<VkDescriptorBufferInfo> infoSet;
109};
110
[4994692]111// TODO: Change the index type to uint32_t and check the Vulkan Tutorial loading model section as a reference
112// TODO: Create a typedef for index type so I can easily change uin16_t to something else later
113// TODO: Maybe create a typedef for each of the templated SceneObject types
114template<class VertexType, class SSBOType>
115struct SceneObject {
116 vector<VertexType> vertices;
117 vector<uint16_t> indices;
118 SSBOType ssbo;
119
120 mat4 model_base;
121 mat4 model_transform;
122
[5ba732a]123 bool modified;
124
[4994692]125 // TODO: Figure out if I should make child classes that have these fields instead of putting them in the
126 // parent class
127 vec3 center; // currently only matters for asteroids
128 float radius; // currently only matters for asteroids
[b8efa56]129 SceneObject<ModelVertex, SSBO_Asteroid>* targetAsteroid; // currently only used for lasers
[4994692]130};
131
132// TODO: Have to figure out how to include an optional ssbo parameter for each object
[2da64ef]133// Could probably use the same approach to make indices optional
[4994692]134// Figure out if there are sufficient use cases to make either of these optional or is it fine to make
135// them mamdatory
[2da64ef]136
[7297892]137
138// TODO: Look into using dynamic_cast to check types of SceneObject and EffectOverTime
139
140struct BaseEffectOverTime {
141 bool deleted;
142
[5192672]143 virtual void applyEffect(float curTime) = 0;
[7297892]144
145 BaseEffectOverTime() :
146 deleted(false) {
147 }
148
149 virtual ~BaseEffectOverTime() {
150 }
151};
152
153template<class VertexType, class SSBOType>
154struct EffectOverTime : public BaseEffectOverTime {
[9d21aac]155 GraphicsPipeline_Vulkan<VertexType>& pipeline;
[7297892]156 vector<SceneObject<VertexType, SSBOType>>& objects;
157 unsigned int objectIndex;
158 size_t effectedFieldOffset;
159 float startValue;
160 float startTime;
161 float changePerSecond;
162
[9d21aac]163 EffectOverTime(GraphicsPipeline_Vulkan<VertexType>& pipeline, vector<SceneObject<VertexType, SSBOType>>& objects,
164 unsigned int objectIndex, size_t effectedFieldOffset, float startTime, float changePerSecond)
165 : pipeline(pipeline)
166 , objects(objects)
167 , objectIndex(objectIndex)
168 , effectedFieldOffset(effectedFieldOffset)
169 , startTime(startTime)
170 , changePerSecond(changePerSecond) {
[7297892]171 size_t ssboOffset = offset_of(&SceneObject<VertexType, SSBOType>::ssbo);
172
173 unsigned char* effectedFieldPtr = reinterpret_cast<unsigned char*>(&objects[objectIndex]) +
174 ssboOffset + effectedFieldOffset;
175
176 startValue = *reinterpret_cast<float*>(effectedFieldPtr);
177 }
178
[5192672]179 void applyEffect(float curTime) {
[7297892]180 if (objects[objectIndex].ssbo.deleted) {
181 this->deleted = true;
182 return;
183 }
184
185 size_t ssboOffset = offset_of(&SceneObject<VertexType, SSBOType>::ssbo);
186
187 unsigned char* effectedFieldPtr = reinterpret_cast<unsigned char*>(&objects[objectIndex]) +
188 ssboOffset + effectedFieldOffset;
189
190 *reinterpret_cast<float*>(effectedFieldPtr) = startValue + (curTime - startTime) * changePerSecond;
191
192 objects[objectIndex].modified = true;
193 }
194};
195
[cefdf23]196// TODO: Maybe move this to a different header
197
[20e4c2b]198enum UIValueType {
199 UIVALUE_INT,
200 UIVALUE_DOUBLE,
201};
202
203struct UIValue {
204 UIValueType type;
205 string label;
206 void* value;
207
208 UIValue(UIValueType _type, string _label, void* _value) : type(_type), label(_label), value(_value) {}
209};
210
[e8445f0]211/* TODO: The following syntax (note the const keyword) means the function will not modify
212 * its params. I should use this where appropriate
213 *
214 * [return-type] [func-name](params...) const { ... }
215 */
216
[99d44b2]217class VulkanGame {
[914bb99]218
[e8ebc76]219 public:
[cefdf23]220
[3f32dfd]221 VulkanGame();
[99d44b2]222 ~VulkanGame();
[0df3c9a]223
[b6e60b4]224 void run(int width, int height, unsigned char guiFlags);
[0df3c9a]225
226 private:
[cefdf23]227
[c324d6a]228 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
229 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
230 VkDebugUtilsMessageTypeFlagsEXT messageType,
231 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
232 void* pUserData);
233
[cefdf23]234 // TODO: Maybe pass these in as parameters to some Camera class
[5ab1b20]235 const float NEAR_CLIP = 0.1f;
236 const float FAR_CLIP = 100.0f;
[cefdf23]237 const float FOV_ANGLE = 67.0f; // means the camera lens goes from -33 deg to 33 deg
[5ab1b20]238
[4a9416a]239 const int EXPLOSION_PARTICLE_COUNT = 300;
240 const vec3 LASER_COLOR = vec3(0.2f, 1.0f, 0.2f);
241
[c6f0793]242 bool done;
[e1f88a9]243
[15104a8]244 vec3 cam_pos;
245
[4e705d6]246 // TODO: Good place to start using smart pointers
[0df3c9a]247 GameGui* gui;
[c559904]248
249 SDL_version sdlVersion;
[b794178]250 SDL_Window* window = nullptr;
[c1d9b2a]251
[301c90a]252 int drawableWidth, drawableHeight;
253
[c1d9b2a]254 VkInstance instance;
255 VkDebugUtilsMessengerEXT debugMessenger;
[7865c5b]256 VkSurfaceKHR vulkanSurface;
[90a424f]257 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
[c1c2021]258 VkDevice device;
259
260 VkQueue graphicsQueue;
261 VkQueue presentQueue;
[0df3c9a]262
[3f32dfd]263 // TODO: Maybe make a swapchain struct for convenience
264 VkSurfaceFormatKHR swapChainSurfaceFormat;
265 VkPresentModeKHR swapChainPresentMode;
266 VkExtent2D swapChainExtent;
267 uint32_t swapChainMinImageCount;
[c324d6a]268 uint32_t swapChainImageCount;
[502bd0b]269 VkSwapchainKHR swapChain;
270 vector<VkImage> swapChainImages;
[f94eea9]271 vector<VkImageView> swapChainImageViews;
[603b5bc]272 vector<VkFramebuffer> swapChainFramebuffers;
[fa9fa1c]273
[6fc24c7]274 VkRenderPass renderPass;
[3f32dfd]275
276 VkCommandPool resourceCommandPool;
277
[9c0a614]278 vector<VkCommandPool> commandPools;
[603b5bc]279 vector<VkCommandBuffer> commandBuffers;
[502bd0b]280
[603b5bc]281 VulkanImage depthImage;
[b794178]282
[3f32dfd]283 // These are per frame
284 vector<VkSemaphore> imageAcquiredSemaphores;
285 vector<VkSemaphore> renderCompleteSemaphores;
286
287 // These are per swap chain image
[4e705d6]288 vector<VkFence> inFlightFences;
289
[3f32dfd]290 uint32_t imageIndex;
291 uint32_t currentFrame;
[4e705d6]292
[28ea92f]293 bool shouldRecreateSwapChain;
[4e705d6]294
[b794178]295 VkSampler textureSampler;
296
[4994692]297 VulkanImage floorTextureImage;
298 VkDescriptorImageInfo floorTextureImageDescriptor;
299
[237cbec]300 VulkanImage laserTextureImage;
301 VkDescriptorImageInfo laserTextureImageDescriptor;
302
[22217d4]303 mat4 viewMat, projMat;
304
[cefdf23]305 // Maybe at some point create an imgui pipeline class, but I don't think it makes sense right now
306 VkDescriptorPool imguiDescriptorPool;
307
308 // TODO: Probably restructure the GraphicsPipeline_Vulkan class based on what I learned about descriptors and textures
309 // while working on graphics-library. Double-check exactly what this was and note it down here.
310 // Basically, I think the point was that if I have several modesl that all use the same shaders and, therefore,
311 // the same pipeline, but use different textures, the approach I took when initially creating GraphicsPipeline_Vulkan
312 // wouldn't work since the whole pipeline couldn't have a common set of descriptors for the textures
[9d21aac]313 GraphicsPipeline_Vulkan<ModelVertex> modelPipeline;
314 GraphicsPipeline_Vulkan<ModelVertex> shipPipeline;
315 GraphicsPipeline_Vulkan<ModelVertex> asteroidPipeline;
316 GraphicsPipeline_Vulkan<LaserVertex> laserPipeline;
317 GraphicsPipeline_Vulkan<ExplosionVertex> explosionPipeline;
[cefdf23]318
[996dd3e]319 StorageBufferSet storageBuffers_modelPipeline;
[a3cefaa]320 VulkanBuffer<SSBO_ModelObject> objects_modelPipeline;
321
[996dd3e]322 StorageBufferSet storageBuffers_shipPipeline;
[a3cefaa]323 VulkanBuffer<SSBO_ModelObject> objects_shipPipeline;
324
[996dd3e]325 StorageBufferSet storageBuffers_asteroidPipeline;
[a3cefaa]326 VulkanBuffer<SSBO_Asteroid> objects_asteroidPipeline;
327
[996dd3e]328 StorageBufferSet storageBuffers_laserPipeline;
[a3cefaa]329 VulkanBuffer<SSBO_Laser> objects_laserPipeline;
330
[996dd3e]331 StorageBufferSet storageBuffers_explosionPipeline;
[a3cefaa]332 VulkanBuffer<SSBO_Explosion> objects_explosionPipeline;
[996dd3e]333
[860a0da]334 // TODO: Maybe make the ubo objects part of the pipeline class since there's only one ubo
335 // per pipeline.
336 // Or maybe create a higher level wrapper around GraphicsPipeline_Vulkan to hold things like
337 // the objects vector, the ubo, and the ssbo
338
[2ba5617]339 // TODO: Rename *_VP_mats to *_uniforms and possibly use different types for each one
340 // if there is a need to add other uniform variables to one or more of the shaders
341
[2d87297]342 vector<SceneObject<ModelVertex, SSBO_ModelObject>> modelObjects;
[0fe8433]343
[d25381b]344 vector<VkBuffer> uniformBuffers_modelPipeline;
345 vector<VkDeviceMemory> uniformBuffersMemory_modelPipeline;
346 vector<VkDescriptorBufferInfo> uniformBufferInfoList_modelPipeline;
[b794178]347
[0fe8433]348 UBO_VP_mats object_VP_mats;
349
[8d92284]350 vector<SceneObject<ModelVertex, SSBO_ModelObject>> shipObjects;
[0fe8433]351
[3782d66]352 vector<VkBuffer> uniformBuffers_shipPipeline;
353 vector<VkDeviceMemory> uniformBuffersMemory_shipPipeline;
354 vector<VkDescriptorBufferInfo> uniformBufferInfoList_shipPipeline;
355
[0fe8433]356 UBO_VP_mats ship_VP_mats;
[0e09340]357
[b8efa56]358 vector<SceneObject<ModelVertex, SSBO_Asteroid>> asteroidObjects;
[3e8cc8b]359
360 vector<VkBuffer> uniformBuffers_asteroidPipeline;
361 vector<VkDeviceMemory> uniformBuffersMemory_asteroidPipeline;
362 vector<VkDescriptorBufferInfo> uniformBufferInfoList_asteroidPipeline;
363
364 UBO_VP_mats asteroid_VP_mats;
365
[237cbec]366 vector<SceneObject<LaserVertex, SSBO_Laser>> laserObjects;
367
368 vector<VkBuffer> uniformBuffers_laserPipeline;
369 vector<VkDeviceMemory> uniformBuffersMemory_laserPipeline;
370 vector<VkDescriptorBufferInfo> uniformBufferInfoList_laserPipeline;
371
372 UBO_VP_mats laser_VP_mats;
373
[4a9416a]374 vector<SceneObject<ExplosionVertex, SSBO_Explosion>> explosionObjects;
375
376 vector<VkBuffer> uniformBuffers_explosionPipeline;
377 vector<VkDeviceMemory> uniformBuffersMemory_explosionPipeline;
378 vector<VkDescriptorBufferInfo> uniformBufferInfoList_explosionPipeline;
379
380 UBO_Explosion explosion_UBO;
381
[7297892]382 vector<BaseEffectOverTime*> effects;
383
[0807aeb]384 float shipSpeed = 0.5f;
385 float asteroidSpeed = 2.0f;
386
387 float spawnRate_asteroid = 0.5;
388 float lastSpawn_asteroid;
[4ece3bf]389
[1f81ecc]390 unsigned int leftLaserIdx = -1;
[b8efa56]391 EffectOverTime<ModelVertex, SSBO_Asteroid>* leftLaserEffect = nullptr;
[1f81ecc]392
393 unsigned int rightLaserIdx = -1;
[b8efa56]394 EffectOverTime<ModelVertex, SSBO_Asteroid>* rightLaserEffect = nullptr;
[1f81ecc]395
[20e4c2b]396 /*** High-level vars ***/
397
[301c90a]398 // TODO: Just typedef the type of this function to RenderScreenFn or something since it's used in a few places
399 void (VulkanGame::* currentRenderScreenFn)(int width, int height);
[20e4c2b]400
401 map<string, vector<UIValue>> valueLists;
402
403 int score;
404 float fps;
405
406 // TODO: Make a separate TImer class
407 time_point<steady_clock> startTime;
408 float fpsStartTime, curTime, prevTime, elapsedTime;
409
410 int frameCount;
411
412 /*** Functions ***/
413
[4e705d6]414 bool initUI(int width, int height, unsigned char guiFlags);
[0df3c9a]415 void initVulkan();
[f97c5e7]416 void initGraphicsPipelines();
[15104a8]417 void initMatrices();
[20e4c2b]418 void renderLoop();
[3f32dfd]419 void updateScene();
[0df3c9a]420 void cleanup();
[c1d9b2a]421
[c324d6a]422 void createVulkanInstance(const vector<const char*>& validationLayers);
[c1d9b2a]423 void setupDebugMessenger();
424 void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo);
[90a424f]425 void createVulkanSurface();
[fe5c3ba]426 void pickPhysicalDevice(const vector<const char*>& deviceExtensions);
[fa9fa1c]427 bool isDeviceSuitable(VkPhysicalDevice physicalDevice, const vector<const char*>& deviceExtensions);
[c324d6a]428 void createLogicalDevice(const vector<const char*>& validationLayers,
[c1c2021]429 const vector<const char*>& deviceExtensions);
[3f32dfd]430 void chooseSwapChainProperties();
[502bd0b]431 void createSwapChain();
[f94eea9]432 void createImageViews();
[3f32dfd]433 void createResourceCommandPool();
[603b5bc]434 void createImageResources();
[cefdf23]435 VkFormat findDepthFormat(); // TODO: Declare/define (in the cpp file) this function in some util functions section
436 void createRenderPass();
437 void createCommandPools();
[603b5bc]438 void createFramebuffers();
439 void createCommandBuffers();
[34bdf3a]440 void createSyncObjects();
[f94eea9]441
[3f32dfd]442 void createTextureSampler();
443
[cefdf23]444 void initImGuiOverlay();
445 void cleanupImGuiOverlay();
446
[9d21aac]447 // TODO: Maybe move these to a different class, possibly VulkanBuffer or some new related class
448
449 void createBufferSet(VkDeviceSize bufferSize, VkBufferUsageFlags flags, VkMemoryPropertyFlags properties,
450 vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory,
451 vector<VkDescriptorBufferInfo>& bufferInfoList);
452
453 // TODO: See if it makes sense to rename this to resizeBufferSet() and use it to resize other types of buffers as well
454 // TODO: Remove the need for templating, which is only there so a GraphicsPupeline_Vulkan can be passed in
455 template<class VertexType, class SSBOType>
[a3cefaa]456 void resizeStorageBufferSet(StorageBufferSet& set, VulkanBuffer<SSBOType>& buffer,
457 GraphicsPipeline_Vulkan<VertexType>& pipeline,
458 VkCommandPool commandPool, VkQueue graphicsQueue);
[9d21aac]459
460 template<class SSBOType>
461 void updateStorageBuffer(StorageBufferSet& storageBufferSet, size_t objIndex, SSBOType& ssbo);
[3b7d497]462
[4994692]463 // TODO: Since addObject() returns a reference to the new object now,
464 // stop using objects.back() to access the object that was just created
[2d87297]465 template<class VertexType, class SSBOType>
[9d21aac]466 SceneObject<VertexType, SSBOType>& addObject(vector<SceneObject<VertexType, SSBOType>>& objects,
467 GraphicsPipeline_Vulkan<VertexType>& pipeline,
468 const vector<VertexType>& vertices, vector<uint16_t> indices,
[a3cefaa]469 SSBOType ssbo, StorageBufferSet& storageBuffers);
[0fe8433]470
[cefdf23]471 template<class VertexType>
472 vector<VertexType> addObjectIndex(unsigned int objIndex, vector<VertexType> vertices);
473
474 template<class VertexType>
475 vector<VertexType> addVertexNormals(vector<VertexType> vertices);
476
477 template<class VertexType, class SSBOType>
478 void centerObject(SceneObject<VertexType, SSBOType>& object);
479
[2da64ef]480 template<class VertexType, class SSBOType>
481 void updateObject(vector<SceneObject<VertexType, SSBOType>>& objects,
[9d21aac]482 GraphicsPipeline_Vulkan<VertexType>& pipeline, size_t index);
[2da64ef]483
[1f81ecc]484 template<class VertexType, class SSBOType>
[9d21aac]485 void updateObjectVertices(GraphicsPipeline_Vulkan<VertexType>& pipeline,
[1f81ecc]486 SceneObject<VertexType, SSBOType>& obj, size_t index);
487
[52a02e6]488 void addLaser(vec3 start, vec3 end, vec3 color, float width);
489 void translateLaser(size_t index, const vec3& translation);
490 void updateLaserTarget(size_t index);
[b8efa56]491 bool getLaserAndAsteroidIntersection(SceneObject<ModelVertex, SSBO_Asteroid>& asteroid,
[52a02e6]492 vec3& start, vec3& end, vec3& intersection);
493
[4a9416a]494 void addExplosion(mat4 model_mat, float duration, float cur_time);
495
[ea2b4dc]496 void renderFrame(ImDrawData* draw_data);
[4e2c709]497 void presentFrame();
498
[d2d9286]499 void recreateSwapChain();
500
[c1c2021]501 void cleanupSwapChain();
[20e4c2b]502
503 /*** High-level functions ***/
504
[301c90a]505 void renderMainScreen(int width, int height);
506 void renderGameScreen(int width, int height);
[20e4c2b]507
508 void initGuiValueLists(map<string, vector<UIValue>>& valueLists);
509 void renderGuiValueList(vector<UIValue>& values);
510
[301c90a]511 void goToScreen(void (VulkanGame::* renderScreenFn)(int width, int height));
[20e4c2b]512 void quitGame();
[e8ebc76]513};
514
[4a9416a]515// Start of specialized no-op functions
516
517template<>
518inline void VulkanGame::centerObject(SceneObject<ExplosionVertex, SSBO_Explosion>& object) {
519}
520
521// End of specialized no-op functions
522
[9d21aac]523template<class VertexType, class SSBOType>
[a3cefaa]524void VulkanGame::resizeStorageBufferSet(StorageBufferSet& set, VulkanBuffer<SSBOType>& buffer,
525 GraphicsPipeline_Vulkan<VertexType>& pipeline,
526 VkCommandPool commandPool, VkQueue graphicsQueue) {
527 size_t numObjects = buffer.numObjects < buffer.capacity ? buffer.numObjects : buffer.capacity;
528
529 do {
530 buffer.capacity *= 2;
531 } while (buffer.capacity < buffer.numObjects);
532
533 VkDeviceSize bufferSize = buffer.capacity * sizeof(SSBOType);
[9d21aac]534
535 for (size_t i = 0; i < set.buffers.size(); i++) {
536 VkBuffer newStorageBuffer;
537 VkDeviceMemory newStorageBufferMemory;
538
539 VulkanUtils::createBuffer(device, physicalDevice, bufferSize,
540 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
541 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
542 newStorageBuffer, newStorageBufferMemory);
543
544 VulkanUtils::copyBuffer(device, commandPool, set.buffers[i], newStorageBuffer,
[a3cefaa]545 0, 0, numObjects * sizeof(SSBOType), graphicsQueue);
[9d21aac]546
547 vkDestroyBuffer(device, set.buffers[i], nullptr);
548 vkFreeMemory(device, set.memory[i], nullptr);
549
550 set.buffers[i] = newStorageBuffer;
551 set.memory[i] = newStorageBufferMemory;
552
553 set.infoSet[i].buffer = set.buffers[i];
554 set.infoSet[i].offset = 0; // This is the offset from the start of the buffer, so always 0 for now
555 set.infoSet[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
556 }
[a3cefaa]557
558 // Assume the SSBO is always the 2nd binding
559 // TODO: Figure out a way to make this more flexible
560 pipeline.updateDescriptorInfo(1, &set.infoSet, swapChainImages);
[9d21aac]561}
562
563// TODO: See if it makes sense to pass in the current swapchain index instead of updating all of them
564template<class SSBOType>
565void VulkanGame::updateStorageBuffer(StorageBufferSet& storageBufferSet, size_t objIndex, SSBOType& ssbo) {
566 for (size_t i = 0; i < storageBufferSet.memory.size(); i++) {
567 VulkanUtils::copyDataToMemory(device, ssbo, storageBufferSet.memory[i], objIndex * sizeof(SSBOType));
568 }
569}
570
[3b84bb6]571// TODO: Right now, it's basically necessary to pass the identity matrix in for ssbo.model
572// and to change the model matrix later by setting model_transform and then calling updateObject()
[9d21aac]573// Figure out a better way to allow the model matrix to be set during object creation
[2d87297]574template<class VertexType, class SSBOType>
[9d21aac]575SceneObject<VertexType, SSBOType>& VulkanGame::addObject(vector<SceneObject<VertexType, SSBOType>>& objects,
576 GraphicsPipeline_Vulkan<VertexType>& pipeline,
577 const vector<VertexType>& vertices, vector<uint16_t> indices,
[a3cefaa]578 SSBOType ssbo, StorageBufferSet& storageBuffers) {
[2ba5617]579 // TODO: Use the model field of ssbo to set the object's model_base
580 // currently, the passed in model is useless since it gets overridden in updateObject() anyway
[0fe8433]581 size_t numVertices = pipeline.getNumVertices();
582
583 for (uint16_t& idx : indices) {
584 idx += numVertices;
585 }
586
[5ba732a]587 objects.push_back({ vertices, indices, ssbo, mat4(1.0f), mat4(1.0f), false });
[3b84bb6]588
[2ba5617]589 SceneObject<VertexType, SSBOType>& obj = objects.back();
[1f81ecc]590
[cefdf23]591 // TODO: Specify whether to center the object outside of this function or, worst case, maybe
592 // with a boolean being passed in here, so that I don't have to rely on checking the specific object
593 // type
[4a9416a]594 if (!is_same_v<VertexType, LaserVertex> && !is_same_v<VertexType, ExplosionVertex>) {
[1f81ecc]595 centerObject(obj);
596 }
[2ba5617]597
[9d21aac]598 pipeline.addObject(obj.vertices, obj.indices, resourceCommandPool, graphicsQueue);
599
[4994692]600 return obj;
[0fe8433]601}
602
[cefdf23]603template<class VertexType>
604vector<VertexType> VulkanGame::addObjectIndex(unsigned int objIndex, vector<VertexType> vertices) {
605 for (VertexType& vertex : vertices) {
606 vertex.objIndex = objIndex;
607 }
[2da64ef]608
[cefdf23]609 return vertices;
[1f81ecc]610}
611
[914bb99]612// This function sets all the normals for a face to be parallel
613// This is good for models that should have distinct faces, but bad for models that should appear smooth
614// Maybe add an option to set all copies of a point to have the same normal and have the direction of
615// that normal be the weighted average of all the faces it is a part of, where the weight from each face
616// is its surface area.
617
618// TODO: Since the current approach to normal calculation basicaly makes indexed drawing useless, see if it's
619// feasible to automatically enable/disable indexed drawing based on which approach is used
[06d959f]620template<class VertexType>
621vector<VertexType> VulkanGame::addVertexNormals(vector<VertexType> vertices) {
622 for (unsigned int i = 0; i < vertices.size(); i += 3) {
623 vec3 p1 = vertices[i].pos;
[cefdf23]624 vec3 p2 = vertices[i + 1].pos;
625 vec3 p3 = vertices[i + 2].pos;
[06d959f]626
[a79be34]627 vec3 normal = normalize(cross(p2 - p1, p3 - p1));
[06d959f]628
629 // Add the same normal for all 3 vertices
630 vertices[i].normal = normal;
[cefdf23]631 vertices[i + 1].normal = normal;
632 vertices[i + 2].normal = normal;
[cf727ca]633 }
634
635 return vertices;
636}
637
[3b84bb6]638template<class VertexType, class SSBOType>
639void VulkanGame::centerObject(SceneObject<VertexType, SSBOType>& object) {
640 vector<VertexType>& vertices = object.vertices;
641
[a79be34]642 float min_x = vertices[0].pos.x;
643 float max_x = vertices[0].pos.x;
644 float min_y = vertices[0].pos.y;
645 float max_y = vertices[0].pos.y;
646 float min_z = vertices[0].pos.z;
647 float max_z = vertices[0].pos.z;
648
649 // start from the second point
650 for (unsigned int i = 1; i < vertices.size(); i++) {
[3b84bb6]651 vec3& pos = vertices[i].pos;
652
653 if (min_x > pos.x) {
654 min_x = pos.x;
655 } else if (max_x < pos.x) {
656 max_x = pos.x;
[a79be34]657 }
658
[3b84bb6]659 if (min_y > pos.y) {
660 min_y = pos.y;
661 } else if (max_y < pos.y) {
662 max_y = pos.y;
[a79be34]663 }
664
[3b84bb6]665 if (min_z > pos.z) {
666 min_z = pos.z;
667 } else if (max_z < pos.z) {
668 max_z = pos.z;
[a79be34]669 }
670 }
671
672 vec3 center = vec3(min_x + max_x, min_y + max_y, min_z + max_z) / 2.0f;
673
674 for (unsigned int i = 0; i < vertices.size(); i++) {
675 vertices[i].pos -= center;
676 }
677
[2ba5617]678 object.radius = std::max(max_x - center.x, max_y - center.y);
679 object.radius = std::max(object.radius, max_z - center.z);
680
[3b84bb6]681 object.center = vec3(0.0f, 0.0f, 0.0f);
[a79be34]682}
683
[cefdf23]684// TODO: Just pass in the single object instead of a list of all of them
685template<class VertexType, class SSBOType>
686void VulkanGame::updateObject(vector<SceneObject<VertexType, SSBOType>>& objects,
[9d21aac]687 GraphicsPipeline_Vulkan<VertexType>& pipeline, size_t index) {
[cefdf23]688 SceneObject<VertexType, SSBOType>& obj = objects[index];
689
690 obj.ssbo.model = obj.model_transform * obj.model_base;
691 obj.center = vec3(obj.ssbo.model * vec4(0.0f, 0.0f, 0.0f, 1.0f));
692
693 obj.modified = false;
694}
695
696template<class VertexType, class SSBOType>
[9d21aac]697void VulkanGame::updateObjectVertices(GraphicsPipeline_Vulkan<VertexType>& pipeline,
[cefdf23]698 SceneObject<VertexType, SSBOType>& obj, size_t index) {
699 pipeline.updateObjectVertices(index, obj.vertices, resourceCommandPool, graphicsQueue);
700}
701
[3b84bb6]702#endif // _VULKAN_GAME_H
Note: See TracBrowser for help on using the repository browser.