source: opengl-game/vulkan-game.hpp@ 1abebc1

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

Remove the storageBuffers parameter from addObject() since it is no longer used, rename StorageBufferSet, resizeStorageBufferSet(), and updateStorageuffer() to BufferSet, resizeBufferSet(), and updateBufferSet() respectively, and change updateObject() to just take a SceneObject reference.

  • Property mode set to 100644
File size: 23.9 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
[1abebc1]105struct BufferSet {
[996dd3e]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
[1abebc1]319 BufferSet storageBuffers_modelPipeline;
[a3cefaa]320 VulkanBuffer<SSBO_ModelObject> objects_modelPipeline;
321
[1abebc1]322 BufferSet storageBuffers_shipPipeline;
[a3cefaa]323 VulkanBuffer<SSBO_ModelObject> objects_shipPipeline;
324
[1abebc1]325 BufferSet storageBuffers_asteroidPipeline;
[a3cefaa]326 VulkanBuffer<SSBO_Asteroid> objects_asteroidPipeline;
327
[1abebc1]328 BufferSet storageBuffers_laserPipeline;
[a3cefaa]329 VulkanBuffer<SSBO_Laser> objects_laserPipeline;
330
[1abebc1]331 BufferSet 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>
[1abebc1]456 void resizeBufferSet(BufferSet& set, VulkanBuffer<SSBOType>& buffer,
457 GraphicsPipeline_Vulkan<VertexType>& pipeline, VkCommandPool commandPool,
458 VkQueue graphicsQueue);
[9d21aac]459
460 template<class SSBOType>
[1abebc1]461 void updateBufferSet(BufferSet& set, 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,
[1abebc1]469 SSBOType ssbo);
[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>
[1abebc1]481 void updateObject(SceneObject<VertexType, SSBOType>& obj);
[2da64ef]482
[1f81ecc]483 template<class VertexType, class SSBOType>
[9d21aac]484 void updateObjectVertices(GraphicsPipeline_Vulkan<VertexType>& pipeline,
[1f81ecc]485 SceneObject<VertexType, SSBOType>& obj, size_t index);
486
[52a02e6]487 void addLaser(vec3 start, vec3 end, vec3 color, float width);
488 void translateLaser(size_t index, const vec3& translation);
489 void updateLaserTarget(size_t index);
[b8efa56]490 bool getLaserAndAsteroidIntersection(SceneObject<ModelVertex, SSBO_Asteroid>& asteroid,
[52a02e6]491 vec3& start, vec3& end, vec3& intersection);
492
[4a9416a]493 void addExplosion(mat4 model_mat, float duration, float cur_time);
494
[ea2b4dc]495 void renderFrame(ImDrawData* draw_data);
[4e2c709]496 void presentFrame();
497
[d2d9286]498 void recreateSwapChain();
499
[c1c2021]500 void cleanupSwapChain();
[20e4c2b]501
502 /*** High-level functions ***/
503
[301c90a]504 void renderMainScreen(int width, int height);
505 void renderGameScreen(int width, int height);
[20e4c2b]506
507 void initGuiValueLists(map<string, vector<UIValue>>& valueLists);
508 void renderGuiValueList(vector<UIValue>& values);
509
[301c90a]510 void goToScreen(void (VulkanGame::* renderScreenFn)(int width, int height));
[20e4c2b]511 void quitGame();
[e8ebc76]512};
513
[4a9416a]514// Start of specialized no-op functions
515
516template<>
517inline void VulkanGame::centerObject(SceneObject<ExplosionVertex, SSBO_Explosion>& object) {
518}
519
520// End of specialized no-op functions
521
[9d21aac]522template<class VertexType, class SSBOType>
[1abebc1]523void VulkanGame::resizeBufferSet(BufferSet& set, VulkanBuffer<SSBOType>& buffer,
524 GraphicsPipeline_Vulkan<VertexType>& pipeline, VkCommandPool commandPool,
525 VkQueue graphicsQueue) {
[a3cefaa]526 size_t numObjects = buffer.numObjects < buffer.capacity ? buffer.numObjects : buffer.capacity;
527
528 do {
529 buffer.capacity *= 2;
530 } while (buffer.capacity < buffer.numObjects);
531
532 VkDeviceSize bufferSize = buffer.capacity * sizeof(SSBOType);
[9d21aac]533
534 for (size_t i = 0; i < set.buffers.size(); i++) {
535 VkBuffer newStorageBuffer;
536 VkDeviceMemory newStorageBufferMemory;
537
538 VulkanUtils::createBuffer(device, physicalDevice, bufferSize,
539 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
540 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
541 newStorageBuffer, newStorageBufferMemory);
542
543 VulkanUtils::copyBuffer(device, commandPool, set.buffers[i], newStorageBuffer,
[a3cefaa]544 0, 0, numObjects * sizeof(SSBOType), graphicsQueue);
[9d21aac]545
546 vkDestroyBuffer(device, set.buffers[i], nullptr);
547 vkFreeMemory(device, set.memory[i], nullptr);
548
549 set.buffers[i] = newStorageBuffer;
550 set.memory[i] = newStorageBufferMemory;
551
552 set.infoSet[i].buffer = set.buffers[i];
553 set.infoSet[i].offset = 0; // This is the offset from the start of the buffer, so always 0 for now
554 set.infoSet[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
555 }
[a3cefaa]556
557 // Assume the SSBO is always the 2nd binding
558 // TODO: Figure out a way to make this more flexible
559 pipeline.updateDescriptorInfo(1, &set.infoSet, swapChainImages);
[9d21aac]560}
561
562// TODO: See if it makes sense to pass in the current swapchain index instead of updating all of them
563template<class SSBOType>
[1abebc1]564void VulkanGame::updateBufferSet(BufferSet& set, size_t objIndex, SSBOType& ssbo) {
565 for (size_t i = 0; i < set.memory.size(); i++) {
566 VulkanUtils::copyDataToMemory(device, ssbo, set.memory[i], objIndex * sizeof(SSBOType));
[9d21aac]567 }
568}
569
[3b84bb6]570// TODO: Right now, it's basically necessary to pass the identity matrix in for ssbo.model
571// and to change the model matrix later by setting model_transform and then calling updateObject()
[9d21aac]572// Figure out a better way to allow the model matrix to be set during object creation
[2d87297]573template<class VertexType, class SSBOType>
[9d21aac]574SceneObject<VertexType, SSBOType>& VulkanGame::addObject(vector<SceneObject<VertexType, SSBOType>>& objects,
575 GraphicsPipeline_Vulkan<VertexType>& pipeline,
576 const vector<VertexType>& vertices, vector<uint16_t> indices,
[1abebc1]577 SSBOType ssbo) {
[2ba5617]578 // TODO: Use the model field of ssbo to set the object's model_base
579 // currently, the passed in model is useless since it gets overridden in updateObject() anyway
[0fe8433]580 size_t numVertices = pipeline.getNumVertices();
581
582 for (uint16_t& idx : indices) {
583 idx += numVertices;
584 }
585
[5ba732a]586 objects.push_back({ vertices, indices, ssbo, mat4(1.0f), mat4(1.0f), false });
[3b84bb6]587
[2ba5617]588 SceneObject<VertexType, SSBOType>& obj = objects.back();
[1f81ecc]589
[cefdf23]590 // TODO: Specify whether to center the object outside of this function or, worst case, maybe
591 // with a boolean being passed in here, so that I don't have to rely on checking the specific object
592 // type
[4a9416a]593 if (!is_same_v<VertexType, LaserVertex> && !is_same_v<VertexType, ExplosionVertex>) {
[1f81ecc]594 centerObject(obj);
595 }
[2ba5617]596
[9d21aac]597 pipeline.addObject(obj.vertices, obj.indices, resourceCommandPool, graphicsQueue);
598
[4994692]599 return obj;
[0fe8433]600}
601
[cefdf23]602template<class VertexType>
603vector<VertexType> VulkanGame::addObjectIndex(unsigned int objIndex, vector<VertexType> vertices) {
604 for (VertexType& vertex : vertices) {
605 vertex.objIndex = objIndex;
606 }
[2da64ef]607
[cefdf23]608 return vertices;
[1f81ecc]609}
610
[914bb99]611// This function sets all the normals for a face to be parallel
612// This is good for models that should have distinct faces, but bad for models that should appear smooth
613// Maybe add an option to set all copies of a point to have the same normal and have the direction of
614// that normal be the weighted average of all the faces it is a part of, where the weight from each face
615// is its surface area.
616
617// TODO: Since the current approach to normal calculation basicaly makes indexed drawing useless, see if it's
618// feasible to automatically enable/disable indexed drawing based on which approach is used
[06d959f]619template<class VertexType>
620vector<VertexType> VulkanGame::addVertexNormals(vector<VertexType> vertices) {
621 for (unsigned int i = 0; i < vertices.size(); i += 3) {
622 vec3 p1 = vertices[i].pos;
[cefdf23]623 vec3 p2 = vertices[i + 1].pos;
624 vec3 p3 = vertices[i + 2].pos;
[06d959f]625
[a79be34]626 vec3 normal = normalize(cross(p2 - p1, p3 - p1));
[06d959f]627
628 // Add the same normal for all 3 vertices
629 vertices[i].normal = normal;
[cefdf23]630 vertices[i + 1].normal = normal;
631 vertices[i + 2].normal = normal;
[cf727ca]632 }
633
634 return vertices;
635}
636
[3b84bb6]637template<class VertexType, class SSBOType>
638void VulkanGame::centerObject(SceneObject<VertexType, SSBOType>& object) {
639 vector<VertexType>& vertices = object.vertices;
640
[a79be34]641 float min_x = vertices[0].pos.x;
642 float max_x = vertices[0].pos.x;
643 float min_y = vertices[0].pos.y;
644 float max_y = vertices[0].pos.y;
645 float min_z = vertices[0].pos.z;
646 float max_z = vertices[0].pos.z;
647
648 // start from the second point
649 for (unsigned int i = 1; i < vertices.size(); i++) {
[3b84bb6]650 vec3& pos = vertices[i].pos;
651
652 if (min_x > pos.x) {
653 min_x = pos.x;
654 } else if (max_x < pos.x) {
655 max_x = pos.x;
[a79be34]656 }
657
[3b84bb6]658 if (min_y > pos.y) {
659 min_y = pos.y;
660 } else if (max_y < pos.y) {
661 max_y = pos.y;
[a79be34]662 }
663
[3b84bb6]664 if (min_z > pos.z) {
665 min_z = pos.z;
666 } else if (max_z < pos.z) {
667 max_z = pos.z;
[a79be34]668 }
669 }
670
671 vec3 center = vec3(min_x + max_x, min_y + max_y, min_z + max_z) / 2.0f;
672
673 for (unsigned int i = 0; i < vertices.size(); i++) {
674 vertices[i].pos -= center;
675 }
676
[2ba5617]677 object.radius = std::max(max_x - center.x, max_y - center.y);
678 object.radius = std::max(object.radius, max_z - center.z);
679
[3b84bb6]680 object.center = vec3(0.0f, 0.0f, 0.0f);
[a79be34]681}
682
[cefdf23]683// TODO: Just pass in the single object instead of a list of all of them
684template<class VertexType, class SSBOType>
[1abebc1]685void VulkanGame::updateObject(SceneObject<VertexType, SSBOType>& obj) {
[cefdf23]686 obj.ssbo.model = obj.model_transform * obj.model_base;
687 obj.center = vec3(obj.ssbo.model * vec4(0.0f, 0.0f, 0.0f, 1.0f));
688
689 obj.modified = false;
690}
691
692template<class VertexType, class SSBOType>
[9d21aac]693void VulkanGame::updateObjectVertices(GraphicsPipeline_Vulkan<VertexType>& pipeline,
[cefdf23]694 SceneObject<VertexType, SSBOType>& obj, size_t index) {
695 pipeline.updateObjectVertices(index, obj.vertices, resourceCommandPool, graphicsQueue);
696}
697
[3b84bb6]698#endif // _VULKAN_GAME_H
Note: See TracBrowser for help on using the repository browser.