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@…>, 3 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
Line 
1#ifndef _VULKAN_GAME_H
2#define _VULKAN_GAME_H
3
4#include <algorithm>
5#include <chrono>
6#include <map>
7#include <vector>
8
9#include <vulkan/vulkan.h>
10
11#include <SDL2/SDL.h>
12#include <SDL2/SDL_ttf.h>
13
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
16#define GLM_FORCE_RIGHT_HANDED
17
18#include <glm/glm.hpp>
19#include <glm/gtc/matrix_transform.hpp>
20
21#include "IMGUI/imgui_impl_vulkan.h"
22
23#include "consts.hpp"
24#include "utils.hpp"
25#include "vulkan-utils.hpp"
26#include "vulkan-buffer.hpp"
27#include "graphics-pipeline_vulkan.hpp"
28#include "game-gui-sdl.hpp"
29
30using namespace glm;
31using namespace std::chrono;
32
33#ifdef NDEBUG
34 const bool ENABLE_VALIDATION_LAYERS = false;
35#else
36 const bool ENABLE_VALIDATION_LAYERS = true;
37#endif
38
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
42struct OverlayVertex {
43 vec3 pos;
44 vec2 texCoord;
45};
46
47struct ModelVertex {
48 vec3 pos;
49 vec3 color;
50 vec2 texCoord;
51 vec3 normal;
52 unsigned int objIndex;
53};
54
55struct LaserVertex {
56 vec3 pos;
57 vec2 texCoord;
58 unsigned int objIndex;
59};
60
61struct ExplosionVertex {
62 vec3 particleStartVelocity;
63 float particleStartTime;
64 unsigned int objIndex;
65};
66
67struct SSBO_ModelObject {
68 alignas(16) mat4 model;
69};
70
71struct SSBO_Asteroid {
72 alignas(16) mat4 model;
73 alignas(4) float hp;
74 alignas(4) unsigned int deleted;
75};
76
77struct SSBO_Laser {
78 alignas(16) mat4 model;
79 alignas(4) vec3 color;
80 alignas(4) unsigned int deleted;
81};
82
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
90struct UBO_VP_mats {
91 alignas(16) mat4 view;
92 alignas(16) mat4 proj;
93};
94
95struct UBO_Explosion {
96 alignas(16) mat4 view;
97 alignas(16) mat4 proj;
98 alignas(4) float cur_time;
99};
100
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
104// TODO: Maybe change the structure here since VkDescriptorBufferInfo already stores a reference to the VkBuffer
105struct BufferSet {
106 vector<VkBuffer> buffers;
107 vector<VkDeviceMemory> memory;
108 vector<VkDescriptorBufferInfo> infoSet;
109};
110
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
123 bool modified;
124
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
129 SceneObject<ModelVertex, SSBO_Asteroid>* targetAsteroid; // currently only used for lasers
130};
131
132// TODO: Have to figure out how to include an optional ssbo parameter for each object
133// Could probably use the same approach to make indices optional
134// Figure out if there are sufficient use cases to make either of these optional or is it fine to make
135// them mamdatory
136
137
138// TODO: Look into using dynamic_cast to check types of SceneObject and EffectOverTime
139
140struct BaseEffectOverTime {
141 bool deleted;
142
143 virtual void applyEffect(float curTime) = 0;
144
145 BaseEffectOverTime() :
146 deleted(false) {
147 }
148
149 virtual ~BaseEffectOverTime() {
150 }
151};
152
153template<class VertexType, class SSBOType>
154struct EffectOverTime : public BaseEffectOverTime {
155 GraphicsPipeline_Vulkan<VertexType>& pipeline;
156 vector<SceneObject<VertexType, SSBOType>>& objects;
157 unsigned int objectIndex;
158 size_t effectedFieldOffset;
159 float startValue;
160 float startTime;
161 float changePerSecond;
162
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) {
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
179 void applyEffect(float curTime) {
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
196// TODO: Maybe move this to a different header
197
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
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
217class VulkanGame {
218
219 public:
220
221 VulkanGame();
222 ~VulkanGame();
223
224 void run(int width, int height, unsigned char guiFlags);
225
226 private:
227
228 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
229 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
230 VkDebugUtilsMessageTypeFlagsEXT messageType,
231 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
232 void* pUserData);
233
234 // TODO: Maybe pass these in as parameters to some Camera class
235 const float NEAR_CLIP = 0.1f;
236 const float FAR_CLIP = 100.0f;
237 const float FOV_ANGLE = 67.0f; // means the camera lens goes from -33 deg to 33 deg
238
239 const int EXPLOSION_PARTICLE_COUNT = 300;
240 const vec3 LASER_COLOR = vec3(0.2f, 1.0f, 0.2f);
241
242 bool done;
243
244 vec3 cam_pos;
245
246 // TODO: Good place to start using smart pointers
247 GameGui* gui;
248
249 SDL_version sdlVersion;
250 SDL_Window* window = nullptr;
251
252 int drawableWidth, drawableHeight;
253
254 VkInstance instance;
255 VkDebugUtilsMessengerEXT debugMessenger;
256 VkSurfaceKHR vulkanSurface;
257 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
258 VkDevice device;
259
260 VkQueue graphicsQueue;
261 VkQueue presentQueue;
262
263 // TODO: Maybe make a swapchain struct for convenience
264 VkSurfaceFormatKHR swapChainSurfaceFormat;
265 VkPresentModeKHR swapChainPresentMode;
266 VkExtent2D swapChainExtent;
267 uint32_t swapChainMinImageCount;
268 uint32_t swapChainImageCount;
269 VkSwapchainKHR swapChain;
270 vector<VkImage> swapChainImages;
271 vector<VkImageView> swapChainImageViews;
272 vector<VkFramebuffer> swapChainFramebuffers;
273
274 VkRenderPass renderPass;
275
276 VkCommandPool resourceCommandPool;
277
278 vector<VkCommandPool> commandPools;
279 vector<VkCommandBuffer> commandBuffers;
280
281 VulkanImage depthImage;
282
283 // These are per frame
284 vector<VkSemaphore> imageAcquiredSemaphores;
285 vector<VkSemaphore> renderCompleteSemaphores;
286
287 // These are per swap chain image
288 vector<VkFence> inFlightFences;
289
290 uint32_t imageIndex;
291 uint32_t currentFrame;
292
293 bool shouldRecreateSwapChain;
294
295 VkSampler textureSampler;
296
297 VulkanImage floorTextureImage;
298 VkDescriptorImageInfo floorTextureImageDescriptor;
299
300 VulkanImage laserTextureImage;
301 VkDescriptorImageInfo laserTextureImageDescriptor;
302
303 mat4 viewMat, projMat;
304
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
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;
318
319 BufferSet storageBuffers_modelPipeline;
320 VulkanBuffer<SSBO_ModelObject> objects_modelPipeline;
321
322 BufferSet storageBuffers_shipPipeline;
323 VulkanBuffer<SSBO_ModelObject> objects_shipPipeline;
324
325 BufferSet storageBuffers_asteroidPipeline;
326 VulkanBuffer<SSBO_Asteroid> objects_asteroidPipeline;
327
328 BufferSet storageBuffers_laserPipeline;
329 VulkanBuffer<SSBO_Laser> objects_laserPipeline;
330
331 BufferSet storageBuffers_explosionPipeline;
332 VulkanBuffer<SSBO_Explosion> objects_explosionPipeline;
333
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
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
342 vector<SceneObject<ModelVertex, SSBO_ModelObject>> modelObjects;
343
344 vector<VkBuffer> uniformBuffers_modelPipeline;
345 vector<VkDeviceMemory> uniformBuffersMemory_modelPipeline;
346 vector<VkDescriptorBufferInfo> uniformBufferInfoList_modelPipeline;
347
348 UBO_VP_mats object_VP_mats;
349
350 vector<SceneObject<ModelVertex, SSBO_ModelObject>> shipObjects;
351
352 vector<VkBuffer> uniformBuffers_shipPipeline;
353 vector<VkDeviceMemory> uniformBuffersMemory_shipPipeline;
354 vector<VkDescriptorBufferInfo> uniformBufferInfoList_shipPipeline;
355
356 UBO_VP_mats ship_VP_mats;
357
358 vector<SceneObject<ModelVertex, SSBO_Asteroid>> asteroidObjects;
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
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
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
382 vector<BaseEffectOverTime*> effects;
383
384 float shipSpeed = 0.5f;
385 float asteroidSpeed = 2.0f;
386
387 float spawnRate_asteroid = 0.5;
388 float lastSpawn_asteroid;
389
390 unsigned int leftLaserIdx = -1;
391 EffectOverTime<ModelVertex, SSBO_Asteroid>* leftLaserEffect = nullptr;
392
393 unsigned int rightLaserIdx = -1;
394 EffectOverTime<ModelVertex, SSBO_Asteroid>* rightLaserEffect = nullptr;
395
396 /*** High-level vars ***/
397
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);
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
414 bool initUI(int width, int height, unsigned char guiFlags);
415 void initVulkan();
416 void initGraphicsPipelines();
417 void initMatrices();
418 void renderLoop();
419 void updateScene();
420 void cleanup();
421
422 void createVulkanInstance(const vector<const char*>& validationLayers);
423 void setupDebugMessenger();
424 void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo);
425 void createVulkanSurface();
426 void pickPhysicalDevice(const vector<const char*>& deviceExtensions);
427 bool isDeviceSuitable(VkPhysicalDevice physicalDevice, const vector<const char*>& deviceExtensions);
428 void createLogicalDevice(const vector<const char*>& validationLayers,
429 const vector<const char*>& deviceExtensions);
430 void chooseSwapChainProperties();
431 void createSwapChain();
432 void createImageViews();
433 void createResourceCommandPool();
434 void createImageResources();
435 VkFormat findDepthFormat(); // TODO: Declare/define (in the cpp file) this function in some util functions section
436 void createRenderPass();
437 void createCommandPools();
438 void createFramebuffers();
439 void createCommandBuffers();
440 void createSyncObjects();
441
442 void createTextureSampler();
443
444 void initImGuiOverlay();
445 void cleanupImGuiOverlay();
446
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>
456 void resizeBufferSet(BufferSet& set, VulkanBuffer<SSBOType>& buffer,
457 GraphicsPipeline_Vulkan<VertexType>& pipeline, VkCommandPool commandPool,
458 VkQueue graphicsQueue);
459
460 template<class SSBOType>
461 void updateBufferSet(BufferSet& set, size_t objIndex, SSBOType& ssbo);
462
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
465 template<class VertexType, class SSBOType>
466 SceneObject<VertexType, SSBOType>& addObject(vector<SceneObject<VertexType, SSBOType>>& objects,
467 GraphicsPipeline_Vulkan<VertexType>& pipeline,
468 const vector<VertexType>& vertices, vector<uint16_t> indices,
469 SSBOType ssbo);
470
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
480 template<class VertexType, class SSBOType>
481 void updateObject(SceneObject<VertexType, SSBOType>& obj);
482
483 template<class VertexType, class SSBOType>
484 void updateObjectVertices(GraphicsPipeline_Vulkan<VertexType>& pipeline,
485 SceneObject<VertexType, SSBOType>& obj, size_t index);
486
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);
490 bool getLaserAndAsteroidIntersection(SceneObject<ModelVertex, SSBO_Asteroid>& asteroid,
491 vec3& start, vec3& end, vec3& intersection);
492
493 void addExplosion(mat4 model_mat, float duration, float cur_time);
494
495 void renderFrame(ImDrawData* draw_data);
496 void presentFrame();
497
498 void recreateSwapChain();
499
500 void cleanupSwapChain();
501
502 /*** High-level functions ***/
503
504 void renderMainScreen(int width, int height);
505 void renderGameScreen(int width, int height);
506
507 void initGuiValueLists(map<string, vector<UIValue>>& valueLists);
508 void renderGuiValueList(vector<UIValue>& values);
509
510 void goToScreen(void (VulkanGame::* renderScreenFn)(int width, int height));
511 void quitGame();
512};
513
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
522template<class VertexType, class SSBOType>
523void VulkanGame::resizeBufferSet(BufferSet& set, VulkanBuffer<SSBOType>& buffer,
524 GraphicsPipeline_Vulkan<VertexType>& pipeline, VkCommandPool commandPool,
525 VkQueue graphicsQueue) {
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);
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,
544 0, 0, numObjects * sizeof(SSBOType), graphicsQueue);
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 }
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);
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>
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));
567 }
568}
569
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()
572// Figure out a better way to allow the model matrix to be set during object creation
573template<class VertexType, class SSBOType>
574SceneObject<VertexType, SSBOType>& VulkanGame::addObject(vector<SceneObject<VertexType, SSBOType>>& objects,
575 GraphicsPipeline_Vulkan<VertexType>& pipeline,
576 const vector<VertexType>& vertices, vector<uint16_t> indices,
577 SSBOType ssbo) {
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
580 size_t numVertices = pipeline.getNumVertices();
581
582 for (uint16_t& idx : indices) {
583 idx += numVertices;
584 }
585
586 objects.push_back({ vertices, indices, ssbo, mat4(1.0f), mat4(1.0f), false });
587
588 SceneObject<VertexType, SSBOType>& obj = objects.back();
589
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
593 if (!is_same_v<VertexType, LaserVertex> && !is_same_v<VertexType, ExplosionVertex>) {
594 centerObject(obj);
595 }
596
597 pipeline.addObject(obj.vertices, obj.indices, resourceCommandPool, graphicsQueue);
598
599 return obj;
600}
601
602template<class VertexType>
603vector<VertexType> VulkanGame::addObjectIndex(unsigned int objIndex, vector<VertexType> vertices) {
604 for (VertexType& vertex : vertices) {
605 vertex.objIndex = objIndex;
606 }
607
608 return vertices;
609}
610
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
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;
623 vec3 p2 = vertices[i + 1].pos;
624 vec3 p3 = vertices[i + 2].pos;
625
626 vec3 normal = normalize(cross(p2 - p1, p3 - p1));
627
628 // Add the same normal for all 3 vertices
629 vertices[i].normal = normal;
630 vertices[i + 1].normal = normal;
631 vertices[i + 2].normal = normal;
632 }
633
634 return vertices;
635}
636
637template<class VertexType, class SSBOType>
638void VulkanGame::centerObject(SceneObject<VertexType, SSBOType>& object) {
639 vector<VertexType>& vertices = object.vertices;
640
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++) {
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;
656 }
657
658 if (min_y > pos.y) {
659 min_y = pos.y;
660 } else if (max_y < pos.y) {
661 max_y = pos.y;
662 }
663
664 if (min_z > pos.z) {
665 min_z = pos.z;
666 } else if (max_z < pos.z) {
667 max_z = pos.z;
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
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
680 object.center = vec3(0.0f, 0.0f, 0.0f);
681}
682
683// TODO: Just pass in the single object instead of a list of all of them
684template<class VertexType, class SSBOType>
685void VulkanGame::updateObject(SceneObject<VertexType, SSBOType>& obj) {
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>
693void VulkanGame::updateObjectVertices(GraphicsPipeline_Vulkan<VertexType>& pipeline,
694 SceneObject<VertexType, SSBOType>& obj, size_t index) {
695 pipeline.updateObjectVertices(index, obj.vertices, resourceCommandPool, graphicsQueue);
696}
697
698#endif // _VULKAN_GAME_H
Note: See TracBrowser for help on using the repository browser.