#include "pch.h" #include "Renderer.h" #include "Mesh.h" #include "Utils.h" #include "Texture.h" #include "Effects/Effect.h" #include "Effects/FireEffect.h" #include "HitTest.h" #include "Scenes/MainScene.h" #include "Scenes/DioramaScene.h" #include "Scenes/InstancedScene.h" #include "Scenes/PlanetScene.h" namespace dae { Renderer::Renderer(SDL_Window *pWindow) : m_pWindow(pWindow) { //Initialize SDL_GetWindowSize(pWindow, &m_Width, &m_Height); //Initialize DirectX pipeline const HRESULT result = InitializeDirectX(); if (result == S_OK) { m_IsInitialized = true; std::cout << GREEN << "DirectX is initialized and ready!" << RESET << std::endl; } else { std::cout << RED << "DirectX initialization failed!" << RESET << std::endl; } //Best camera positions (Sorry for the magic numbers) m_SceneCameraPositions[SceneNames::Main] = {Vector3{0.f, 0.f, 0.f}, Vector3{0.f, 0.f, 0.f}}; m_SceneCameraPositions[SceneNames::Diorama] = {Vector3{48.88f, 23.0f, -3.3f}, Vector3{-0.23f, 4.79f, 0}}; m_SceneCameraPositions[SceneNames::Instanced] = {Vector3{11.8f, 12.4f, 12.9f}, Vector3{-0.30f, 0.76f, 0.f}}; m_SceneCameraPositions[SceneNames::Planet] = {Vector3{-18.5f, 10.5f, -15.7f}, Vector3{-0.46f, 0.86f, 0}}; InitializeSDLRasterizer(); m_pScene = std::make_unique(); m_pScene->Initialize(m_DevicePtr, m_DeviceContextPtr, nullptr); if (!m_pScene->GetMeshes().empty()) { m_pFireMesh = m_pScene->GetMeshes().back().get(); } const float aspectRatio = static_cast(m_Width) / static_cast(m_Height); m_Camera = Camera({.0f, .0f, .0f}, 45.f); m_Camera.Initialize(45.f, {.0f, .0f, .0f}, aspectRatio); } Renderer::~Renderer() { m_RenderTargetViewPtr->Release(); m_RenderTargetBufferPtr->Release(); m_DepthStencilViewPtr->Release(); m_DepthStencilBufferPtr->Release(); m_SwapChainPtr->Release(); if (m_DeviceContextPtr) { m_DeviceContextPtr->ClearState(); m_DeviceContextPtr->Flush(); m_DeviceContextPtr->Release(); } m_DevicePtr->Release(); m_pScene->Cleanup(); //SDL SDL_FreeSurface(m_pBackBuffer); SDL_FreeSurface(m_pFrontBuffer); delete[] m_pDepthBufferPixels; } void Renderer::Update(const Timer *pTimer) { m_Camera.Update(pTimer); for (auto& mesh: m_pScene->GetMeshes()) { mesh->SetCameraPos(m_Camera.GetPosition()); } if (m_Rotating) { float rotationThisFrame = pTimer->GetElapsed() * (45.0f * TO_RADIANS); // 45 degrees/sec to radians/sec m_currentRotation += rotationThisFrame; Matrix rotationMatrix = Matrix::CreateRotationY(rotationThisFrame); for (auto& mesh: m_pScene->GetMeshes()) { Matrix originalWorldMatrix = mesh->GetWorldMatrix(); Matrix world = rotationMatrix * originalWorldMatrix; mesh->SetWorldMatrix(world); } } m_pScene->Update(); } void Renderer::Render() { if (!m_IsInitialized) return; if (m_backendType == Backendtype::DirectX) { this->RenderDirectX(); } else { this->RenderSDL(); } } void Renderer::RenderDirectX() const { //Clear back buffer ColorRGB ChosenClearColor = m_UseUniformClearColor ? m_UniformClearColor : DirectXClearColor; const float clearColor[] = {static_cast(ChosenClearColor.r) / 255.f, static_cast(ChosenClearColor.g) / 255.f, static_cast(ChosenClearColor.b) / 255.f, 1.f}; m_DeviceContextPtr->ClearRenderTargetView(m_RenderTargetViewPtr, clearColor); m_DeviceContextPtr->ClearDepthStencilView(m_DepthStencilViewPtr, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); Matrix viewProjMatrix = m_Camera.GetViewProjectionMatrix(); for (auto& mesh: m_pScene->GetMeshes()) { if (mesh->GetShouldRender()) { Matrix modelMatrix = mesh->GetWorldMatrix(); Matrix worldViewProjMatrix = modelMatrix * viewProjMatrix; mesh->Render(m_DeviceContextPtr, worldViewProjMatrix); } } m_pScene->Render(m_DeviceContextPtr, m_RenderTargetViewPtr, m_DepthStencilViewPtr, m_Camera); //Present m_SwapChainPtr->Present(0, 0); } void Renderer::RenderSDL() { ColorRGB ChosenClearColor = m_UseUniformClearColor ? m_UniformClearColor : m_ClearColorSoftware; SDL_FillRect(m_pBackBuffer, nullptr, SDL_MapRGB(m_pBackBuffer->format, ChosenClearColor.r, ChosenClearColor.g, ChosenClearColor.b)); SDL_LockSurface(m_pBackBuffer); std::fill_n(m_pDepthBufferPixels, m_Width * m_Height, std::numeric_limits::max()); ColorRGB finalColor{}; constexpr int numVerticies = 3; m_VerticiesScreenSpace.clear(); for (auto& currentMesh: m_pScene->GetMeshes()) { if (!currentMesh->GetShouldRender()) { continue; } const Matrix worldViewProjectionMatrix{currentMesh->GetWorldMatrix() * m_Camera.GetViewProjectionMatrix()}; VertexTransformationFunction(worldViewProjectionMatrix, currentMesh.get(), currentMesh->GetVertices(), m_VerticiesScreenSpace); int numTriangles{}; switch (currentMesh->GetPrimitiveTopology()) { case PrimitiveTopology::TriangleList: numTriangles = static_cast(currentMesh->GetIndices().size()) / numVerticies; break; case PrimitiveTopology::TriangleStrip: numTriangles = static_cast(currentMesh->GetIndices().size()) - 2; break; } for (int triangleIndex{}; triangleIndex < numTriangles; ++triangleIndex) { VertexOut vertex0, vertex1, vertex2; switch (currentMesh->GetPrimitiveTopology()) { case PrimitiveTopology::TriangleList: vertex0 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex * numVerticies + 0]]; vertex1 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex * numVerticies + 1]]; vertex2 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex * numVerticies + 2]]; break; case PrimitiveTopology::TriangleStrip: vertex0 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex + 0]]; vertex1 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex + 1]]; vertex2 = m_VerticiesScreenSpace[currentMesh->GetIndices()[triangleIndex + 2]]; if (triangleIndex % 2 == 1) { std::swap(vertex1, vertex2); } if (vertex0.position == vertex1.position || vertex0.position == vertex2.position || vertex1.position == vertex2.position) { continue; } break; } if (!vertex0.valid and !vertex1.valid and !vertex2.valid) { continue; } const float minX{std::min(vertex0.position.x, std::min(vertex1.position.x, vertex2.position.x))}; const float minY{std::min(vertex0.position.y, std::min(vertex1.position.y, vertex2.position.y))}; const float maxX{std::max(vertex0.position.x, std::max(vertex1.position.x, vertex2.position.x))}; const float maxY{std::max(vertex0.position.y, std::max(vertex1.position.y, vertex2.position.y))}; const Vector3 side1{vertex1.position - vertex0.position}; const Vector3 side2{vertex2.position - vertex0.position}; const float totalArea{Vector3::Cross(side1, side2).z}; const int startX = std::max(0, static_cast(minX)) - 1; const int endX = std::min(m_Width - 1, static_cast(maxX)) + 1; const int startY = std::max(0, static_cast(minY)) - 1; const int endY = std::min(m_Height - 1, static_cast(maxY)) + 1; for (int px{startX}; px < endX; ++px) { for (int py{startY}; py < endY; ++py) { if (m_isHitbox) { //Hitboxes m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format, static_cast(255), static_cast(255), static_cast(255)); continue; } if (px < 0 || px >= m_Width || py < 0 || py >= m_Height) { //TEMP fix for out of bounds //This is to remove triangles having an incorrect edge on their bounding box continue; } Vector3 P{static_cast(px) + 0.5f, static_cast(py) + 0.5f, 1.f}; auto sample{TriangleHitTest(P, vertex0, vertex1, vertex2)}; if (!sample.has_value()) { continue; } const Vector3 fragPos{static_cast(px) + 0.5f, static_cast(py) + 0.5f, 1.f}; int depthBufferIndex{px + (py * m_Width)}; float min{.985f}; float max{1.f}; float depthBuffer{(sample.value().depth - min) * (max - min)}; float currentDepth = sample.value().depth; if (m_pDepthBufferPixels[depthBufferIndex] > currentDepth) { m_pDepthBufferPixels[depthBufferIndex] = currentDepth; if (m_isDepthBuffer) { finalColor = ColorRGB{depthBuffer, depthBuffer, depthBuffer}; } else { finalColor = ShadePixel(sample.value()); } finalColor.MaxToOne(); m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format, static_cast(finalColor.r * 255), static_cast(finalColor.g * 255), static_cast(finalColor.b * 255)); } } } } } SDL_UnlockSurface(m_pBackBuffer); SDL_BlitSurface(m_pBackBuffer, nullptr, m_pFrontBuffer, nullptr); SDL_UpdateWindowSurface(m_pWindow); } HRESULT Renderer::InitializeDirectX() { //1. Create device & deviceContext //===== D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_1; uint32_t createDeviceFlags = 0; #if defined(DEBUG) || defined(_DEBUG) createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif HRESULT result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, &featureLevel, 1, D3D11_SDK_VERSION, &m_DevicePtr, nullptr, &m_DeviceContextPtr); if (FAILED(result)) return result; //Create DXGI factory IDXGIFactory1 *DxgiFactoryPtr{}; result = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&DxgiFactoryPtr)); if (FAILED(result)) return result; //2. Create swap chain //===== DXGI_SWAP_CHAIN_DESC swapChainDesc{}; swapChainDesc.BufferDesc.Width = m_Width; swapChainDesc.BufferDesc.Height = m_Height; swapChainDesc.BufferDesc.RefreshRate.Numerator = 1; swapChainDesc.BufferDesc.RefreshRate.Denominator = 60; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.Windowed = true; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.Flags = 0; //Get the handle (HWND) from the SDL back buffer SDL_SysWMinfo sysWMInfo{}; SDL_GetVersion(&sysWMInfo.version); SDL_GetWindowWMInfo(m_pWindow, &sysWMInfo); swapChainDesc.OutputWindow = sysWMInfo.info.win.window; //Create SwapChain result = DxgiFactoryPtr->CreateSwapChain(m_DevicePtr, &swapChainDesc, &m_SwapChainPtr); if (FAILED(result)) return result; //3. Create depthStencil (DS) & DepthStencilView (DSV) //===== //Resource D3D11_TEXTURE2D_DESC depthStencilDesc{}; depthStencilDesc.Width = m_Width; depthStencilDesc.Height = m_Height; depthStencilDesc.MipLevels = 1; depthStencilDesc.ArraySize = 1; depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilDesc.SampleDesc.Count = 1; depthStencilDesc.SampleDesc.Quality = 0; depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; //View D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc{}; depthStencilViewDesc.Format = depthStencilDesc.Format; depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; depthStencilViewDesc.Texture2D.MipSlice = 0; result = m_DevicePtr->CreateTexture2D(&depthStencilDesc, nullptr, &m_DepthStencilBufferPtr); if (FAILED(result)) return result; result = m_DevicePtr->CreateDepthStencilView(m_DepthStencilBufferPtr, &depthStencilViewDesc, &m_DepthStencilViewPtr); if (FAILED(result)) return result; //.4 Create RenderTarget (RT) & RenderTargetView (RTV) //Resource result = m_SwapChainPtr->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&m_RenderTargetBufferPtr)); if (FAILED(result)) return result; //View result = m_DevicePtr->CreateRenderTargetView(m_RenderTargetBufferPtr, nullptr, &m_RenderTargetViewPtr); if (FAILED(result)) return result; //5. Bind RTV & DSV to output Merger stage //===== m_DeviceContextPtr->OMSetRenderTargets(1, &m_RenderTargetViewPtr, m_DepthStencilViewPtr); //6. Set Viewport //===== D3D11_VIEWPORT viewport{}; viewport.Width = static_cast(m_Width); viewport.Height = static_cast(m_Height); viewport.TopLeftX = 0.f; viewport.TopLeftY = 0.f; viewport.MinDepth = 0.f; viewport.MaxDepth = 1.f; m_DeviceContextPtr->RSSetViewports(1, &viewport); return S_OK; } void Renderer::InitializeSDLRasterizer() { m_pFrontBuffer = SDL_GetWindowSurface(m_pWindow); m_pBackBuffer = SDL_CreateRGBSurface(0, m_Width, m_Height, 32, 0, 0, 0, 0); m_pBackBufferPixels = (uint32_t *) m_pBackBuffer->pixels; m_pDepthBufferPixels = new float[m_Width * m_Height]; } void Renderer::VertexTransformationFunction(const Matrix &WorldViewProjectionMatrix, Mesh *mesh, std::vector &vertices_in, std::vector &vertices_out) const { for (const VertexIn &vert: vertices_in) { VertexOut vertex_out{}; Vector4 vertPos{WorldViewProjectionMatrix.TransformPoint({vert.position, 1})}; const Vector3 normal{mesh->GetWorldMatrix().TransformVector(vert.normal).Normalized()}; const Vector3 tangent{mesh->GetWorldMatrix().TransformVector(vert.tangent).Normalized()}; vertPos.x /= vertPos.w; vertPos.y /= vertPos.w; vertPos.z /= vertPos.w; bool isValid{true}; //Check if the vertex is inside the screen if (vertPos.x < -1.f || vertPos.x > 1.f || vertPos.y < -1.f || vertPos.y > 1.f || vertPos.z < 0.f || vertPos.z > 1.f) isValid = false; vertPos.x = ((vertPos.x + 1.f) / 2.f) * static_cast(m_Width); vertPos.y = ((1.f - vertPos.y) / 2.f) * static_cast(m_Height); vertex_out.position = vertPos; vertex_out.uv = vert.uv; vertex_out.normal = normal; vertex_out.tangent = tangent; vertex_out.mesh = mesh; vertex_out.valid = isValid; vertex_out.viewDir = (mesh->GetWorldMatrix().TransformPoint(vertex_out.position) - m_Camera.GetPosition().ToPoint4()).Normalized().GetXYZ(); vertices_out.push_back(vertex_out); } } void Renderer::ToggleDepthBuffer() { m_isDepthBuffer = !m_isDepthBuffer; std::string mode = m_isDepthBuffer ? "ON" : "OFF"; std::cout << MAGENTA << "[SOFTWARE]" << BLUE << " Depth Buffer " << mode << RESET << std::endl; } ColorRGB Renderer::ShadePixel(const Sample &sample) { Material *currentMaterial = sample.mesh->GetMaterial(); if (currentMaterial->normalTexturePtr == nullptr && currentMaterial->specularTexturePtr == nullptr && currentMaterial->glossTexturePtr == nullptr) { return currentMaterial->diffuseTexturePtr->Sample(sample.uv); } Vector3 lightDirection = {.577f, -.577f, .577f}; Vector3 normal = sample.normal.Normalized(); constexpr float lightIntensity{7.f}; ColorRGB color{1, 1, 1}; constexpr ColorRGB ambient{.03f, .03f, .03f}; if (m_useNormals) { const Vector3 biNormal{Vector3::Cross(normal, sample.tangent)}; const Matrix tangentToWorld{ sample.tangent, biNormal, normal, {0.f, 0.f, 0.f} }; const ColorRGB normalSample{sample.mesh->GetMaterial()->normalTexturePtr->Sample(sample.uv)}; Vector4 normalMapSample{ 2.f * normalSample.r - 1.f, 2.f * normalSample.g - 1.f, 2.f * normalSample.b - 1.f, 0.f }; normal = tangentToWorld.TransformVector(normalMapSample).Normalized(); } const ColorRGB diffuseSample{currentMaterial->diffuseTexturePtr->Sample(sample.uv)}; double invPi = 1.0f / PI; const ColorRGB lambert{diffuseSample * lightIntensity / PI}; //TODO: ask why deviding by PI causses Segmentation fault // const ColorRGB lambert{ diffuseSample * lightIntensity / PI }; float specularReflectance{1.f}; float shininess{25.f}; specularReflectance *= currentMaterial->specularTexturePtr->Sample(sample.uv).r; shininess *= currentMaterial->glossTexturePtr->Sample(sample.uv).r; const float cosAngle = Vector3::Dot(normal, -lightDirection); const Vector3 reflect = Vector3::Reflect(lightDirection, normal); float cosSpecular = Vector3::Dot(reflect, sample.viewDirection); cosSpecular = std::max(cosSpecular, 0.f); const ColorRGB specular = specularReflectance * powf(cosSpecular, shininess) * colors::White; if (cosAngle < 0) { return ambient; } switch (m_ShadeMode) { case ShadeMode::ObservedArea: color = ColorRGB{cosAngle, cosAngle, cosAngle}; break; case ShadeMode::Diffuse: color = lambert; break; case ShadeMode::Specular: color = specular; break; case ShadeMode::Combined: color = lambert + specular + ambient; color *= ColorRGB{cosAngle, cosAngle, cosAngle}; break; } return color; } void Renderer::CycleCullMode() { for (auto& mesh: m_pScene->GetMeshes()) { mesh->CycleCullMode(); } std::string mode; switch (m_CullMode) { case CullMode::None: m_CullMode = CullMode::Front; mode = "Front"; break; case CullMode::Front: m_CullMode = CullMode::Back; mode = "Back"; break; case CullMode::Back: m_CullMode = CullMode::None; mode = "None"; break; } std::cout << MAGENTA << "[HARDWARE]" << BLUE << " Cull Mode = " << mode << RESET << std::endl; } void Renderer::ToggleBoundingBox() { m_isHitbox = !m_isHitbox; std::string mode = m_isHitbox ? "ON" : "OFF"; std::cout << MAGENTA << "[SOFTWARE]" << BLUE << " Hitbox " << mode << RESET << std::endl; } void Renderer::CycleRenderingMode() { std::string mode; switch (m_ShadeMode) { case ShadeMode::ObservedArea: m_ShadeMode = ShadeMode::Diffuse; mode = "Diffuse"; break; case ShadeMode::Diffuse: m_ShadeMode = ShadeMode::Specular; mode = "Specular"; break; case ShadeMode::Specular: m_ShadeMode = ShadeMode::Combined; mode = "Combined"; break; case ShadeMode::Combined: m_ShadeMode = ShadeMode::ObservedArea; mode = "Observed Area"; break; } std::cout << MAGENTA << "[SOFTWARE]" << BLUE << " Shading Mode = " << mode << RESET << std::endl; } void Renderer::SwitchBackend() { if (m_backendType == Backendtype::DirectX) { m_backendType = Backendtype::SDL; std::cout << MAGENTA << "[SHARED]" << BLUE << " Rasterizer mode = SOFTWARE" << RESET << std::endl; } else { m_backendType = Backendtype::DirectX; std::cout << MAGENTA << "[SHARED]" << BLUE << " Rasterizer mode = HARDWARE" << RESET << std::endl; } } void Renderer::NextSamplingState() { for (auto& mesh: m_pScene->GetMeshes()) { mesh->NextSamplingState(); } std::string mode; switch (m_TechniqueType) { case TechniqueType::Point: m_TechniqueType = TechniqueType::Linear; mode = "Linear"; break; case TechniqueType::Linear: m_TechniqueType = TechniqueType::Anisotropic; mode = "Anisotropic"; break; case TechniqueType::Anisotropic: m_TechniqueType = TechniqueType::Point; mode = "Point"; break; } std::cout << MAGENTA << "[HARDWARE]" << BLUE << " Texture Sampling Mode = " << mode << RESET << std::endl; } void Renderer::ToggleNormals() { m_useNormals = !m_useNormals; for (auto& mesh: m_pScene->GetMeshes()) { mesh->ToggleNormals(); } std::string mode = m_useNormals ? "ON" : "OFF"; std::cout << MAGENTA << "[SOFTWARE]" << BLUE << " Normal Map " << mode << RESET << std::endl; } void Renderer::ToggleRotation() { m_Rotating = !m_Rotating; std::string mode = m_Rotating ? "ON" : "OFF"; std::cout << MAGENTA << "[SHARED]" << BLUE << " Model Rotation " << mode << RESET << std::endl; } void Renderer::ToggleUniformClearColor() { m_UseUniformClearColor = !m_UseUniformClearColor; std::string mode = m_UseUniformClearColor ? "ON" : "OFF"; std::cout << MAGENTA << "[SHARED]" << BLUE << " Uniform Clear Color " << mode << RESET << std::endl; } void Renderer::ToggleFireFX() { if (m_pFireMesh != nullptr) { m_pFireMesh->SetShouldRender(!m_pFireMesh->GetShouldRender()); std::string mode = m_pFireMesh->GetShouldRender() ? "ON" : "OFF"; std::cout << MAGENTA << "[HARDWARE]" << BLUE << " FireFX " << mode << RESET << std::endl; } } void Renderer::NextScene() { m_pScene->Cleanup(); //Calculate the next scene int index = static_cast(m_CurrentScene); index = (index + 1) % static_cast(SceneNames::Count); m_CurrentScene = static_cast(index); switch (m_CurrentScene) { case SceneNames::Main: m_pScene = std::make_unique(); m_pFireMesh = nullptr; std::cout << MAGENTA << "[SHARED]" << BLUE << " Scene = Main" << RESET << std::endl; std::cout << MAGENTA << "This could take a second" << RESET << std::endl; break; case SceneNames::Diorama: m_pScene = std::make_unique(); std::cout << MAGENTA << "[SHARED]" << BLUE << " Scene = Diorama" << RESET << std::endl; std::cout << MAGENTA << "This could take a second" << RESET << std::endl; break; case SceneNames::Instanced: m_pScene = std::make_unique(); std::cout << MAGENTA << "[SHARED]" << BLUE << " Scene = Instanced" << RESET << std::endl; std::cout << MAGENTA << "This could take a second" << RESET << std::endl; break; case SceneNames::Planet: m_pScene = std::make_unique(); std::cout << MAGENTA << "[SHARED]" << BLUE << " Scene = Planet" << RESET << std::endl; std::cout << MAGENTA << "This could take a second" << RESET << std::endl; break; case SceneNames::Count: break; } m_Camera.SetPosition(m_SceneCameraPositions[m_CurrentScene].first); m_Camera.SetRotation(m_SceneCameraPositions[m_CurrentScene].second); m_pScene->Initialize(m_DevicePtr, m_DeviceContextPtr, &m_Camera); if (m_CurrentScene == SceneNames::Main) { //Kind of sloppy fix but hey :p m_pFireMesh = m_pScene->GetMeshes().back().get(); } } }