Changeset 4a777d2 in opengl-game


Ignore:
Timestamp:
Apr 11, 2021, 12:09:58 AM (3 years ago)
Author:
Dmitry Portnoy <dportnoy@…>
Branches:
feature/imgui-sdl
Children:
cb6fabb, e8445f0
Parents:
b8efa56
git-author:
Dmitry Portnoy <dportnoy@…> (04/11/21 00:09:49)
git-committer:
Dmitry Portnoy <dportnoy@…> (04/11/21 00:09:58)
Message:

Add the model pipeline and the spinning, textured squares to SDLGame

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sdl-game.cpp

    rb8efa56 r4a777d2  
    88
    99#include "logger.hpp"
     10#include "utils.hpp"
    1011
    1112#include "gui/imgui/button-imgui.hpp"
     
    8990   initImGuiOverlay();
    9091
     92   // TODO: Figure out how much of ubo creation and associated variables should be in the pipeline class
     93   // Maybe combine the ubo-related objects into a new class
     94
     95   initGraphicsPipelines();
     96
     97   initMatrices();
     98
     99   modelPipeline.addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&ModelVertex::pos));
     100   modelPipeline.addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&ModelVertex::color));
     101   modelPipeline.addAttribute(VK_FORMAT_R32G32_SFLOAT, offset_of(&ModelVertex::texCoord));
     102   modelPipeline.addAttribute(VK_FORMAT_R32G32B32_SFLOAT, offset_of(&ModelVertex::normal));
     103   modelPipeline.addAttribute(VK_FORMAT_R32_UINT, offset_of(&ModelVertex::objIndex));
     104
     105   createBufferSet(sizeof(UBO_VP_mats), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
     106      uniformBuffers_modelPipeline, uniformBuffersMemory_modelPipeline, uniformBufferInfoList_modelPipeline);
     107
     108   modelPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
     109      VK_SHADER_STAGE_VERTEX_BIT, &uniformBufferInfoList_modelPipeline);
     110   modelPipeline.addStorageDescriptor(VK_SHADER_STAGE_VERTEX_BIT);
     111   modelPipeline.addDescriptorInfo(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
     112      VK_SHADER_STAGE_FRAGMENT_BIT, &floorTextureImageDescriptor);
     113
     114   SceneObject<ModelVertex, SSBO_ModelObject>* texturedSquare = nullptr;
     115
     116   texturedSquare = &addObject(modelObjects, modelPipeline,
     117      addObjectIndex<ModelVertex>(modelObjects.size(),
     118         addVertexNormals<ModelVertex>({
     119            {{-0.5f, -0.5f,  0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, 0},
     120            {{ 0.5f, -0.5f,  0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, 0},
     121            {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0},
     122            {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0},
     123            {{-0.5f,  0.5f,  0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0},
     124            {{-0.5f, -0.5f,  0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, 0}
     125         })), {
     126            0, 1, 2, 3, 4, 5
     127      }, {
     128         mat4(1.0f)
     129      }, false);
     130
     131   texturedSquare->model_base =
     132      translate(mat4(1.0f), vec3(0.0f, 0.0f, -2.0f));
     133   texturedSquare->modified = true;
     134
     135   texturedSquare = &addObject(modelObjects, modelPipeline,
     136      addObjectIndex<ModelVertex>(modelObjects.size(),
     137         addVertexNormals<ModelVertex>({
     138            {{-0.5f, -0.5f,  0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}},
     139            {{ 0.5f, -0.5f,  0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}},
     140            {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
     141            {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}},
     142            {{-0.5f,  0.5f,  0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
     143            {{-0.5f, -0.5f,  0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}}
     144         })), {
     145            0, 1, 2, 3, 4, 5
     146      }, {
     147         mat4(1.0f)
     148      }, false);
     149
     150   texturedSquare->model_base =
     151      translate(mat4(1.0f), vec3(0.0f, 0.0f, -1.5f));
     152   texturedSquare->modified = true;
     153
     154   modelPipeline.createDescriptorSetLayout();
     155   modelPipeline.createPipeline("shaders/model-vert.spv", "shaders/model-frag.spv");
     156   modelPipeline.createDescriptorPool(swapChainImages);
     157   modelPipeline.createDescriptorSets(swapChainImages);
     158
    91159   currentRenderScreenFn = &VulkanGame::renderMainScreen;
    92160
     
    182250   createCommandBuffers();
    183251   createSyncObjects();
     252}
     253
     254void VulkanGame::initGraphicsPipelines() {
     255   modelPipeline = GraphicsPipeline_Vulkan<ModelVertex, SSBO_ModelObject>(
     256      VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, physicalDevice, device, renderPass,
     257      { 0, 0, (int)swapChainExtent.width, (int)swapChainExtent.height }, swapChainImages, 16, 24, 10);
     258}
     259
     260// TODO: Maybe change the name to initScene() or something similar
     261void VulkanGame::initMatrices() {
     262   cam_pos = vec3(0.0f, 0.0f, 2.0f);
     263
     264   float cam_yaw = 0.0f;
     265   float cam_pitch = -50.0f;
     266
     267   mat4 yaw_mat = rotate(mat4(1.0f), radians(-cam_yaw), vec3(0.0f, 1.0f, 0.0f));
     268   mat4 pitch_mat = rotate(mat4(1.0f), radians(-cam_pitch), vec3(1.0f, 0.0f, 0.0f));
     269
     270   mat4 R_view = pitch_mat * yaw_mat;
     271   mat4 T_view = translate(mat4(1.0f), vec3(-cam_pos.x, -cam_pos.y, -cam_pos.z));
     272   viewMat = R_view * T_view;
     273
     274   projMat = perspective(radians(FOV_ANGLE), (float)swapChainExtent.width / (float)swapChainExtent.height, NEAR_CLIP, FAR_CLIP);
     275   projMat[1][1] *= -1; // flip the y-axis so that +y is up
     276
     277   object_VP_mats.view = viewMat;
     278   object_VP_mats.proj = projMat;
    184279}
    185280
     
    241336               cout << "Window resize event detected" << endl;
    242337               shouldRecreateSwapChain = true;
     338               break;
     339            case UI_EVENT_KEYDOWN:
     340               if (e.key.repeat) {
     341                  break;
     342               }
     343
     344               if (e.key.keycode == SDL_SCANCODE_ESCAPE) {
     345                  done = true;
     346               } else if (e.key.keycode == SDL_SCANCODE_SPACE) {
     347                  cout << "Adding a plane" << endl;
     348                  float zOffset = -2.0f + (0.5f * modelObjects.size());
     349
     350                  SceneObject<ModelVertex, SSBO_ModelObject>& texturedSquare =
     351                     addObject(modelObjects, modelPipeline,
     352                        addObjectIndex<ModelVertex>(modelObjects.size(),
     353                           addVertexNormals<ModelVertex>({
     354                              {{-0.5f, -0.5f,  0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, 0},
     355                              {{ 0.5f, -0.5f,  0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, 0},
     356                              {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0},
     357                              {{ 0.5f,  0.5f,  0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0},
     358                              {{-0.5f,  0.5f,  0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0},
     359                              {{-0.5f, -0.5f,  0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, 0}
     360                           })), {
     361                              0, 1, 2, 3, 4, 5
     362                        }, {
     363                           mat4(1.0f)
     364                        }, true);
     365
     366                  texturedSquare.model_base =
     367                     translate(mat4(1.0f), vec3(0.0f, 0.0f, zOffset));
     368                  texturedSquare.modified = true;
     369               // START UNREVIEWED SECTION
     370               // END UNREVIEWED SECTION
     371               } else {
     372                  cout << "Key event detected" << endl;
     373               }
    243374               break;
    244375            case UI_EVENT_KEYUP:
     
    277408      }
    278409
     410      updateScene();
     411
    279412      // TODO: Move this into a renderImGuiOverlay() function
    280413      ImGui_ImplVulkan_NewFrame();
     
    296429}
    297430
     431// TODO: The only updates that need to happen once per Vulkan image are the SSBO ones,
     432// which are already handled by updateObject(). Move this code to a different place,
     433// where it will run just once per frame
     434void VulkanGame::updateScene() {
     435   for (SceneObject<ModelVertex, SSBO_ModelObject>& model : this->modelObjects) {
     436      model.model_transform =
     437         translate(mat4(1.0f), vec3(0.0f, -2.0f, -0.0f)) *
     438         rotate(mat4(1.0f), curTime * radians(90.0f), vec3(0.0f, 0.0f, 1.0f));
     439      model.modified = true;
     440   }
     441
     442   for (size_t i = 0; i < modelObjects.size(); i++) {
     443      if (modelObjects[i].modified) {
     444         updateObject(modelObjects, modelPipeline, i);
     445      }
     446   }
     447
     448   VulkanUtils::copyDataToMemory(device, uniformBuffersMemory_modelPipeline[imageIndex], 0, object_VP_mats);
     449}
     450
    298451void VulkanGame::cleanup() {
    299452   // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)
     
    304457
    305458   cleanupSwapChain();
     459
     460   VulkanUtils::destroyVulkanImage(device, floorTextureImage);
     461   // START UNREVIEWED SECTION
     462
     463   vkDestroySampler(device, textureSampler, nullptr);
     464
     465   modelPipeline.cleanupBuffers();
     466
     467   // END UNREVIEWED SECTION
    306468
    307469   vkDestroyCommandPool(device, resourceCommandPool, nullptr);
     
    638800   VulkanUtils::createDepthImage(device, physicalDevice, resourceCommandPool, findDepthFormat(), swapChainExtent,
    639801      depthImage, graphicsQueue);
     802
     803   createTextureSampler();
     804
     805   // TODO: Move all images/textures somewhere into the assets folder
     806
     807   VulkanUtils::createVulkanImageFromFile(device, physicalDevice, resourceCommandPool, "textures/texture.jpg",
     808      floorTextureImage, graphicsQueue);
     809
     810   floorTextureImageDescriptor = {};
     811   floorTextureImageDescriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
     812   floorTextureImageDescriptor.imageView = floorTextureImage.imageView;
     813   floorTextureImageDescriptor.sampler = textureSampler;
    640814}
    641815
     
    726900      }
    727901   }
     902}
     903
     904void VulkanGame::createTextureSampler() {
     905   VkSamplerCreateInfo samplerInfo = {};
     906   samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
     907   samplerInfo.magFilter = VK_FILTER_LINEAR;
     908   samplerInfo.minFilter = VK_FILTER_LINEAR;
     909
     910   samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
     911   samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
     912   samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
     913
     914   samplerInfo.anisotropyEnable = VK_TRUE;
     915   samplerInfo.maxAnisotropy = 16;
     916   samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
     917   samplerInfo.unnormalizedCoordinates = VK_FALSE;
     918   samplerInfo.compareEnable = VK_FALSE;
     919   samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
     920   samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
     921   samplerInfo.mipLodBias = 0.0f;
     922   samplerInfo.minLod = 0.0f;
     923   samplerInfo.maxLod = 0.0f;
     924
     925   VKUTIL_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler),
     926      "failed to create texture sampler!");
    728927}
    729928
     
    8811080}
    8821081
     1082void VulkanGame::createBufferSet(VkDeviceSize bufferSize, VkBufferUsageFlags flags,
     1083                                 vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory,
     1084                                 vector<VkDescriptorBufferInfo>& bufferInfoList) {
     1085   buffers.resize(swapChainImageCount);
     1086   buffersMemory.resize(swapChainImageCount);
     1087   bufferInfoList.resize(swapChainImageCount);
     1088
     1089   for (size_t i = 0; i < swapChainImageCount; i++) {
     1090      VulkanUtils::createBuffer(device, physicalDevice, bufferSize, flags,
     1091         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
     1092         buffers[i], buffersMemory[i]);
     1093
     1094      bufferInfoList[i].buffer = buffers[i];
     1095      bufferInfoList[i].offset = 0; // This is the offset from the start of the buffer, so always 0 for now
     1096      bufferInfoList[i].range = bufferSize; // Size of the update starting from offset, or VK_WHOLE_SIZE
     1097   }
     1098}
     1099
    8831100void VulkanGame::renderFrame(ImDrawData* draw_data) {
    8841101   VkResult result = vkAcquireNextImageKHR(device, swapChain, numeric_limits<uint64_t>::max(),
     
    9261143
    9271144   vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
     1145
     1146   // TODO: Find a more elegant, per-screen solution for this
     1147   if (currentRenderScreenFn == &VulkanGame::renderGameScreen) {
     1148      modelPipeline.createRenderCommands(commandBuffers[imageIndex], imageIndex);
     1149
     1150
     1151
     1152
     1153   }
    9281154
    9291155   ImGui_ImplVulkan_RenderDrawData(draw_data, commandBuffers[imageIndex]);
     
    9991225   createSyncObjects();
    10001226
    1001    // TODO: Update pipelines here
     1227   // TODO: Move UBO creation/management into GraphicsPipeline_Vulkan, like I did with SSBOs
     1228   // TODO: Check if the shader stages and maybe some other properties of the pipeline can be re-used
     1229   // instead of recreated every time
     1230
     1231   createBufferSet(sizeof(UBO_VP_mats), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
     1232      uniformBuffers_modelPipeline, uniformBuffersMemory_modelPipeline, uniformBufferInfoList_modelPipeline);
     1233
     1234   modelPipeline.updateRenderPass(renderPass);
     1235   modelPipeline.createPipeline("shaders/model-vert.spv", "shaders/model-frag.spv");
     1236   modelPipeline.createDescriptorPool(swapChainImages);
     1237   modelPipeline.createDescriptorSets(swapChainImages);
    10021238
    10031239   imageIndex = 0;
     
    10141250      vkFreeCommandBuffers(device, commandPools[i], 1, &commandBuffers[i]);
    10151251      vkDestroyCommandPool(device, commandPools[i], nullptr);
     1252   }
     1253
     1254   modelPipeline.cleanup();
     1255
     1256   for (size_t i = 0; i < uniformBuffers_modelPipeline.size(); i++) {
     1257      vkDestroyBuffer(device, uniformBuffers_modelPipeline[i], nullptr);
     1258      vkFreeMemory(device, uniformBuffersMemory_modelPipeline[i], nullptr);
    10161259   }
    10171260
  • sdl-game.hpp

    rb8efa56 r4a777d2  
    1010#include <SDL2/SDL.h>
    1111
     12#define GLM_FORCE_RADIANS
     13#define GLM_FORCE_DEPTH_ZERO_TO_ONE // Since, in Vulkan, the depth range is 0 to 1 instead of -1 to 1
     14#define GLM_FORCE_RIGHT_HANDED
     15
     16#include <glm/glm.hpp>
     17#include <glm/gtc/matrix_transform.hpp>
     18
    1219#include "IMGUI/imgui_impl_vulkan.h"
    1320
    1421#include "consts.hpp"
    1522#include "vulkan-utils.hpp"
    16 
     23#include "graphics-pipeline_vulkan.hpp"
    1724#include "game-gui-sdl.hpp"
    1825
     26using namespace glm;
    1927using namespace std;
    2028using namespace std::chrono;
     
    2836#endif
    2937
     38// TODO: Consider if there is a better way of dealing with all the vertex types and ssbo types, maybe
     39// by consolidating some and trying to keep new ones to a minimum
     40
     41struct ModelVertex {
     42   vec3 pos;
     43   vec3 color;
     44   vec2 texCoord;
     45   vec3 normal;
     46   unsigned int objIndex;
     47};
     48
     49struct LaserVertex {
     50   vec3 pos;
     51   vec2 texCoord;
     52   unsigned int objIndex;
     53};
     54
     55struct ExplosionVertex {
     56   vec3 particleStartVelocity;
     57   float particleStartTime;
     58   unsigned int objIndex;
     59};
     60
     61struct SSBO_ModelObject {
     62   alignas(16) mat4 model;
     63};
     64
     65struct SSBO_Asteroid {
     66   alignas(16) mat4 model;
     67   alignas(4) float hp;
     68   alignas(4) unsigned int deleted;
     69};
     70
     71struct UBO_VP_mats {
     72   alignas(16) mat4 view;
     73   alignas(16) mat4 proj;
     74};
     75
     76// TODO: Change the index type to uint32_t and check the Vulkan Tutorial loading model section as a reference
     77// TODO: Create a typedef for index type so I can easily change uin16_t to something else later
     78// TODO: Maybe create a typedef for each of the templated SceneObject types
     79template<class VertexType, class SSBOType>
     80struct SceneObject {
     81   vector<VertexType> vertices;
     82   vector<uint16_t> indices;
     83   SSBOType ssbo;
     84
     85   mat4 model_base;
     86   mat4 model_transform;
     87
     88   bool modified;
     89
     90   // TODO: Figure out if I should make child classes that have these fields instead of putting them in the
     91   // parent class
     92   vec3 center; // currently only matters for asteroids
     93   float radius; // currently only matters for asteroids
     94   SceneObject<ModelVertex, SSBO_Asteroid>* targetAsteroid; // currently only used for lasers
     95};
     96
     97// TODO: Have to figure out how to include an optional ssbo parameter for each object
     98// Could probably use the same approach to make indices optional
     99// Figure out if there are sufficient use cases to make either of these optional or is it fine to make
     100// them mamdatory
     101
     102
     103// TODO: Look into using dynamic_cast to check types of SceneObject and EffectOverTime
     104
    30105// TODO: Maybe move this to a different header
    31106
     
    60135         void* pUserData);
    61136
     137      // TODO: Maybe pass these in as parameters to some Camera class
     138      const float NEAR_CLIP = 0.1f;
     139      const float FAR_CLIP = 100.0f;
     140      const float FOV_ANGLE = 67.0f; // means the camera lens goes from -33 deg to 33 deg
     141
    62142      bool done;
     143
     144      vec3 cam_pos;
    63145
    64146      // TODO: Good place to start using smart pointers
     
    110192      bool shouldRecreateSwapChain;
    111193
     194      VkSampler textureSampler;
     195
     196      VulkanImage floorTextureImage;
     197      VkDescriptorImageInfo floorTextureImageDescriptor;
     198
     199      mat4 viewMat, projMat;
     200
    112201      // Maybe at some point create an imgui pipeline class, but I don't think it makes sense right now
    113202      VkDescriptorPool imguiDescriptorPool;
     203
     204      // TODO: Probably restructure the GraphicsPipeline_Vulkan class based on what I learned about descriptors and textures
     205      // while working on graphics-library. Double-check exactly what this was and note it down here.
     206      // Basically, I think the point was that if I have several models that all use the same shaders and, therefore,
     207      // the same pipeline, but use different textures, the approach I took when initially creating GraphicsPipeline_Vulkan
     208      // wouldn't work since the whole pipeline couldn't have a common set of descriptors for the textures
     209      GraphicsPipeline_Vulkan<ModelVertex, SSBO_ModelObject> modelPipeline;
     210
     211      // TODO: Maybe make the ubo objects part of the pipeline class since there's only one ubo
     212      // per pipeline.
     213      // Or maybe create a higher level wrapper around GraphicsPipeline_Vulkan to hold things like
     214      // the objects vector, the ubo, and the ssbo
     215
     216      // TODO: Rename *_VP_mats to *_uniforms and possibly use different types for each one
     217      // if there is a need to add other uniform variables to one or more of the shaders
     218
     219      vector<SceneObject<ModelVertex, SSBO_ModelObject>> modelObjects;
     220
     221      vector<VkBuffer> uniformBuffers_modelPipeline;
     222      vector<VkDeviceMemory> uniformBuffersMemory_modelPipeline;
     223      vector<VkDescriptorBufferInfo> uniformBufferInfoList_modelPipeline;
     224
     225      UBO_VP_mats object_VP_mats;
    114226
    115227      /*** High-level vars ***/
     
    133245      bool initUI(int width, int height, unsigned char guiFlags);
    134246      void initVulkan();
     247      void initGraphicsPipelines();
     248      void initMatrices();
    135249      void renderLoop();
     250      void updateScene();
    136251      void cleanup();
    137252
     
    156271      void createSyncObjects();
    157272
     273      void createTextureSampler();
     274
    158275      void initImGuiOverlay();
    159276      void cleanupImGuiOverlay();
    160277
     278      void createBufferSet(VkDeviceSize bufferSize, VkBufferUsageFlags flags,
     279         vector<VkBuffer>& buffers, vector<VkDeviceMemory>& buffersMemory,
     280         vector<VkDescriptorBufferInfo>& bufferInfoList);
     281
     282      // TODO: Since addObject() returns a reference to the new object now,
     283      // stop using objects.back() to access the object that was just created
     284      template<class VertexType, class SSBOType>
     285      SceneObject<VertexType, SSBOType>& addObject(
     286         vector<SceneObject<VertexType, SSBOType>>& objects,
     287         GraphicsPipeline_Vulkan<VertexType, SSBOType>& pipeline,
     288         const vector<VertexType>& vertices, vector<uint16_t> indices, SSBOType ssbo,
     289         bool pipelinesCreated);
     290
     291      template<class VertexType>
     292      vector<VertexType> addObjectIndex(unsigned int objIndex, vector<VertexType> vertices);
     293
     294      template<class VertexType>
     295      vector<VertexType> addVertexNormals(vector<VertexType> vertices);
     296
     297      template<class VertexType, class SSBOType>
     298      void centerObject(SceneObject<VertexType, SSBOType>& object);
     299
     300      template<class VertexType, class SSBOType>
     301      void updateObject(vector<SceneObject<VertexType, SSBOType>>& objects,
     302         GraphicsPipeline_Vulkan<VertexType, SSBOType>& pipeline, size_t index);
     303
    161304      void renderFrame(ImDrawData* draw_data);
    162305      void presentFrame();
     
    178321};
    179322
     323// TODO: Right now, it's basically necessary to pass the identity matrix in for ssbo.model
     324// and to change the model matrix later by setting model_transform and then calling updateObject()
     325// Figure out a better way to allow the model matrix to be set during objecting creation
     326
     327// TODO: Maybe return a reference to the object from this method if I decide that updating it
     328// immediately after creation is a good idea (such as setting model_base)
     329// Currently, model_base is set like this in a few places and the radius is set for asteroids
     330// to account for scaling
     331template<class VertexType, class SSBOType>
     332SceneObject<VertexType, SSBOType>& VulkanGame::addObject(
     333   vector<SceneObject<VertexType, SSBOType>>& objects,
     334   GraphicsPipeline_Vulkan<VertexType, SSBOType>& pipeline,
     335   const vector<VertexType>& vertices, vector<uint16_t> indices, SSBOType ssbo,
     336   bool pipelinesCreated) {
     337   // TODO: Use the model field of ssbo to set the object's model_base
     338   // currently, the passed in model is useless since it gets overridden in updateObject() anyway
     339   size_t numVertices = pipeline.getNumVertices();
     340
     341   for (uint16_t& idx : indices) {
     342      idx += numVertices;
     343   }
     344
     345   objects.push_back({ vertices, indices, ssbo, mat4(1.0f), mat4(1.0f), false });
     346
     347   SceneObject<VertexType, SSBOType>& obj = objects.back();
     348
     349   // TODO: Specify whether to center the object outside of this function or, worst case, maybe
     350   // with a boolean being passed in here, so that I don't have to rely on checking the specific object
     351   // type
     352   if (!is_same_v<VertexType, LaserVertex> && !is_same_v<VertexType, ExplosionVertex>) {
     353      centerObject(obj);
     354   }
     355
     356   bool storageBufferResized = pipeline.addObject(obj.vertices, obj.indices, obj.ssbo,
     357      resourceCommandPool, graphicsQueue);
     358
     359   if (pipelinesCreated) {
     360      vkDeviceWaitIdle(device);
     361
     362      for (uint32_t i = 0; i < swapChainImageCount; i++) {
     363         vkFreeCommandBuffers(device, commandPools[i], 1, &commandBuffers[i]);
     364      }
     365
     366      // TODO: The pipeline recreation only has to be done once per frame where at least
     367      // one SSBO is resized.
     368      // Refactor the logic to check for any resized SSBOs after all objects for the frame
     369      // are created and then recreate each of the corresponding pipelines only once per frame
     370      if (storageBufferResized) {
     371         pipeline.createPipeline(pipeline.vertShaderFile, pipeline.fragShaderFile);
     372         pipeline.createDescriptorPool(swapChainImages);
     373         pipeline.createDescriptorSets(swapChainImages);
     374      }
     375
     376      createCommandBuffers();
     377   }
     378
     379   return obj;
     380}
     381
     382template<class VertexType>
     383vector<VertexType> VulkanGame::addObjectIndex(unsigned int objIndex, vector<VertexType> vertices) {
     384   for (VertexType& vertex : vertices) {
     385      vertex.objIndex = objIndex;
     386   }
     387
     388   return vertices;
     389}
     390
     391template<class VertexType>
     392vector<VertexType> VulkanGame::addVertexNormals(vector<VertexType> vertices) {
     393   for (unsigned int i = 0; i < vertices.size(); i += 3) {
     394      vec3 p1 = vertices[i].pos;
     395      vec3 p2 = vertices[i + 1].pos;
     396      vec3 p3 = vertices[i + 2].pos;
     397
     398      vec3 normal = normalize(cross(p2 - p1, p3 - p1));
     399
     400      // Add the same normal for all 3 vertices
     401      vertices[i].normal = normal;
     402      vertices[i + 1].normal = normal;
     403      vertices[i + 2].normal = normal;
     404   }
     405
     406   return vertices;
     407}
     408
     409template<class VertexType, class SSBOType>
     410void VulkanGame::centerObject(SceneObject<VertexType, SSBOType>& object) {
     411   vector<VertexType>& vertices = object.vertices;
     412
     413   float min_x = vertices[0].pos.x;
     414   float max_x = vertices[0].pos.x;
     415   float min_y = vertices[0].pos.y;
     416   float max_y = vertices[0].pos.y;
     417   float min_z = vertices[0].pos.z;
     418   float max_z = vertices[0].pos.z;
     419
     420   // start from the second point
     421   for (unsigned int i = 1; i < vertices.size(); i++) {
     422      vec3& pos = vertices[i].pos;
     423
     424      if (min_x > pos.x) {
     425         min_x = pos.x;
     426      }
     427      else if (max_x < pos.x) {
     428         max_x = pos.x;
     429      }
     430
     431      if (min_y > pos.y) {
     432         min_y = pos.y;
     433      }
     434      else if (max_y < pos.y) {
     435         max_y = pos.y;
     436      }
     437
     438      if (min_z > pos.z) {
     439         min_z = pos.z;
     440      }
     441      else if (max_z < pos.z) {
     442         max_z = pos.z;
     443      }
     444   }
     445
     446   vec3 center = vec3(min_x + max_x, min_y + max_y, min_z + max_z) / 2.0f;
     447
     448   for (unsigned int i = 0; i < vertices.size(); i++) {
     449      vertices[i].pos -= center;
     450   }
     451
     452   object.radius = std::max(max_x - center.x, max_y - center.y);
     453   object.radius = std::max(object.radius, max_z - center.z);
     454
     455   object.center = vec3(0.0f, 0.0f, 0.0f);
     456}
     457
     458// TODO: Just pass in the single object instead of a list of all of them
     459template<class VertexType, class SSBOType>
     460void VulkanGame::updateObject(vector<SceneObject<VertexType, SSBOType>>& objects,
     461   GraphicsPipeline_Vulkan<VertexType, SSBOType>& pipeline, size_t index) {
     462   SceneObject<VertexType, SSBOType>& obj = objects[index];
     463
     464   obj.ssbo.model = obj.model_transform * obj.model_base;
     465   obj.center = vec3(obj.ssbo.model * vec4(0.0f, 0.0f, 0.0f, 1.0f));
     466
     467   pipeline.updateObject(index, obj.ssbo);
     468
     469   obj.modified = false;
     470}
     471
    180472#endif // _SDL_GAME_H
Note: See TracChangeset for help on using the changeset viewer.