Boom exam done!
This commit is contained in:
@@ -163,7 +163,7 @@ void dae::Camera::Update(const dae::Timer *pTimer) {
|
||||
mousePosChange = true;
|
||||
} else if (mouseState == SDL_BUTTON_X2) //lmb + rmb
|
||||
{
|
||||
origin.y += static_cast<float>(mouseY) / 2;
|
||||
origin.y -= static_cast<float>(mouseY) / 2;
|
||||
|
||||
mousePosChange = true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include "Math/MathHelpers.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace dae
|
||||
{
|
||||
@@ -11,8 +13,8 @@ namespace dae
|
||||
|
||||
void MaxToOne()
|
||||
{
|
||||
const float maxValue = std::max(r, std::max(g, b));
|
||||
if (maxValue > 1.f)
|
||||
const float maxValue = (r > g) ? ((r > b) ? r : b) : ((g > b) ? g : b);
|
||||
if (maxValue > 1.f)
|
||||
*this /= maxValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ ID3DX11Effect *BaseEffect::LoadEffect(ID3D11Device *devicePtr, const std::wstrin
|
||||
std::wstringstream ss;
|
||||
for (UINT i{}; i < errorBlobPtr->GetBufferSize(); i++)
|
||||
ss << errorsPtr[i];
|
||||
|
||||
OutputDebugStringW(ss.str().c_str());
|
||||
|
||||
errorBlobPtr->Release();
|
||||
@@ -66,7 +65,6 @@ ID3DX11Effect *BaseEffect::LoadEffect(ID3D11Device *devicePtr, const std::wstrin
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::cout << "Effect loaded" << std::endl;
|
||||
return effectPtr;
|
||||
}
|
||||
|
||||
@@ -93,3 +91,7 @@ void BaseEffect::SetWorldMatrix(const dae::Matrix& matrix) const {
|
||||
void BaseEffect::ToggleNormals() {
|
||||
|
||||
}
|
||||
|
||||
void BaseEffect::NextCullMode() {
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
|
||||
virtual void NextSamplingState();
|
||||
|
||||
virtual void NextCullMode();
|
||||
|
||||
virtual void SetCameraPos(const dae::Vector3 &vector3) const;
|
||||
|
||||
virtual void SetMaterial(Material *material);
|
||||
|
||||
@@ -10,9 +10,9 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
|
||||
if(!m_LightPosVariablePtr->IsValid())
|
||||
std::wcout << L"gLightDirection Vector is not valid" << std::endl;
|
||||
|
||||
m_SamplerVariablePtr = m_EffectPtr->GetVariableByName("gSampler")->AsSampler();
|
||||
m_SamplerVariablePtr = m_EffectPtr->GetVariableByName("gSampleState")->AsSampler();
|
||||
if(!m_SamplerVariablePtr->IsValid())
|
||||
std::wcout << L"gSampler Sampler is not valid" << std::endl;
|
||||
std::wcout << L"gSampleState Sampler is not valid" << std::endl;
|
||||
|
||||
m_MatWorldVariablePtr = m_EffectPtr->GetVariableByName("gWorldMatrix")->AsMatrix();
|
||||
if(!m_MatWorldVariablePtr->IsValid())
|
||||
@@ -46,9 +46,15 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
|
||||
if(!m_UseNormalMapVariablePtr->IsValid())
|
||||
std::wcout << L"gUseNormalMap Scalar is not valid" << std::endl;
|
||||
|
||||
m_RasterizerVariablePtr = m_EffectPtr->GetVariableByName("gRasterizerState")->AsRasterizer();
|
||||
if(!m_RasterizerVariablePtr->IsValid())
|
||||
std::wcout << L"gRasterizerState Rasterizer is not valid" << std::endl;
|
||||
|
||||
m_UseNormalMapVariablePtr->SetBool(m_UseNormalMap);
|
||||
|
||||
|
||||
|
||||
|
||||
constexpr int vectorSize{ 4 };
|
||||
constexpr float lightDirection[vectorSize]{ .577f, -.577f, .577f, 0.f };
|
||||
m_LightPosVariablePtr->SetFloatVector(lightDirection);
|
||||
@@ -57,6 +63,10 @@ Effect::Effect(ID3D11Device *devicePtr, const std::wstring &filePath)
|
||||
m_LightColorVariablePtr->SetFloatVector(lightColor);
|
||||
|
||||
this->InitSamplers(devicePtr);
|
||||
this->InitRasterizer(devicePtr);
|
||||
|
||||
m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]);
|
||||
m_RasterizerVariablePtr->SetRasterizerState(0,m_RasterizerStates[static_cast<int>(m_CullMode)]);
|
||||
}
|
||||
|
||||
Effect::~Effect() {
|
||||
@@ -90,6 +100,9 @@ Effect::~Effect() {
|
||||
m_SamplerVariablePtr->Release();
|
||||
m_SamplerVariablePtr = nullptr;
|
||||
|
||||
m_RasterizerVariablePtr->Release();
|
||||
m_RasterizerVariablePtr = nullptr;
|
||||
|
||||
for(auto sampler : m_SamplerStates){
|
||||
sampler->Release();
|
||||
}
|
||||
@@ -156,3 +169,32 @@ void Effect::InitSamplers(ID3D11Device *devicePtr) {
|
||||
|
||||
m_SamplerVariablePtr->SetSampler(0,m_SamplerStates[static_cast<int>(m_TechniqueType)]);
|
||||
}
|
||||
|
||||
void Effect::NextCullMode() {
|
||||
m_CullMode = static_cast<CullMode>((static_cast<int>(m_CullMode) + 1) % 3);
|
||||
m_RasterizerVariablePtr->SetRasterizerState(0,m_RasterizerStates[static_cast<int>(m_CullMode)]);
|
||||
}
|
||||
|
||||
void Effect::InitRasterizer(ID3D11Device *devicePtr) {
|
||||
D3D11_RASTERIZER_DESC rasterDesc = {};
|
||||
rasterDesc.FillMode = D3D11_FILL_SOLID; // Solid fill
|
||||
rasterDesc.FrontCounterClockwise = FALSE;
|
||||
rasterDesc.DepthBias = D3D11_DEFAULT_DEPTH_BIAS;
|
||||
rasterDesc.SlopeScaledDepthBias = D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
||||
rasterDesc.DepthClipEnable = TRUE;
|
||||
rasterDesc.ScissorEnable = FALSE;
|
||||
rasterDesc.MultisampleEnable = FALSE;
|
||||
rasterDesc.AntialiasedLineEnable = FALSE;
|
||||
|
||||
rasterDesc.CullMode = D3D11_CULL_BACK; // Cull back faces
|
||||
|
||||
devicePtr->CreateRasterizerState(&rasterDesc, &m_RasterizerStates[static_cast<int>(CullMode::Back)]);
|
||||
|
||||
rasterDesc.CullMode = D3D11_CULL_FRONT;
|
||||
|
||||
devicePtr->CreateRasterizerState(&rasterDesc, &m_RasterizerStates[static_cast<int>(CullMode::Front)]);
|
||||
|
||||
rasterDesc.CullMode = D3D11_CULL_NONE;
|
||||
|
||||
devicePtr->CreateRasterizerState(&rasterDesc, &m_RasterizerStates[static_cast<int>(CullMode::None)]);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,12 @@ enum class TechniqueType {
|
||||
Anisotropic = 2
|
||||
};
|
||||
|
||||
enum class CullMode {
|
||||
None = 0,
|
||||
Front = 1,
|
||||
Back = 2
|
||||
};
|
||||
|
||||
|
||||
class Effect: public BaseEffect {
|
||||
public:
|
||||
@@ -20,15 +26,18 @@ public:
|
||||
|
||||
void SetCameraPos(const dae::Vector3 &pos) const override;
|
||||
|
||||
void SetMaterial(Material *material);
|
||||
void SetMaterial(Material *material) override;
|
||||
|
||||
void ToggleNormals() override;
|
||||
|
||||
void NextSamplingState() override;
|
||||
|
||||
void NextCullMode() override;
|
||||
|
||||
private:
|
||||
|
||||
void InitSamplers(ID3D11Device* devicePtr);
|
||||
void InitRasterizer(ID3D11Device* devicePtr);
|
||||
|
||||
ID3DX11EffectMatrixVariable *m_MatWorldVariablePtr{};
|
||||
|
||||
@@ -45,9 +54,14 @@ private:
|
||||
|
||||
ID3DX11EffectSamplerVariable *m_SamplerVariablePtr{};
|
||||
|
||||
ID3DX11EffectRasterizerVariable* m_RasterizerVariablePtr{};
|
||||
|
||||
TechniqueType m_TechniqueType{TechniqueType::Linear};
|
||||
|
||||
std::array<ID3D11SamplerState*, 3> m_SamplerStates{};
|
||||
std::array<ID3D11RasterizerState*, 3> m_RasterizerStates{};
|
||||
|
||||
CullMode m_CullMode{ CullMode::Back };
|
||||
|
||||
bool m_UseNormalMap{true};
|
||||
};
|
||||
|
||||
72
project/src/HitTest.cpp
Normal file
72
project/src/HitTest.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "HitTest.h"
|
||||
|
||||
|
||||
|
||||
float CrossZ(const Vector3& p0, const Vector3& p1, const Vector3& point)
|
||||
{
|
||||
return (p1.x - p0.x) * (point.y - p0.y)
|
||||
- (p1.y - p0.y) * (point.x - p0.x);
|
||||
}
|
||||
|
||||
std::optional<Sample> TriangleHitTest(const Vector3& fragPos, const VertexOut& v0, const VertexOut& v1, const VertexOut& v2)
|
||||
{
|
||||
Vector3 weights;
|
||||
|
||||
weights.x = CrossZ(v2.position, v1.position, fragPos);
|
||||
if ( weights.x > 0 )
|
||||
return std::nullopt;
|
||||
|
||||
weights.y = CrossZ(v0.position, v2.position, fragPos);
|
||||
if ( weights.y > 0 )
|
||||
return std::nullopt;
|
||||
|
||||
weights.z = CrossZ(v1.position, v0.position, fragPos);
|
||||
if ( weights.z > 0 )
|
||||
return std::nullopt;
|
||||
|
||||
const float totalWeight{ weights.x + weights.y + weights.z };
|
||||
|
||||
const float invTotalWeight{ 1.0f / totalWeight };
|
||||
const Vector3 normWeights{
|
||||
weights.x * invTotalWeight,
|
||||
weights.y * invTotalWeight,
|
||||
weights.z * invTotalWeight
|
||||
};
|
||||
|
||||
const float depth =
|
||||
1 / (normWeights.x / v0.position.w +
|
||||
normWeights.y / v1.position.w +
|
||||
normWeights.z / v2.position.w);
|
||||
|
||||
const Vector2 uv =
|
||||
v0.uv * depth * normWeights.x / v0.position.w +
|
||||
v1.uv * depth * normWeights.y / v1.position.w +
|
||||
v2.uv * depth * normWeights.z / v2.position.w;
|
||||
|
||||
const float interpolatedDepth = 1 / (normWeights.x / v0.position.w + normWeights.y / v1.position.w + normWeights.z / v2.position.w);
|
||||
|
||||
auto interpolate =
|
||||
[&]<typename Type>(const Type& val0, const Type& val1, const Type& val2) -> Type
|
||||
{
|
||||
return (val0 / v0.position.w * normWeights.x +
|
||||
val1 / v1.position.w * normWeights.y +
|
||||
val2 / v2.position.w * normWeights.z) * interpolatedDepth;
|
||||
|
||||
};
|
||||
|
||||
//Invert the normal
|
||||
const Vector3 normal = interpolate(v0.normal, v1.normal, v2.normal).Normalized();
|
||||
const Vector3 tangent = interpolate(v0.tangent, v1.tangent, v2.tangent).Normalized();
|
||||
const Vector3 viewDir = interpolate(v0.viewDir, v1.viewDir, v2.viewDir).Normalized();
|
||||
|
||||
return Sample{
|
||||
.uv = uv,
|
||||
.normal = normal,
|
||||
.tangent = tangent,
|
||||
.viewDirection = viewDir,
|
||||
.depth = depth,
|
||||
.weight = normWeights,
|
||||
.mesh = v0.mesh
|
||||
};
|
||||
}
|
||||
|
||||
28
project/src/HitTest.h
Normal file
28
project/src/HitTest.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef GP1_DIRECTX_HITTEST_H
|
||||
#define GP1_DIRECTX_HITTEST_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include "ColorRGB.h"
|
||||
#include "Math/Vector3.h"
|
||||
#include "Math/Vector2.h"
|
||||
#include "Mesh.h"
|
||||
|
||||
using namespace dae;
|
||||
|
||||
|
||||
struct Sample
|
||||
{
|
||||
Vector2 uv{};
|
||||
Vector3 normal{};
|
||||
Vector3 tangent{};
|
||||
Vector3 viewDirection{};
|
||||
float depth{};
|
||||
Vector3 weight{};
|
||||
Mesh* mesh{};
|
||||
};
|
||||
|
||||
|
||||
std::optional<Sample> TriangleHitTest(const Vector3& fragPos, const VertexOut& v0, const VertexOut& v1, const VertexOut& v2);
|
||||
|
||||
#endif //GP1_DIRECTX_HITTEST_H
|
||||
@@ -164,5 +164,10 @@ namespace dae {
|
||||
if (index == 1) return y;
|
||||
return z;
|
||||
}
|
||||
|
||||
bool Vector3::operator==(const Vector3 &v) const {
|
||||
return (x - v.x) < FLT_EPSILON && (y - v.y) < FLT_EPSILON && (z - v.z) < FLT_EPSILON;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace dae
|
||||
Vector3& operator*=(float scale);
|
||||
float& operator[](int index);
|
||||
float operator[](int index) const;
|
||||
bool operator==(const Vector3& v) const;
|
||||
|
||||
|
||||
static const Vector3 UnitX;
|
||||
static const Vector3 UnitY;
|
||||
|
||||
@@ -98,5 +98,14 @@ namespace dae
|
||||
if (index == 2)return z;
|
||||
return w;
|
||||
}
|
||||
|
||||
bool Vector4::operator==(const Vector4 &v) const {
|
||||
return
|
||||
std::abs(x - v.x) <= FLT_EPSILON &&
|
||||
std::abs(y - v.y) <= FLT_EPSILON &&
|
||||
std::abs(z - v.z) <= FLT_EPSILON &&
|
||||
std::abs(w - v.w) <= FLT_EPSILON;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
}
|
||||
@@ -32,5 +32,6 @@ namespace dae
|
||||
Vector4& operator+=(const Vector4& v);
|
||||
float& operator[](int index);
|
||||
float operator[](int index) const;
|
||||
bool operator==(const Vector4& v) const;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -136,3 +136,12 @@ void Mesh::SetWorldMatrix(const Matrix &matrix) {
|
||||
void Mesh::ToggleNormals() {
|
||||
m_EffectPtr->ToggleNormals();
|
||||
}
|
||||
|
||||
void Mesh::SetMaterial(Material *pMaterial) {
|
||||
m_Material.reset(pMaterial);
|
||||
m_EffectPtr->SetMaterial(pMaterial);
|
||||
}
|
||||
|
||||
void Mesh::CycleCullMode() {
|
||||
m_EffectPtr->NextCullMode();
|
||||
}
|
||||
@@ -13,6 +13,11 @@ using namespace dae;
|
||||
struct VertexIn;
|
||||
struct VertexOut;
|
||||
|
||||
enum class PrimitiveTopology {
|
||||
TriangleList,
|
||||
TriangleStrip
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,8 +38,21 @@ public:
|
||||
|
||||
void NextSamplingState();
|
||||
|
||||
Material* GetMaterial() const { return m_Material.get(); }
|
||||
|
||||
void SetWorldMatrix(const Matrix &matrix);
|
||||
|
||||
std::vector<VertexIn>& GetVertices() { return m_VerticesIn; }
|
||||
std::vector<Uint32>& GetIndices() { return m_Indices; }
|
||||
PrimitiveTopology GetPrimitiveTopology() const { return m_PrimitiveTopology; }
|
||||
|
||||
void SetMaterial(Material *pMaterial);
|
||||
|
||||
void CycleCullMode();
|
||||
|
||||
void SetShouldRender(bool shouldRender) { m_ShouldRender = shouldRender; }
|
||||
bool GetShouldRender() const { return m_ShouldRender; }
|
||||
|
||||
private:
|
||||
BaseEffect *m_EffectPtr;
|
||||
|
||||
@@ -49,6 +67,10 @@ private:
|
||||
UINT m_IndicesCount;
|
||||
|
||||
std::shared_ptr<Material> m_Material{};
|
||||
|
||||
PrimitiveTopology m_PrimitiveTopology{PrimitiveTopology::TriangleList};
|
||||
|
||||
bool m_ShouldRender{ true };
|
||||
};
|
||||
|
||||
struct VertexIn {
|
||||
@@ -65,5 +87,7 @@ struct VertexOut {
|
||||
Vector3 normal{};
|
||||
Vector3 tangent{};
|
||||
Vector3 viewDir{};
|
||||
Mesh* mesh{};
|
||||
bool valid{ true };
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Texture.h"
|
||||
#include "Effects/Effect.h"
|
||||
#include "Effects/FireEffect.h"
|
||||
#include "HitTest.h"
|
||||
|
||||
namespace dae {
|
||||
|
||||
@@ -63,6 +64,23 @@ namespace dae {
|
||||
FireEffect* fireEffect = new FireEffect(m_DevicePtr, L"resources/Fire.fx");
|
||||
m_meshes.push_back(new Mesh(m_DevicePtr, vertices, indices, FireMaterial, fireEffect));
|
||||
|
||||
m_pFireMesh = m_meshes.back();
|
||||
|
||||
//
|
||||
// std::vector<std::unique_ptr<Utils::MaterialMesh>> materialMeshes;
|
||||
// Utils::LoadObjWithMaterials("resources/scene.obj", materialMeshes, true, m_DevicePtr);
|
||||
// for (const auto &mesh: materialMeshes) {
|
||||
// if(mesh->vertices.size() > 0) {
|
||||
// Effect *effect = new Effect(m_DevicePtr, L"resources/SimpleDiffuse.fx");
|
||||
// std::shared_ptr<Material> material = std::make_shared<Material>();
|
||||
// material->diffuseTexturePtr = Texture::LoadFromFile("./resources/" + mesh->diffuse_texture, m_DevicePtr);
|
||||
// m_meshes.push_back(new Mesh(m_DevicePtr, mesh->vertices, mesh->indices, material, effect));
|
||||
// Matrix worldMatrix = m_meshes.back()->GetWorldMatrix();
|
||||
// worldMatrix *= Matrix::CreateScale(2.f, 2.f, 2.f);
|
||||
// m_meshes.back()->SetWorldMatrix(worldMatrix);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
float aspectRatio = static_cast<float>(m_Width) / static_cast<float>(m_Height);
|
||||
m_Camera = Camera({.0f, 5.0f, -64.f}, 45.f);
|
||||
@@ -90,6 +108,12 @@ namespace dae {
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
//SDL
|
||||
|
||||
SDL_FreeSurface(m_pBackBuffer);
|
||||
SDL_FreeSurface(m_pFrontBuffer);
|
||||
|
||||
delete[] m_pDepthBufferPixels;
|
||||
|
||||
}
|
||||
|
||||
@@ -108,40 +132,189 @@ namespace dae {
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::Render() const {
|
||||
void Renderer::Render() {
|
||||
if (!m_IsInitialized)
|
||||
return;
|
||||
if (m_backendType == Backendtype::DirectX) {
|
||||
this->RenderDirectX();
|
||||
} else {
|
||||
this->RenderSDL();
|
||||
}
|
||||
|
||||
//Clear back buffer
|
||||
}
|
||||
|
||||
void Renderer::RenderDirectX() const {
|
||||
//Clear back buffer
|
||||
if(m_UniformClearColor){
|
||||
const float clearColor[] = {static_cast<float>(r) / 255.f, static_cast<float>(g) / 255.f, static_cast<float>(b) / 255.f, 1.f};
|
||||
m_DeviceContextPtr->ClearRenderTargetView(m_RenderTargetViewPtr, clearColor);
|
||||
} else {
|
||||
const float clearColor[] = {1.f / 255.f, 0.f / 255.f, 76.f / 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_meshes) {
|
||||
m_DeviceContextPtr->ClearDepthStencilView(m_DepthStencilViewPtr, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
||||
|
||||
Matrix viewProjMatrix = m_Camera.GetViewProjectionMatrix();
|
||||
for (auto mesh: m_meshes) {
|
||||
if(mesh->GetShouldRender()){
|
||||
Matrix modelMatrix = mesh->GetWorldMatrix();
|
||||
Matrix worldViewProjMatrix = modelMatrix * viewProjMatrix;
|
||||
|
||||
mesh->Render(m_DeviceContextPtr, worldViewProjMatrix);
|
||||
}
|
||||
|
||||
//Present
|
||||
m_SwapChainPtr->Present(0, 0);
|
||||
} else {
|
||||
SDL_FillRect(m_pBackBuffer, nullptr, Uint32(255 << 24) + Uint32(100 << 16) + Uint32(100 << 8) + Uint32(100));
|
||||
|
||||
//Lock BackBuffer
|
||||
for (int x = 0; x < 100; ++x) {
|
||||
for (int y = 0; y < 100; ++y) {
|
||||
m_pBackBufferPixels[(x + 100) + (y + 150) * m_Width] = SDL_MapRGB(m_pBackBuffer->format, 255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_BlitSurface(m_pBackBuffer, nullptr, m_pFrontBuffer, nullptr);
|
||||
SDL_UpdateWindowSurface(m_pWindow);
|
||||
}
|
||||
|
||||
//Present
|
||||
m_SwapChainPtr->Present(0, 0);
|
||||
}
|
||||
|
||||
void Renderer::RenderSDL() {
|
||||
SDL_FillRect(m_pBackBuffer, nullptr, m_ClearColor);
|
||||
SDL_LockSurface(m_pBackBuffer);
|
||||
std::fill_n(m_pDepthBufferPixels, m_Width * m_Height, std::numeric_limits<float>::max());
|
||||
|
||||
SDL_FillRect(m_pBackBuffer, nullptr, m_ClearColor);
|
||||
|
||||
ColorRGB finalColor{};
|
||||
constexpr int numVerticies = 3;
|
||||
|
||||
m_VerticiesScreenSpace.clear();
|
||||
|
||||
|
||||
for (auto* currentMesh: m_meshes) {
|
||||
|
||||
if(!currentMesh->GetShouldRender()){
|
||||
continue;
|
||||
}
|
||||
|
||||
const Matrix worldViewProjectionMatrix{ currentMesh->GetWorldMatrix() * m_Camera.GetViewProjectionMatrix() };
|
||||
VertexTransformationFunction(worldViewProjectionMatrix, currentMesh, currentMesh->GetVertices(), m_VerticiesScreenSpace);
|
||||
|
||||
int numTriangles{};
|
||||
|
||||
switch (currentMesh->GetPrimitiveTopology()) {
|
||||
case PrimitiveTopology::TriangleList:
|
||||
numTriangles = static_cast<int>(currentMesh->GetIndices().size()) / numVerticies;
|
||||
break;
|
||||
case PrimitiveTopology::TriangleStrip:
|
||||
numTriangles = static_cast<int>(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<int>(minX)) - 1;
|
||||
const int endX = std::min(m_Width - 1, static_cast<int>(maxX)) + 1;
|
||||
|
||||
const int startY = std::max(0, static_cast<int>(minY)) - 1;
|
||||
const int endY = std::min(m_Height - 1, static_cast<int>(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<uint8_t>(255),
|
||||
static_cast<uint8_t>(255),
|
||||
static_cast<uint8_t>(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<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f};
|
||||
|
||||
auto sample{ TriangleHitTest(P, vertex0, vertex1, vertex2) };
|
||||
|
||||
if (!sample.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Vector3 fragPos{ static_cast<float>(px) + 0.5f, static_cast<float>(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<uint8_t>(finalColor.r * 255),
|
||||
static_cast<uint8_t>(finalColor.g * 255),
|
||||
static_cast<uint8_t>(finalColor.b * 255));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockSurface(m_pBackBuffer);
|
||||
SDL_BlitSurface(m_pBackBuffer,nullptr, m_pFrontBuffer, nullptr);
|
||||
SDL_UpdateWindowSurface(m_pWindow);
|
||||
}
|
||||
|
||||
HRESULT Renderer::InitializeDirectX() {
|
||||
@@ -259,10 +432,163 @@ namespace dae {
|
||||
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];
|
||||
m_pDepthBufferPixels = new float[m_Width * m_Height];
|
||||
}
|
||||
|
||||
|
||||
void Renderer::VertexTransformationFunction(const Matrix &WorldViewProjectionMatrix, Mesh* mesh,
|
||||
std::vector<VertexIn> &vertices_in, std::vector<VertexOut> &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) };
|
||||
const Vector3 tangent{ mesh->GetWorldMatrix().TransformVector(vert.tangent) };
|
||||
|
||||
|
||||
|
||||
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<float>(m_Width);
|
||||
vertPos.y = ((1.f - vertPos.y) / 2.f) * static_cast<float>(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.viewDir = WorldViewProjectionMatrix.TransformVector(vert.viewDir);
|
||||
vertex_out.valid = isValid;
|
||||
|
||||
vertices_out.push_back(vertex_out);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Renderer::ToggleDepthBuffer() {
|
||||
m_isDepthBuffer = !m_isDepthBuffer;
|
||||
}
|
||||
|
||||
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 ColorRGB normalSample{ sample.mesh->GetMaterial()->normalTexturePtr->Sample(sample.uv) };
|
||||
const Vector4 normalMapSample{
|
||||
2.f * normalSample.r - 1.f,
|
||||
2.f * normalSample.g - 1.f,
|
||||
2.f * normalSample.b - 1.f,
|
||||
0.f
|
||||
};
|
||||
|
||||
const Vector3 biNormal{ Vector3::Cross(normal, sample.tangent) };
|
||||
const Matrix tangentToWorld{
|
||||
Vector4{ sample.tangent, 0.f },
|
||||
Vector4{ biNormal, 0.f },
|
||||
Vector4{ normal, 0.f },
|
||||
Vector4{ 0.f, 0.f, 0.f, 1.f }
|
||||
};
|
||||
normal = tangentToWorld.TransformVector(normalMapSample).Normalized();
|
||||
}
|
||||
|
||||
|
||||
const ColorRGB diffuseSample{ currentMaterial->diffuseTexturePtr->Sample(sample.uv) };
|
||||
double invPi = 1.0 / PI;
|
||||
const ColorRGB lambert{ diffuseSample * lightIntensity * invPi };
|
||||
|
||||
//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->glossTexturePtr->Sample(sample.uv).r;
|
||||
shininess *= currentMaterial->specularTexturePtr->Sample(sample.uv).r;
|
||||
|
||||
const float cosAngle = Vector3::Dot(normal, -lightDirection);
|
||||
|
||||
const ColorRGB specular = specularReflectance * powf(cosAngle, shininess) * colors::White;
|
||||
|
||||
if (cosAngle < 0) {
|
||||
return ambient;
|
||||
}
|
||||
|
||||
switch(m_ShadeMode){
|
||||
case ShadeMode::ObservedArea:
|
||||
break;
|
||||
case ShadeMode::Diffuse:
|
||||
color = lambert;
|
||||
break;
|
||||
case ShadeMode::Specular:
|
||||
color = specular;
|
||||
break;
|
||||
case ShadeMode::Combined:
|
||||
color = lambert + specular + ambient;
|
||||
break;
|
||||
}
|
||||
|
||||
color *= ColorRGB{ cosAngle, cosAngle, cosAngle };
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void Renderer::CycleCullMode() {
|
||||
for(auto mesh: m_meshes){
|
||||
mesh->CycleCullMode();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::ToggleBoundingBox() {
|
||||
m_isHitbox = !m_isHitbox;
|
||||
}
|
||||
|
||||
void Renderer::CycleRenderingMode() {
|
||||
switch (m_ShadeMode) {
|
||||
case ShadeMode::ObservedArea:
|
||||
m_ShadeMode = ShadeMode::Diffuse;
|
||||
std::cout << "Diffuse" << std::endl;
|
||||
break;
|
||||
case ShadeMode::Diffuse:
|
||||
m_ShadeMode = ShadeMode::Specular;
|
||||
std::cout << "Specular" << std::endl;
|
||||
break;
|
||||
case ShadeMode::Specular:
|
||||
m_ShadeMode = ShadeMode::Combined;
|
||||
std::cout << "Combined" << std::endl;
|
||||
break;
|
||||
case ShadeMode::Combined:
|
||||
m_ShadeMode = ShadeMode::ObservedArea;
|
||||
std::cout << "Observed Area" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Renderer::SwitchBackend() {
|
||||
if (m_backendType == Backendtype::DirectX) {
|
||||
m_backendType = Backendtype::SDL;
|
||||
@@ -278,6 +604,7 @@ namespace dae {
|
||||
}
|
||||
|
||||
void Renderer::ToggleNormals() {
|
||||
m_useNormals = !m_useNormals;
|
||||
for(auto mesh: m_meshes){
|
||||
mesh->ToggleNormals();
|
||||
}
|
||||
@@ -290,4 +617,10 @@ namespace dae {
|
||||
void Renderer::ToggleUniformClearColor() {
|
||||
m_UniformClearColor = !m_UniformClearColor;
|
||||
}
|
||||
|
||||
void Renderer::ToggleFireFX() {
|
||||
m_pFireMesh->SetShouldRender(!m_pFireMesh->GetShouldRender());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Mesh.h"
|
||||
#include "Camera.h"
|
||||
#include "HitTest.h"
|
||||
|
||||
struct SDL_Window;
|
||||
struct SDL_Surface;
|
||||
@@ -11,12 +12,19 @@ enum class Backendtype {
|
||||
SDL
|
||||
};
|
||||
|
||||
enum class ShadeMode{
|
||||
ObservedArea,
|
||||
Diffuse,
|
||||
Specular,
|
||||
Combined
|
||||
};
|
||||
|
||||
namespace dae
|
||||
{
|
||||
class Renderer final
|
||||
{
|
||||
public:
|
||||
Renderer(SDL_Window* pWindow);
|
||||
explicit Renderer(SDL_Window* pWindow);
|
||||
~Renderer();
|
||||
|
||||
Renderer(const Renderer&) = delete;
|
||||
@@ -25,7 +33,7 @@ namespace dae
|
||||
Renderer& operator=(Renderer&&) noexcept = delete;
|
||||
|
||||
void Update(const Timer* pTimer);
|
||||
void Render() const;
|
||||
void Render();
|
||||
|
||||
//Switching Functions
|
||||
void NextSamplingState();
|
||||
@@ -37,31 +45,23 @@ namespace dae
|
||||
|
||||
void ToggleUniformClearColor();
|
||||
|
||||
void ToggleDepthBuffer();
|
||||
|
||||
void CycleCullMode();
|
||||
|
||||
void ToggleBoundingBox();
|
||||
|
||||
void CycleRenderingMode();
|
||||
|
||||
void ToggleFireFX();
|
||||
|
||||
private:
|
||||
// Common vars
|
||||
SDL_Window* m_pWindow{};
|
||||
|
||||
int m_Width{};
|
||||
int m_Height{};
|
||||
|
||||
bool m_IsInitialized{ false };
|
||||
|
||||
//DIRECTX
|
||||
HRESULT InitializeDirectX();
|
||||
void InitializeSDLRasterizer();
|
||||
|
||||
ID3D11Device* m_DevicePtr{};
|
||||
ID3D11DeviceContext* m_DeviceContextPtr{};
|
||||
IDXGISwapChain* m_SwapChainPtr{};
|
||||
ID3D11Texture2D* m_DepthStencilBufferPtr{};
|
||||
ID3D11DepthStencilView* m_DepthStencilViewPtr{};
|
||||
ID3D11Resource* m_RenderTargetBufferPtr{};
|
||||
ID3D11RenderTargetView* m_RenderTargetViewPtr{};
|
||||
|
||||
SDL_Surface* m_pFrontBuffer{ nullptr };
|
||||
SDL_Surface* m_pBackBuffer{ nullptr };
|
||||
uint32_t* m_pBackBufferPixels{};
|
||||
|
||||
|
||||
std::vector<Mesh*> m_meshes{};
|
||||
std::vector<std::shared_ptr<Material>> m_materials{};
|
||||
|
||||
@@ -73,5 +73,51 @@ namespace dae
|
||||
float m_currentRotation{};
|
||||
bool m_UniformClearColor{ false };
|
||||
|
||||
|
||||
//DirectX vars
|
||||
|
||||
bool m_IsInitialized{ false };
|
||||
|
||||
HRESULT InitializeDirectX();
|
||||
void RenderDirectX() const;
|
||||
|
||||
//Storing the mesh so i can deactivate it;
|
||||
Mesh* m_pFireMesh{};
|
||||
|
||||
ID3D11Device* m_DevicePtr{};
|
||||
ID3D11DeviceContext* m_DeviceContextPtr{};
|
||||
IDXGISwapChain* m_SwapChainPtr{};
|
||||
ID3D11Texture2D* m_DepthStencilBufferPtr{};
|
||||
ID3D11DepthStencilView* m_DepthStencilViewPtr{};
|
||||
ID3D11Resource* m_RenderTargetBufferPtr{};
|
||||
ID3D11RenderTargetView* m_RenderTargetViewPtr{};
|
||||
|
||||
//SDL vars
|
||||
|
||||
void InitializeSDLRasterizer();
|
||||
void RenderSDL();
|
||||
void VertexTransformationFunction(const Matrix& WorldViewProjectionMatrix, Mesh* mesh, std::vector<VertexIn> &vertices_in, std::vector<VertexOut> &vertices_out) const;
|
||||
ColorRGB ShadePixel(const Sample& sample);
|
||||
|
||||
|
||||
SDL_Surface* m_pFrontBuffer{ nullptr };
|
||||
SDL_Surface* m_pBackBuffer{ nullptr };
|
||||
uint32_t* m_pBackBufferPixels{};
|
||||
|
||||
bool m_useNormals{ true };
|
||||
bool m_isHitbox{ false };
|
||||
ShadeMode m_ShadeMode{ ShadeMode::Combined };
|
||||
bool m_isDepthBuffer{ false };
|
||||
|
||||
|
||||
Uint8 r{100};
|
||||
Uint8 g{100};
|
||||
Uint8 b{100};
|
||||
Uint32 m_ClearColor{ Uint32(255 << 24) + Uint32(r << 16) + Uint32(g << 8) + Uint32(b) };
|
||||
float* m_pDepthBufferPixels{};
|
||||
|
||||
std::vector<VertexOut> m_VerticiesScreenSpace{};
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <algorithm>
|
||||
#include "Texture.h"
|
||||
|
||||
Texture::~Texture() {
|
||||
@@ -11,6 +12,11 @@ Texture *Texture::LoadFromFile(const std::string &path, ID3D11Device *devicePtr)
|
||||
std::cerr << "Failed to load texture: " << path << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
if (surface->format->BytesPerPixel != 4)
|
||||
{
|
||||
std::cerr << "Texture::LoadFromFile > Texture is not in the right format: " << path << std::endl;
|
||||
// throw std::runtime_error("Texture is not in the right format");
|
||||
}
|
||||
|
||||
auto *texture = new Texture(surface, devicePtr);
|
||||
|
||||
@@ -46,6 +52,22 @@ Texture::Texture(SDL_Surface *surfacePtr, ID3D11Device *devicePtr) {
|
||||
|
||||
hr = devicePtr->CreateShaderResourceView(m_TexturePtr, &SRVDesc, &m_TextureResourceViewPtr);
|
||||
|
||||
SDL_FreeSurface(surfacePtr);
|
||||
|
||||
m_SurfacePtr = surfacePtr;
|
||||
m_pSurfacePixels = static_cast<Uint32 *>(surfacePtr->pixels);
|
||||
}
|
||||
|
||||
ColorRGB Texture::Sample(const Vector2 &uv) const {
|
||||
Uint8 red, green, blue;
|
||||
|
||||
Vector2 wrapped = {fmod(uv.x, 1.0f), fmod(uv.y, 1.0f)};
|
||||
|
||||
if (wrapped.x < 0.0f) wrapped.x += 1.0f;
|
||||
if (wrapped.y < 0.0f) wrapped.y += 1.0f;
|
||||
|
||||
SDL_GetRGB(m_pSurfacePixels[
|
||||
static_cast<int>(wrapped.x * static_cast<float>(m_SurfacePtr->w - 1)) +
|
||||
static_cast<int>(wrapped.y * static_cast<float>(m_SurfacePtr->h - 1)) * (m_SurfacePtr->w)
|
||||
], m_SurfacePtr->format, &red, &green, &blue);
|
||||
|
||||
return ColorRGB{static_cast<float>(red) / 255.0f, static_cast<float>(green) / 255.0f, static_cast<float>(blue) / 255.0f};
|
||||
}
|
||||
@@ -7,7 +7,10 @@
|
||||
#include "Texture.h"
|
||||
#include "SDL_surface.h"
|
||||
#include "SDL_image.h"
|
||||
#include "ColorRGB.h"
|
||||
#include "Math/Vector2.h"
|
||||
|
||||
using namespace dae;
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
@@ -17,11 +20,16 @@ public:
|
||||
|
||||
inline ID3D11ShaderResourceView* GetSrv() const { return m_TextureResourceViewPtr; }
|
||||
|
||||
ColorRGB Sample(const Vector2& uv) const;
|
||||
|
||||
private:
|
||||
Texture(SDL_Surface* surfacePtr, ID3D11Device* devicePtr);
|
||||
|
||||
ID3D11ShaderResourceView* m_TextureResourceViewPtr{};
|
||||
ID3D11Texture2D* m_TexturePtr{};
|
||||
|
||||
SDL_Surface* m_SurfacePtr{ nullptr };
|
||||
uint32_t* m_pSurfacePixels{ nullptr };
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -256,5 +256,118 @@ namespace dae {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct MaterialMesh {
|
||||
std::vector<VertexIn> vertices;
|
||||
std::vector<uint32_t> indices;
|
||||
int material_id = -1; // Material ID associated with this mesh
|
||||
std::string diffuse_texture; // Path to the diffuse texture
|
||||
};
|
||||
|
||||
|
||||
static bool LoadObjWithMaterials(const std::string &fileName, std::vector<std::unique_ptr<MaterialMesh>> &meshes,
|
||||
bool flipAxisAndWinding = true, ID3D11Device* device = nullptr) {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string warn, err;
|
||||
|
||||
std::string basepath = "resources/";
|
||||
|
||||
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, fileName.c_str(), basepath.c_str())) {
|
||||
if (!warn.empty()) {
|
||||
std::cerr << "Warning: " << warn << std::endl;
|
||||
}
|
||||
if (!err.empty()) {
|
||||
std::cerr << "Error: " << err << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear and prepare the meshes array
|
||||
meshes.clear();
|
||||
|
||||
// Create Mesh objects for each material
|
||||
meshes.resize(materials.size());
|
||||
for (size_t i = 0; i < materials.size(); ++i) {
|
||||
meshes[i] = std::make_unique<MaterialMesh>();
|
||||
meshes[i]->material_id = static_cast<int>(i);
|
||||
meshes[i]->diffuse_texture = materials[i].diffuse_texname;
|
||||
}
|
||||
|
||||
// Default Mesh for faces with no material
|
||||
auto defaultMesh = std::make_unique<MaterialMesh>();
|
||||
defaultMesh->material_id = -1;
|
||||
defaultMesh->diffuse_texture = "";
|
||||
meshes.push_back(std::move(defaultMesh));
|
||||
|
||||
for (const auto &shape : shapes) {
|
||||
size_t index_offset = 0;
|
||||
|
||||
for (size_t f = 0; f < shape.mesh.num_face_vertices.size(); f++) {
|
||||
auto fv = size_t(shape.mesh.num_face_vertices[f]);
|
||||
|
||||
if (fv != 3) {
|
||||
std::cerr << "Error: Only triangular faces are supported." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int material_id = (f < shape.mesh.material_ids.size()) ? shape.mesh.material_ids[f] : -1;
|
||||
if (material_id < 0 || material_id >= static_cast<int>(materials.size())) {
|
||||
material_id = -1;
|
||||
}
|
||||
|
||||
auto* targetMesh = (material_id >= 0 && material_id < static_cast<int>(materials.size()))
|
||||
? meshes[material_id].get()
|
||||
: meshes.back().get(); // Use default mesh
|
||||
|
||||
uint32_t tempIndices[3];
|
||||
VertexIn tempVertices[3];
|
||||
|
||||
for (size_t v = 0; v < fv; v++) {
|
||||
tinyobj::index_t idx = shape.mesh.indices[index_offset + v];
|
||||
|
||||
VertexIn vertex;
|
||||
|
||||
if (idx.vertex_index >= 0) {
|
||||
vertex.position = Vector3(
|
||||
attrib.vertices[3 * idx.vertex_index + 0],
|
||||
attrib.vertices[3 * idx.vertex_index + 1],
|
||||
attrib.vertices[3 * idx.vertex_index + 2]
|
||||
);
|
||||
}
|
||||
|
||||
if (idx.texcoord_index >= 0) {
|
||||
vertex.uv = Vector2(
|
||||
attrib.texcoords[2 * idx.texcoord_index + 0],
|
||||
1.0f - attrib.texcoords[2 * idx.texcoord_index + 1] // Flip V
|
||||
);
|
||||
}
|
||||
|
||||
if (idx.normal_index >= 0) {
|
||||
vertex.normal = Vector3(
|
||||
attrib.normals[3 * idx.normal_index + 0],
|
||||
attrib.normals[3 * idx.normal_index + 1],
|
||||
attrib.normals[3 * idx.normal_index + 2]
|
||||
);
|
||||
}
|
||||
|
||||
tempVertices[v] = vertex;
|
||||
tempIndices[v] = static_cast<uint32_t>(targetMesh->vertices.size());
|
||||
targetMesh->vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
// Push indices in the default order
|
||||
targetMesh->indices.push_back(tempIndices[0]);
|
||||
targetMesh->indices.push_back(tempIndices[1]);
|
||||
targetMesh->indices.push_back(tempIndices[2]);
|
||||
|
||||
index_offset += fv;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ int main(int argc, char *args[]) {
|
||||
const uint32_t width = 640;
|
||||
const uint32_t height = 480;
|
||||
|
||||
|
||||
SDL_Window *pWindow = SDL_CreateWindow(
|
||||
"DirectX - Bram Verhulst - 2GD11E",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
@@ -49,6 +50,8 @@ int main(int argc, char *args[]) {
|
||||
const auto pTimer = new Timer();
|
||||
const auto pRenderer = new Renderer(pWindow);
|
||||
|
||||
bool printFPS = false;
|
||||
|
||||
//Start loop
|
||||
pTimer->Start();
|
||||
float printTimer = 0.f;
|
||||
@@ -73,6 +76,7 @@ int main(int argc, char *args[]) {
|
||||
}
|
||||
if(scancode == SDL_SCANCODE_F9){
|
||||
// Cycle Cull mode
|
||||
pRenderer->CycleCullMode();
|
||||
}
|
||||
if(scancode == SDL_SCANCODE_F10){
|
||||
// Toggle Uniform Clear Color
|
||||
@@ -80,11 +84,13 @@ int main(int argc, char *args[]) {
|
||||
}
|
||||
if(scancode == SDL_SCANCODE_F11){
|
||||
// toggle Print fps
|
||||
printFPS = !printFPS;
|
||||
}
|
||||
|
||||
//Hardware
|
||||
if (scancode == SDL_SCANCODE_F3){
|
||||
// Toggle FireFX mesh
|
||||
pRenderer->ToggleFireFX();
|
||||
}
|
||||
if (scancode == SDL_SCANCODE_F4){
|
||||
//Toggle texture sampling states
|
||||
@@ -93,25 +99,21 @@ int main(int argc, char *args[]) {
|
||||
//Software
|
||||
if(scancode == SDL_SCANCODE_F5){
|
||||
//Cycle shading mode
|
||||
pRenderer->CycleRenderingMode();
|
||||
}
|
||||
if(scancode == SDL_SCANCODE_F6){
|
||||
//Toggle normal mapping
|
||||
pRenderer->ToggleNormals();
|
||||
}
|
||||
if(scancode == SDL_SCANCODE_F7){
|
||||
//Toggle Depth Buffer
|
||||
pRenderer->ToggleDepthBuffer();
|
||||
}
|
||||
if(scancode == SDL_SCANCODE_F8) {
|
||||
//Toggle BoundingBox
|
||||
pRenderer->ToggleBoundingBox();
|
||||
}
|
||||
|
||||
if (e.key.keysym.scancode == SDL_SCANCODE_F2) {
|
||||
}
|
||||
if (e.key.keysym.scancode == SDL_SCANCODE_F3) {
|
||||
|
||||
}
|
||||
if (e.key.keysym.scancode == SDL_SCANCODE_F4) {
|
||||
pRenderer->ToggleNormals();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -129,7 +131,7 @@ int main(int argc, char *args[]) {
|
||||
//--------- Timer ---------
|
||||
pTimer->Update();
|
||||
printTimer += pTimer->GetElapsed();
|
||||
if (printTimer >= 1.f) {
|
||||
if (printTimer >= 1.f && printFPS) {
|
||||
printTimer = 0.f;
|
||||
std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user