This commit is contained in:
2024-12-11 18:53:17 +01:00
commit 78a38ec5dc
149 changed files with 121662 additions and 0 deletions

190
project/src/Camera.cpp Normal file
View File

@@ -0,0 +1,190 @@
//
// Created by Bram on 11/12/2024.
//
#include <iostream>
#include "Camera.h"
#include "GamePadController.h"
dae::Camera::Camera(const dae::Vector3 &_origin, float _fovAngle) :
origin{_origin},
fovAngle{_fovAngle} {
SetFOV(_fovAngle);
}
void dae::Camera::Initialize(float _fovAngle, dae::Vector3 _origin, float _aspect) {
fovAngle = _fovAngle;
fov = tanf((fovAngle * TO_RADIANS) / 2.f);
aspect = _aspect;
origin = _origin;
}
void dae::Camera::SetFOV(float _fovAngle) {
fovAngle = _fovAngle;
fov = tanf((fovAngle * TO_RADIANS) / 2.f);
}
void dae::Camera::CalculateViewMatrix() {
viewMatrix = Matrix::CreateLookAtLH(origin, origin + forward, Vector3::UnitY);
Matrix temp = viewMatrix;
invViewMatrix = temp.Inverse();
right = invViewMatrix.GetAxisX();
up = invViewMatrix.GetAxisY();
forward = invViewMatrix.GetAxisZ();
}
void dae::Camera::CalculateProjectionMatrix() {
//TODO W3
ProjectionMatrix = Matrix::CreatePerspectiveFovLH(fov, aspect, zNear, zFar);
//DirectX Implementation => https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovlh
}
void dae::Camera::Update(const dae::Timer *pTimer) {
const float deltaTime = pTimer->GetElapsed();
//Keyboard Input
const uint8_t *pKeyboardState = SDL_GetKeyboardState(nullptr);
Vector3 zDirection{0.f, 0.f, 0.f};
const Vector3 xDirection{0.f, 0.f, 0.f};
const Vector3 yDirection{0.f, 0.f, 0.f};
float MovementSpeed{10.f};
if (pKeyboardState[SDL_SCANCODE_LSHIFT]) {
MovementSpeed *= 2;
}
if (pKeyboardState[SDL_SCANCODE_W]) {
origin += forward * deltaTime * MovementSpeed;
}
if (pKeyboardState[SDL_SCANCODE_A]) {
origin -= right * deltaTime * MovementSpeed;
}
if (pKeyboardState[SDL_SCANCODE_S]) {
origin -= forward * deltaTime * MovementSpeed;
}
if (pKeyboardState[SDL_SCANCODE_D]) {
origin += right * deltaTime * MovementSpeed;
}
if (pKeyboardState[SDL_SCANCODE_E]) {
origin += up * deltaTime * MovementSpeed;
}
if (pKeyboardState[SDL_SCANCODE_Q]) {
origin -= up * deltaTime * MovementSpeed;
}
bool rightStickMoved = false;
constexpr float DEADZONE = 5000;
if (GamePadController::GetInstance().isAnyControllerConnected()) {
//Controller
float LeftStickX = GamePadController::GetInstance().GetAxis(PLAYER1, SDL_CONTROLLER_AXIS_LEFTX);
float LeftStickY = GamePadController::GetInstance().GetAxis(PLAYER1, SDL_CONTROLLER_AXIS_LEFTY);
float RightStickX = GamePadController::GetInstance().GetAxis(PLAYER1, SDL_CONTROLLER_AXIS_RIGHTX);
float RightStickY = GamePadController::GetInstance().GetAxis(PLAYER1, SDL_CONTROLLER_AXIS_RIGHTY);
if (std::abs(LeftStickX) > DEADZONE) {
float correctedValue = remap(LeftStickX, -32767.f, 32767.f, -1.f, 1.f);
origin += right * deltaTime * MovementSpeed * correctedValue;
}
if (std::abs(LeftStickY) > DEADZONE) {
float correctedValue = -remap(LeftStickY, -32767, 32767, -1, 1);
origin += forward * deltaTime * MovementSpeed * correctedValue;
}
//Look around Controller
float lookMultiplier = 2.f;
if (std::abs(RightStickX) > DEADZONE) {
float correctedValue = remap(RightStickX, -32767.f, 32767.f, -1.f, 1.f);
totalYaw += correctedValue * deltaTime * lookMultiplier;
rightStickMoved = true;
}
if (std::abs(RightStickY) > DEADZONE) {
float correctedValue = -remap(RightStickY, -32767.f, 32767.f, -1.f, 1.f);
totalPitch += correctedValue * deltaTime * lookMultiplier;
rightStickMoved = true;
}
//Controller Up and Down Triggers
float LeftTrigger = GamePadController::GetInstance().GetAxis(PLAYER1, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
float RightTrigger = GamePadController::GetInstance().GetAxis(PLAYER1, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
if (std::abs(LeftTrigger) > DEADZONE) {
float correctedValue = remap(LeftTrigger, 0.f, 32767.f, 0.f, 1.f);
origin -= up * deltaTime * MovementSpeed * correctedValue;
}
if (std::abs(RightTrigger) > DEADZONE) {
float correctedValue = remap(RightTrigger, 0.f, 32767.f, 0.f, 1.f);
origin += up * deltaTime * MovementSpeed * correctedValue;
}
}
//Mouse Input
bool mousePosChange{false};
int mouseX{}, mouseY{};
const uint32_t mouseState = SDL_GetRelativeMouseState(&mouseX, &mouseY);
mouseY *= -1;
if (mouseState == SDL_BUTTON_X1) //rmb
{
totalYaw += (static_cast<float>(mouseX) * mouseSens) * TO_RADIANS;
totalPitch += (static_cast<float>(mouseY) * mouseSens) * TO_RADIANS;
mousePosChange = true;
} else if (mouseState == SDL_BUTTON_LEFT) {
zDirection = forward.Normalized() * static_cast<float>(-mouseY);
totalYaw += static_cast<float>(mouseX) * mouseSens * TO_RADIANS;
mousePosChange = true;
} else if (mouseState == SDL_BUTTON_X2) //lmb + rmb
{
origin.y += static_cast<float>(mouseY) / 2;
mousePosChange = true;
}
origin += ((zDirection + xDirection + yDirection) * cameraSpeed * deltaTime);
if (mousePosChange || rightStickMoved) {
const Matrix yawMatrix{Matrix::CreateRotationY(totalYaw)};
const Matrix pitchMatrix{Matrix::CreateRotationX(totalPitch)};
const Matrix finalRotation{pitchMatrix * yawMatrix};
forward = finalRotation.TransformVector(Vector3::UnitZ);
forward.Normalize();
}
//Update Matrices
CalculateViewMatrix();
CalculateProjectionMatrix(); //Try to optimize this - should only be called once or when fov/aspectRatio changes
}
dae::Matrix dae::Camera::GetViewProjectionMatrix() const {
return viewMatrix * ProjectionMatrix;
}

57
project/src/Camera.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef GP1_DIRECTX_CAMERA_H
#define GP1_DIRECTX_CAMERA_H
#include <cassert>
#include <SDL_keyboard.h>
#include <SDL_mouse.h>
#include "Timer.h"
#include "Vector3.h"
#include "MathHelpers.h"
#include "Matrix.h"
namespace dae {
class Camera {
public:
Camera() = default;
Camera(const Vector3 &_origin, float _fovAngle);
void Initialize(float _fovAngle = 90.f, Vector3 _origin = {0.f, 0.f, 0.f}, float _aspect = 1.f);
void SetFOV(float _fovAngle);
void CalculateViewMatrix();
void CalculateProjectionMatrix();
void Update(const Timer *pTimer);
Matrix GetViewProjectionMatrix() const;
private:
Vector3 origin{};
float fovAngle{90.f};
float fov{tanf((fovAngle * TO_RADIANS) / 2.f)};
Vector3 forward{Vector3::UnitZ};
Vector3 up{Vector3::UnitY};
Vector3 right{Vector3::UnitX};
float totalPitch{};
float totalYaw{};
Matrix invViewMatrix{};
Matrix viewMatrix{};
Matrix ProjectionMatrix{};
float aspect{};
float cameraSpeed{4.f};
float mouseSens{0.3f};
float zNear{.1f};
float zFar{100.f};
};
}
#endif //GP1_DIRECTX_CAMERA_H

124
project/src/ColorRGB.h Normal file
View File

@@ -0,0 +1,124 @@
#pragma once
#include "MathHelpers.h"
namespace dae
{
struct ColorRGB
{
float r{};
float g{};
float b{};
void MaxToOne()
{
const float maxValue = std::max(r, std::max(g, b));
if (maxValue > 1.f)
*this /= maxValue;
}
static ColorRGB Lerp(const ColorRGB& c1, const ColorRGB& c2, float factor)
{
return { Lerpf(c1.r, c2.r, factor), Lerpf(c1.g, c2.g, factor), Lerpf(c1.b, c2.b, factor) };
}
#pragma region ColorRGB (Member) Operators
const ColorRGB& operator+=(const ColorRGB& c)
{
r += c.r;
g += c.g;
b += c.b;
return *this;
}
ColorRGB operator+(const ColorRGB& c) const
{
return { r + c.r, g + c.g, b + c.b };
}
const ColorRGB& operator-=(const ColorRGB& c)
{
r -= c.r;
g -= c.g;
b -= c.b;
return *this;
}
ColorRGB operator-(const ColorRGB& c) const
{
return { r - c.r, g - c.g, b - c.b };
}
const ColorRGB& operator*=(const ColorRGB& c)
{
r *= c.r;
g *= c.g;
b *= c.b;
return *this;
}
ColorRGB operator*(const ColorRGB& c) const
{
return { r * c.r, g * c.g, b * c.b };
}
const ColorRGB& operator/=(const ColorRGB& c)
{
r /= c.r;
g /= c.g;
b /= c.b;
return *this;
}
const ColorRGB& operator*=(float s)
{
r *= s;
g *= s;
b *= s;
return *this;
}
ColorRGB operator*(float s) const
{
return { r * s, g * s,b * s };
}
const ColorRGB& operator/=(float s)
{
r /= s;
g /= s;
b /= s;
return *this;
}
ColorRGB operator/(float s) const
{
return { r / s, g / s,b / s };
}
#pragma endregion
};
//ColorRGB (Global) Operators
inline ColorRGB operator*(float s, const ColorRGB& c)
{
return c * s;
}
namespace colors
{
static ColorRGB Red{ 1,0,0 };
static ColorRGB Blue{ 0,0,1 };
static ColorRGB Green{ 0,1,0 };
static ColorRGB Yellow{ 1,1,0 };
static ColorRGB Cyan{ 0,1,1 };
static ColorRGB Magenta{ 1,0,1 };
static ColorRGB White{ 1,1,1 };
static ColorRGB Black{ 0,0,0 };
static ColorRGB Gray{ 0.5f,0.5f,0.5f };
}
}

103
project/src/Effect.cpp Normal file
View File

@@ -0,0 +1,103 @@
#include "pch.h"
#include "Effect.h"
#include <fstream>
Effect::Effect(ID3D11Device* devicePtr, const std::wstring& filePath)
{
const std::ifstream file(filePath);
if(!file)
std::wcout << L"File doesn't exist" << std::endl;
m_EffectPtr = LoadEffect(devicePtr, filePath);
m_TechniquePtr = m_EffectPtr->GetTechniqueByName("PointTechnique");
if(!m_TechniquePtr->IsValid())
std::wcout << L"Technique is not valid" << std::endl;
m_MatWorldViewProjVariablePtr = m_EffectPtr->GetVariableByName("gWorldViewProj")->AsMatrix();
if(!m_MatWorldViewProjVariablePtr->IsValid())
std::wcout << L"gWorldViewProj Matrix is not valid" << std::endl;
}
Effect::~Effect()
{
m_EffectPtr->Release();
m_EffectPtr = nullptr;
// m_TechniquePtr->Release();
// m_TechniquePtr = nullptr;
}
ID3DX11Effect* Effect::LoadEffect(ID3D11Device* devicePtr, const std::wstring& filePath) {
HRESULT result;
ID3D10Blob *errorBlobPtr{nullptr};
ID3DX11Effect *effectPtr;
DWORD shaderFlags = 0;
#if defined( DEBUG ) || defined( _DEBUG )
shaderFlags |= D3DCOMPILE_DEBUG;
shaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
result = D3DX11CompileEffectFromFile(filePath.c_str(),
nullptr,
nullptr,
shaderFlags,
0,
devicePtr,
&effectPtr,
&errorBlobPtr);
if (FAILED(result)) {
if (errorBlobPtr != nullptr) {
const char *errorsPtr = static_cast<char *>(errorBlobPtr->GetBufferPointer());
std::wstringstream ss;
for (UINT i{}; i < errorBlobPtr->GetBufferSize(); i++)
ss << errorsPtr[i];
OutputDebugStringW(ss.str().c_str());
errorBlobPtr->Release();
errorBlobPtr = nullptr;
return nullptr;
} else {
std::wstringstream ss;
ss << "EffectLoader: Failed to CreateEffectFromFile!\nPath: " << filePath;
std::wcout << ss.str() << std::endl;
return nullptr;
}
}
std::cout << "Effect loaded" << std::endl;
return effectPtr;
}
void Effect::SetWorldViewProjMatrix(const dae::Matrix &matrix) {
m_MatWorldViewProjVariablePtr->SetMatrix(reinterpret_cast<const float*>(&matrix));
}
void Effect::SetMaterial(const Material &material) {
if(material.diffuseTexturePtr)
m_EffectPtr->GetVariableByName("gDiffuseMap")->AsShaderResource()->SetResource(material.diffuseTexturePtr->GetSrv());
}
void Effect::NextTechnique() {
switch (m_TechniqueType) {
case TechniqueType::Point:
m_TechniqueType = TechniqueType::Linear;
m_TechniquePtr = m_EffectPtr->GetTechniqueByName("LinearTechnique");
std::cout << "Linear" << std::endl;
break;
case TechniqueType::Linear:
m_TechniqueType = TechniqueType::Anisotropic;
m_TechniquePtr = m_EffectPtr->GetTechniqueByName("AnisotropicTechnique");
std::cout << "Anisotropic" << std::endl;
break;
case TechniqueType::Anisotropic:
m_TechniqueType = TechniqueType::Point;
m_TechniquePtr = m_EffectPtr->GetTechniqueByName("PointTechnique");
std::cout << "Point" << std::endl;
break;
}
}

36
project/src/Effect.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
#include "Mesh.h"
enum class TechniqueType{
Point,
Linear,
Anisotropic
};
class Effect final
{
static inline constexpr char TECHNIQUE_NAME[] = "DefaultTechnique";
public:
Effect(ID3D11Device* devicePtr, const std::wstring& filePath);
~Effect();
inline ID3DX11Effect* GetEffectPtr() const { return m_EffectPtr; }
inline ID3DX11EffectTechnique* GetTechniquePtr() const { return m_TechniquePtr; }
void SetWorldViewProjMatrix(const dae::Matrix &matrix);
void SetMaterial(const Material &material);
void NextTechnique();
private:
ID3DX11Effect* m_EffectPtr{ nullptr };
ID3DX11EffectTechnique* m_TechniquePtr{};
static ID3DX11Effect* LoadEffect(ID3D11Device* devicePtr, const std::wstring& filePath);
ID3DX11EffectMatrixVariable* m_MatWorldViewProjVariablePtr{};
TechniqueType m_TechniqueType{ TechniqueType::Linear };
};

View File

@@ -0,0 +1,55 @@
//
// Created by Bram on 11/12/2024.
//
#include "GamePadController.h"
GamePadController::GamePadController() = default;
GamePadController::~GamePadController() {
for (auto pGameController : m_pGameControllers) {
SDL_GameControllerClose(pGameController);
}
}
void GamePadController::Init() {
const int numJoysticks = SDL_NumJoysticks();
for (int i = 0; i < numJoysticks; i++) {
if (SDL_IsGameController(i)) {
SDL_GameController *pController = SDL_GameControllerOpen(i);
if (pController) {
m_pGameControllers.push_back(pController);
m_GamePads.push_back(GamePad());
}
}
}
}
void GamePadController::Update() {
for (int i = 0; i < m_pGameControllers.size(); i++) {
SDL_GameController *pController = m_pGameControllers[i];
GamePad &gamePad = m_GamePads[i];
for (int j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++) {
gamePad.buttons[j] = SDL_GameControllerGetButton(pController, (SDL_GameControllerButton) j);
}
for (int j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++) {
gamePad.axis[j] = SDL_GameControllerGetAxis(pController, (SDL_GameControllerAxis) j);
}
}
}
bool GamePadController::IsButtonDown(Controllers controller, int button) const {
return m_GamePads[controller].buttons[button];
}
bool GamePadController::IsButtonUp(Controllers controller, int button) const {
return !m_GamePads[controller].buttons[button];
}
float GamePadController::GetAxis(Controllers controller, int axis) const {
return m_GamePads[controller].axis[axis];
}

View File

@@ -0,0 +1,43 @@
#ifndef GP1_DIRECTX_GAMEPADCONTROLLER_H
#define GP1_DIRECTX_GAMEPADCONTROLLER_H
#include <vector>
#include "SDL_gamecontroller.h"
#include "SDL.h"
struct GamePad{
bool buttons[SDL_CONTROLLER_BUTTON_MAX];
float axis[SDL_CONTROLLER_AXIS_MAX];
};
enum Controllers {PLAYER1, PLAYER2, PLAYER3, PLAYER4};
class GamePadController {
public:
static GamePadController& GetInstance()
{
static GamePadController instance;
return instance;
}
~GamePadController();
void Init();
void Update();
bool IsButtonDown(Controllers controller, int button) const;
bool IsButtonUp(Controllers controller, int button) const;
float GetAxis(Controllers controller, int axis) const;
bool isAnyControllerConnected() const { return !m_pGameControllers.empty(); }
private:
GamePadController();
std::vector<SDL_GameController*> m_pGameControllers;
std::vector<GamePad> m_GamePads;
};
#endif //GP1_DIRECTX_GAMEPADCONTROLLER_H

7
project/src/Math.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include "ColorRGB.h"
#include "Vector2.h"
#include "Vector3.h"
#include "Vector4.h"
#include "Matrix.h"
#include "MathHelpers.h"

57
project/src/MathHelpers.h Normal file
View File

@@ -0,0 +1,57 @@
#pragma once
#include <cmath>
namespace dae {
/* --- HELPER STRUCTS --- */
struct Int2 {
int x{};
int y{};
};
/* --- CONSTANTS --- */
constexpr auto PI = 3.14159265358979323846f;
constexpr auto PI_DIV_2 = 1.57079632679489661923f;
constexpr auto PI_DIV_4 = 0.785398163397448309616f;
constexpr auto PI_2 = 6.283185307179586476925f;
constexpr auto PI_4 = 12.56637061435917295385f;
constexpr auto TO_DEGREES = (180.0f / PI);
constexpr auto TO_RADIANS(PI / 180.0f);
/* --- HELPER FUNCTIONS --- */
inline float Square(float a) {
return a * a;
}
inline float Lerpf(float a, float b, float factor) {
return ((1 - factor) * a) + (factor * b);
}
inline bool AreEqual(float a, float b, float epsilon = 0.0001f) {
return abs(a - b) < epsilon;
}
inline int Clamp(const int v, int min, int max) {
if (v < min) return min;
if (v > max) return max;
return v;
}
inline float Clamp(const float v, float min, float max) {
if (v < min) return min;
if (v > max) return max;
return v;
}
inline float Saturate(const float v) {
if (v < 0.f) return 0.f;
if (v > 1.f) return 1.f;
return v;
}
inline float remap(float value, float low1, float high1, float low2, float high2) {
return (value - low1) / (high1 - low1) * (high2 - low2) + low2;
}
}

301
project/src/Matrix.cpp Normal file
View File

@@ -0,0 +1,301 @@
#include "pch.h"
#include "Matrix.h"
#include <cassert>
#include "MathHelpers.h"
#include <cmath>
namespace dae {
Matrix::Matrix(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis, const Vector3& t) :
Matrix({ xAxis, 0 }, { yAxis, 0 }, { zAxis, 0 }, { t, 1 })
{
}
Matrix::Matrix(const Vector4& xAxis, const Vector4& yAxis, const Vector4& zAxis, const Vector4& t)
{
data[0] = xAxis;
data[1] = yAxis;
data[2] = zAxis;
data[3] = t;
}
Matrix::Matrix(const Matrix& m)
{
data[0] = m[0];
data[1] = m[1];
data[2] = m[2];
data[3] = m[3];
}
Vector3 Matrix::TransformVector(const Vector3& v) const
{
return TransformVector(v.x, v.y, v.z);
}
Vector3 Matrix::TransformVector(float x, float y, float z) const
{
return Vector3{
data[0].x * x + data[1].x * y + data[2].x * z,
data[0].y * x + data[1].y * y + data[2].y * z,
data[0].z * x + data[1].z * y + data[2].z * z
};
}
Vector3 Matrix::TransformPoint(const Vector3& p) const
{
return TransformPoint(p.x, p.y, p.z);
}
Vector3 Matrix::TransformPoint(float x, float y, float z) const
{
return Vector3{
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x,
data[0].y * x + data[1].y * y + data[2].y * z + data[3].y,
data[0].z * x + data[1].z * y + data[2].z * z + data[3].z,
};
}
Vector4 Matrix::TransformPoint(const Vector4& p) const
{
return TransformPoint(p.x, p.y, p.z, p.w);
}
Vector4 Matrix::TransformPoint(float x, float y, float z, float w) const
{
return Vector4{
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x,
data[0].y * x + data[1].y * y + data[2].y * z + data[3].y,
data[0].z * x + data[1].z * y + data[2].z * z + data[3].z,
data[0].w * x + data[1].w * y + data[2].w * z + data[3].w
};
}
const Matrix& Matrix::Transpose()
{
Matrix result{};
for (int r{ 0 }; r < 4; ++r)
{
for (int c{ 0 }; c < 4; ++c)
{
result[r][c] = data[c][r];
}
}
data[0] = result[0];
data[1] = result[1];
data[2] = result[2];
data[3] = result[3];
return *this;
}
const Matrix& Matrix::Inverse()
{
//Optimized Inverse as explained in FGED1 - used widely in other libraries too.
const Vector3& a = data[0];
const Vector3& b = data[1];
const Vector3& c = data[2];
const Vector3& d = data[3];
const float x = data[0][3];
const float y = data[1][3];
const float z = data[2][3];
const float w = data[3][3];
Vector3 s = Vector3::Cross(a, b);
Vector3 t = Vector3::Cross(c, d);
Vector3 u = a * y - b * x;
Vector3 v = c * w - d * z;
const float det = Vector3::Dot(s, v) + Vector3::Dot(t, u);
assert((!AreEqual(det, 0.f)) && "ERROR: determinant is 0, there is no INVERSE!");
const float invDet = 1.f / det;
s *= invDet; t *= invDet; u *= invDet; v *= invDet;
const Vector3 r0 = Vector3::Cross(b, v) + t * y;
const Vector3 r1 = Vector3::Cross(v, a) - t * x;
const Vector3 r2 = Vector3::Cross(d, u) + s * w;
//Vector3 r3 = Vector3::Cross(u, c) - s * z;
data[0] = Vector4{ r0.x, r1.x, r2.x, 0.f };
data[1] = Vector4{ r0.y, r1.y, r2.y, 0.f };
data[2] = Vector4{ r0.z, r1.z, r2.z, 0.f };
data[3] = {-Vector3::Dot(b, t),Vector3::Dot(a, t),-Vector3::Dot(d, s),Vector3::Dot(c, s) };
return *this;
}
Matrix Matrix::Transpose(const Matrix& m)
{
Matrix out{ m };
out.Transpose();
return out;
}
Matrix Matrix::Inverse(const Matrix& m)
{
Matrix out{ m };
out.Inverse();
return out;
}
Matrix Matrix::CreateLookAtLH(const Vector3& origin, const Vector3& forward, const Vector3& up)
{
Vector3 zAxis = (forward - origin).Normalized();
Vector3 xAxis = Vector3::Cross(up, zAxis).Normalized();
Vector3 yAxis = Vector3::Cross(zAxis, xAxis).Normalized();
Vector3 trans =
{
-Vector3::Dot(xAxis, origin),
-Vector3::Dot(yAxis, origin),
-Vector3::Dot(zAxis, origin)
};
return {
{xAxis.x, yAxis.x, zAxis.x},
{xAxis.y, yAxis.y, zAxis.y},
{xAxis.z, yAxis.z, zAxis.z},
{trans.x, trans.y, trans.z}
};
}
Matrix Matrix::CreatePerspectiveFovLH(float fovy, float aspect, float zn, float zf)
{
return Matrix(
{ 1.f / (aspect * fovy), 0, 0, 0 },
{ 0, 1.f / fovy, 0, 0 },
{ 0, 0, (zf) / (zf - zn), 1 },
{ 0, 0, -(zf * zn) / (zf - zn), 0 }
);
}
Vector3 Matrix::GetAxisX() const
{
return data[0];
}
Vector3 Matrix::GetAxisY() const
{
return data[1];
}
Vector3 Matrix::GetAxisZ() const
{
return data[2];
}
Vector3 Matrix::GetTranslation() const
{
return data[3];
}
Matrix Matrix::CreateTranslation(float x, float y, float z)
{
return CreateTranslation({ x, y, z });
}
Matrix Matrix::CreateTranslation(const Vector3& t)
{
return { Vector3::UnitX, Vector3::UnitY, Vector3::UnitZ, t };
}
Matrix Matrix::CreateRotationX(float pitch)
{
return {
{1, 0, 0, 0},
{0, cos(pitch), -sin(pitch), 0},
{0, sin(pitch), cos(pitch), 0},
{0, 0, 0, 1}
};
}
Matrix Matrix::CreateRotationY(float yaw)
{
return {
{cos(yaw), 0, -sin(yaw), 0},
{0, 1, 0, 0},
{sin(yaw), 0, cos(yaw), 0},
{0, 0, 0, 1}
};
}
Matrix Matrix::CreateRotationZ(float roll)
{
return {
{cos(roll), sin(roll), 0, 0},
{-sin(roll), cos(roll), 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
};
}
Matrix Matrix::CreateRotation(float pitch, float yaw, float roll)
{
return CreateRotation({ pitch, yaw, roll });
}
Matrix Matrix::CreateRotation(const Vector3& r)
{
return CreateRotationX(r[0]) * CreateRotationY(r[1]) * CreateRotationZ(r[2]);
}
Matrix Matrix::CreateScale(float sx, float sy, float sz)
{
return { {sx, 0, 0}, {0, sy, 0}, {0, 0, sz}, Vector3::Zero };
}
Matrix Matrix::CreateScale(const Vector3& s)
{
return CreateScale(s[0], s[1], s[2]);
}
#pragma region Operator Overloads
Vector4& Matrix::operator[](int index)
{
assert(index <= 3 && index >= 0);
return data[index];
}
Vector4 Matrix::operator[](int index) const
{
assert(index <= 3 && index >= 0);
return data[index];
}
Matrix Matrix::operator*(const Matrix& m) const
{
Matrix result{};
Matrix m_transposed = Transpose(m);
for (int r{ 0 }; r < 4; ++r)
{
for (int c{ 0 }; c < 4; ++c)
{
result[r][c] = Vector4::Dot(data[r], m_transposed[c]);
}
}
return result;
}
const Matrix& Matrix::operator*=(const Matrix& m)
{
Matrix copy{ *this };
Matrix m_transposed = Transpose(m);
for (int r{ 0 }; r < 4; ++r)
{
for (int c{ 0 }; c < 4; ++c)
{
data[r][c] = Vector4::Dot(copy[r], m_transposed[c]);
}
}
return *this;
}
#pragma endregion
}

75
project/src/Matrix.h Normal file
View File

@@ -0,0 +1,75 @@
#pragma once
#include "Vector3.h"
#include "Vector4.h"
namespace dae {
struct Matrix
{
Matrix() = default;
Matrix(
const Vector3& xAxis,
const Vector3& yAxis,
const Vector3& zAxis,
const Vector3& t);
Matrix(
const Vector4& xAxis,
const Vector4& yAxis,
const Vector4& zAxis,
const Vector4& t);
Matrix(const Matrix& m);
Vector3 TransformVector(const Vector3& v) const;
Vector3 TransformVector(float x, float y, float z) const;
Vector3 TransformPoint(const Vector3& p) const;
Vector3 TransformPoint(float x, float y, float z) const;
Vector4 TransformPoint(const Vector4& p) const;
Vector4 TransformPoint(float x, float y, float z, float w) const;
const Matrix& Transpose();
const Matrix& Inverse();
Vector3 GetAxisX() const;
Vector3 GetAxisY() const;
Vector3 GetAxisZ() const;
Vector3 GetTranslation() const;
static Matrix CreateTranslation(float x, float y, float z);
static Matrix CreateTranslation(const Vector3& t);
static Matrix CreateRotationX(float pitch);
static Matrix CreateRotationY(float yaw);
static Matrix CreateRotationZ(float roll);
static Matrix CreateRotation(float pitch, float yaw, float roll);
static Matrix CreateRotation(const Vector3& r);
static Matrix CreateScale(float sx, float sy, float sz);
static Matrix CreateScale(const Vector3& s);
static Matrix Transpose(const Matrix& m);
static Matrix Inverse(const Matrix& m);
static Matrix CreateLookAtLH(const Vector3& origin, const Vector3& forward, const Vector3& up);
static Matrix CreatePerspectiveFovLH(float fovy, float aspect, float zn, float zf);
Vector4& operator[](int index);
Vector4 operator[](int index) const;
Matrix operator*(const Matrix& m) const;
const Matrix& operator*=(const Matrix& m);
private:
//Row-Major Matrix
Vector4 data[4]
{
{1,0,0,0}, //xAxis
{0,1,0,0}, //yAxis
{0,0,1,0}, //zAxis
{0,0,0,1} //T
};
// v0x v0y v0z v0w
// v1x v1y v1z v1w
// v2x v2y v2z v2w
// v3x v3y v3z v3w
};
}

127
project/src/Mesh.cpp Normal file
View File

@@ -0,0 +1,127 @@
#include <cassert>
#include "pch.h"
#include "Mesh.h"
#include "Effect.h"
Mesh::Mesh(ID3D11Device* devicePtr, const std::vector<VertexIn>& verticesIn, const std::vector<Uint32>& indices, const Material& material) :
m_EffectPtr(new Effect{ devicePtr, L"resources/PosCol3D.fx" }),
m_InputLayoutPtr(nullptr),
m_VertexBufferPtr(nullptr),
m_IndexBufferPtr(nullptr),
m_VerticesIn(verticesIn),
m_Indices(indices),
m_IndicesCount(static_cast<UINT>(m_Indices.size())),
m_Material(material)
{
HRESULT result;
D3D11_BUFFER_DESC bufferDesc{};
D3D11_SUBRESOURCE_DATA subresourceData{};
m_EffectPtr->SetMaterial(m_Material);
//Create vertex layout
static constexpr uint32_t vertexElementCount{ 3 };
D3D11_INPUT_ELEMENT_DESC vertexDesc[vertexElementCount]{};
vertexDesc[0].SemanticName = "POSITION";
vertexDesc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
vertexDesc[0].AlignedByteOffset = 0;
vertexDesc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexDesc[1].SemanticName = "COLOR";
vertexDesc[1].Format = DXGI_FORMAT_R32G32B32_FLOAT;
vertexDesc[1].AlignedByteOffset = offsetof(VertexIn, color);
vertexDesc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
vertexDesc[2].SemanticName = "TEXCOORD";
vertexDesc[2].Format = DXGI_FORMAT_R32G32_FLOAT;
vertexDesc[2].AlignedByteOffset = offsetof(VertexIn, uv);
vertexDesc[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
//Create input layout
D3DX11_PASS_DESC passDesc{};
ID3DX11EffectTechnique* techniquePtr = m_EffectPtr->GetTechniquePtr();
techniquePtr->GetPassByIndex(0)->GetDesc(&passDesc);
result = devicePtr->CreateInputLayout(
vertexDesc,
vertexElementCount,
passDesc.pIAInputSignature,
passDesc.IAInputSignatureSize,
&m_InputLayoutPtr);
assert(result == S_OK && "Creating input layout failed");
//Create vertex buffer
bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
bufferDesc.ByteWidth = sizeof(verticesIn) * static_cast<uint32_t>(verticesIn.size());
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
subresourceData.pSysMem = verticesIn.data();
result = devicePtr->CreateBuffer(&bufferDesc, &subresourceData, &m_VertexBufferPtr);
assert(result == S_OK && "Creating vertex buffer failed");
//Create index buffer
bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
bufferDesc.ByteWidth = sizeof(uint32_t) * m_IndicesCount;
bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
subresourceData.pSysMem = m_Indices.data();
result = devicePtr->CreateBuffer(&bufferDesc, &subresourceData, &m_IndexBufferPtr);
assert(result == S_OK && "Creating index buffer failed");
}
Mesh::~Mesh()
{
m_InputLayoutPtr->Release();
m_InputLayoutPtr = nullptr;
m_VertexBufferPtr->Release();
m_VertexBufferPtr = nullptr;
m_IndexBufferPtr->Release();
m_IndexBufferPtr = nullptr;
delete m_EffectPtr;
m_EffectPtr = nullptr;
}
void Mesh::Render(ID3D11DeviceContext* deviceContextPtr, const Matrix& worldViewProj) const
{
m_EffectPtr->SetWorldViewProjMatrix(worldViewProj);
//1. Set primitive topology
deviceContextPtr->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//2. Set input layout
deviceContextPtr->IASetInputLayout(m_InputLayoutPtr);
//3. Set vertex buffer
constexpr UINT stride = sizeof(VertexIn);
constexpr UINT offset = 0;
deviceContextPtr->IASetVertexBuffers(0, 1, &m_VertexBufferPtr, &stride, &offset);
//4. Set index buffer
deviceContextPtr->IASetIndexBuffer(m_IndexBufferPtr, DXGI_FORMAT_R32_UINT, 0);
//5. Draw
D3DX11_TECHNIQUE_DESC techniqueDesc{};
m_EffectPtr->GetTechniquePtr()->GetDesc(&techniqueDesc);
for (UINT p{}; p < techniqueDesc.Passes; p++)
{
m_EffectPtr->GetTechniquePtr()->GetPassByIndex(p)->Apply(0, deviceContextPtr);
deviceContextPtr->DrawIndexed(m_IndicesCount, 0, 0);
}
}
void Mesh::NextTechnique() {
m_EffectPtr->NextTechnique();
}

63
project/src/Mesh.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#include "Texture.h"
class Effect;
using namespace dae;
struct VertexIn;
struct VertexOut;
struct Material{
Texture* diffuseTexturePtr{ nullptr };
~Material(){
if(diffuseTexturePtr){
delete diffuseTexturePtr;
}
}
};
class Mesh final
{
public:
Mesh(ID3D11Device* devicePtr, const std::vector<VertexIn>& verticesIn, const std::vector<Uint32>& indices, const Material& material);
~Mesh();
void Render(ID3D11DeviceContext* deviceContextPtr, const Matrix& worldViewProj) const;
void NextTechnique();
private:
Effect* m_EffectPtr;
ID3D11InputLayout* m_InputLayoutPtr;
ID3D11Buffer* m_VertexBufferPtr;
ID3D11Buffer* m_IndexBufferPtr;
std::vector<VertexIn> m_VerticesIn;
std::vector<uint32_t> m_Indices;
UINT m_IndicesCount;
Material m_Material{};
};
struct VertexIn
{
Vector3 position{};
Vector3 color{};
Vector2 uv{};
// Vector3 normal{};
// Vector3 tangent{};
};
struct VertexOut
{
Vector4 position{};
Vector3 color{};
Vector2 uv{};
// Vector3 normal{};
};

212
project/src/Renderer.cpp Normal file
View File

@@ -0,0 +1,212 @@
#include "pch.h"
#include "Renderer.h"
#include "Mesh.h"
#include "Utils.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 << "DirectX is initialized and ready!\n";
} else {
std::cout << "DirectX initialization failed!\n";
}
std::vector<VertexIn> vertices{};
std::vector<uint32_t> indices{};
if(Utils::ParseOBJ("resources/vehicle.obj", vertices, indices, false)){
std::cout << "Model Loaded" << std::endl;
} else {
std::cout << "Model failed to load" << std::endl;
}
std::vector<VertexIn> quad = {
{{-1.f, 1.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 0.f}},
{{1.f, 1.f, 0.f}, {0.f, 1.f, 0.f}, {1.f, 0.f}},
{{1.f, -1.f, 0.f}, {0.f, 0.f, 1.f}, {1.f, 1.f}},
{{-1.f, -1.f, 0.f}, {1.f, 1.f, 1.f}, {0.f, 1.f}}
};
std::vector<uint32_t> quadIndices = {
0, 1, 2,
0, 2, 3
};
std::cout << "Vertices: " << vertices.size() << " Indices: " << indices.size() << std::endl;
m_material.diffuseTexturePtr = Texture::LoadFromFile("resources/vehicle_diffuse.png", m_DevicePtr);
m_mesh = new Mesh(m_DevicePtr, quad, quadIndices, m_material);
m_Camera = Camera(Vector3(0.f, 0.f, -5.f), 90.f);
m_Camera.Initialize(90.f, Vector3(0.f, 0.f, -5.f), 1.f);
}
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();
delete m_mesh;
}
void Renderer::Update(const Timer *pTimer) {
m_Camera.Update(pTimer);
}
void Renderer::Render() const {
if (!m_IsInitialized)
return;
//Clear back buffer
const float clearColor[] = { .39f, .59f, .93f, 1.f };
m_DeviceContextPtr->ClearRenderTargetView(m_RenderTargetViewPtr, clearColor);
m_DeviceContextPtr->ClearDepthStencilView(m_DepthStencilViewPtr, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
Matrix worldViewProj = m_Camera.GetViewProjectionMatrix();
Matrix modelMatrix{};
//Render
m_mesh->Render(m_DeviceContextPtr, worldViewProj * modelMatrix);
//Present
m_SwapChainPtr->Present(0, 0);
}
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<void**>(&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<void**>(&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<float>(m_Width);
viewport.Height = static_cast<float>(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::SwitchTechnique() {
m_mesh->NextTechnique();
}
}

54
project/src/Renderer.h Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
#include "Mesh.h"
#include "Camera.h"
struct SDL_Window;
struct SDL_Surface;
namespace dae
{
class Renderer final
{
public:
Renderer(SDL_Window* pWindow);
~Renderer();
Renderer(const Renderer&) = delete;
Renderer(Renderer&&) noexcept = delete;
Renderer& operator=(const Renderer&) = delete;
Renderer& operator=(Renderer&&) noexcept = delete;
void Update(const Timer* pTimer);
void Render() const;
//Switching Functions
void SwitchTechnique();
private:
SDL_Window* m_pWindow{};
int m_Width{};
int m_Height{};
bool m_IsInitialized{ false };
//DIRECTX
HRESULT InitializeDirectX();
ID3D11Device* m_DevicePtr{};
ID3D11DeviceContext* m_DeviceContextPtr{};
IDXGISwapChain* m_SwapChainPtr{};
ID3D11Texture2D* m_DepthStencilBufferPtr{};
ID3D11DepthStencilView* m_DepthStencilViewPtr{};
ID3D11Resource* m_RenderTargetBufferPtr{};
ID3D11RenderTargetView* m_RenderTargetViewPtr{};
Mesh* m_mesh{ nullptr };
Material m_material{};
Camera m_Camera{};
};
}

51
project/src/Texture.cpp Normal file
View File

@@ -0,0 +1,51 @@
#include "Texture.h"
Texture::~Texture() {
m_TextureResourceViewPtr->Release();
m_TexturePtr->Release();
}
Texture *Texture::LoadFromFile(const std::string &path, ID3D11Device *devicePtr) {
SDL_Surface *surface = IMG_Load(path.c_str());
if (!surface) {
std::cerr << "Failed to load texture: " << path << std::endl;
return nullptr;
}
Texture *texture = new Texture(surface, devicePtr);
return texture;
}
Texture::Texture(SDL_Surface *surfacePtr, ID3D11Device *devicePtr) {
DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
D3D11_TEXTURE2D_DESC desc{};
desc.Width = surfacePtr->w;
desc.Height = surfacePtr->h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = surfacePtr->pixels;
initData.SysMemPitch = static_cast<UINT>(surfacePtr->pitch);
initData.SysMemSlicePitch = static_cast<UINT>(surfacePtr->h * surfacePtr->pitch);
HRESULT hr = devicePtr->CreateTexture2D(&desc, &initData, &m_TexturePtr);
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc{};
SRVDesc.Format = format;
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
SRVDesc.Texture2D.MipLevels = 1;
hr = devicePtr->CreateShaderResourceView(m_TexturePtr, &SRVDesc, &m_TextureResourceViewPtr);
SDL_FreeSurface(surfacePtr);
}

28
project/src/Texture.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef GP1_DIRECTX_TEXTURE_H
#define GP1_DIRECTX_TEXTURE_H
#include <iostream>
#include <string>
#include <d3d11.h>
#include "Texture.h"
#include "SDL_surface.h"
#include "SDL_image.h"
class Texture {
public:
~Texture();
static Texture* LoadFromFile(const std::string& path, ID3D11Device* devicePtr);
inline ID3D11ShaderResourceView* GetSrv() const { return m_TextureResourceViewPtr; }
private:
Texture(SDL_Surface* surfacePtr, ID3D11Device* devicePtr);
ID3D11ShaderResourceView* m_TextureResourceViewPtr{};
ID3D11Texture2D* m_TexturePtr{};
};
#endif //GP1_DIRECTX_TEXTURE_H

86
project/src/Timer.cpp Normal file
View File

@@ -0,0 +1,86 @@
#include "pch.h"
#include "Timer.h"
namespace dae
{
Timer::Timer()
{
const uint64_t countsPerSecond = SDL_GetPerformanceFrequency();
m_SecondsPerCount = 1.0f / static_cast<float>(countsPerSecond);
}
void Timer::Reset()
{
const uint64_t currentTime = SDL_GetPerformanceCounter();
m_BaseTime = currentTime;
m_PreviousTime = currentTime;
m_StopTime = 0;
m_FPSTimer = 0.0f;
m_FPSCount = 0;
m_IsStopped = false;
}
void Timer::Start()
{
const uint64_t startTime = SDL_GetPerformanceCounter();
if (m_IsStopped)
{
m_PausedTime += (startTime - m_StopTime);
m_PreviousTime = startTime;
m_StopTime = 0;
m_IsStopped = false;
}
}
void Timer::Update()
{
if (m_IsStopped)
{
m_FPS = 0;
m_ElapsedTime = 0.0f;
m_TotalTime = static_cast<float>(((m_StopTime - m_PausedTime) - m_BaseTime) * m_BaseTime);
return;
}
const uint64_t currentTime = SDL_GetPerformanceCounter();
m_CurrentTime = currentTime;
m_ElapsedTime = static_cast<float>(m_CurrentTime - m_PreviousTime) * m_SecondsPerCount;
m_PreviousTime = m_CurrentTime;
if (m_ElapsedTime < 0.0f)
m_ElapsedTime = 0.0f;
if (m_ForceElapsedUpperBound && m_ElapsedTime > m_ElapsedUpperBound)
{
m_ElapsedTime = m_ElapsedUpperBound;
}
m_TotalTime = static_cast<float>(m_CurrentTime - m_PausedTime - m_BaseTime) * m_SecondsPerCount;
//FPS LOGIC
m_FPSTimer += m_ElapsedTime;
++m_FPSCount;
if (m_FPSTimer >= 1.0f)
{
m_dFPS = static_cast<float>(m_FPSCount) / m_FPSTimer;
m_FPS = m_FPSCount;
m_FPSCount = 0;
m_FPSTimer = 0.0f;
}
}
void Timer::Stop()
{
if (!m_IsStopped)
{
const uint64_t currentTime = SDL_GetPerformanceCounter();
m_StopTime = currentTime;
m_IsStopped = true;
}
}
}

50
project/src/Timer.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
//Standard includes
#include <cstdint>
namespace dae
{
class Timer
{
public:
Timer();
virtual ~Timer() = default;
Timer(const Timer&) = delete;
Timer(Timer&&) noexcept = delete;
Timer& operator=(const Timer&) = delete;
Timer& operator=(Timer&&) noexcept = delete;
void Reset();
void Start();
void Update();
void Stop();
uint32_t GetFPS() const { return m_FPS; };
float GetdFPS() const { return m_dFPS; };
float GetElapsed() const { return m_ElapsedTime; };
float GetTotal() const { return m_TotalTime; };
bool IsRunning() const { return !m_IsStopped; };
private:
uint64_t m_BaseTime = 0;
uint64_t m_PausedTime = 0;
uint64_t m_StopTime = 0;
uint64_t m_PreviousTime = 0;
uint64_t m_CurrentTime = 0;
uint32_t m_FPS = 0;
float m_dFPS = 0.0f;
uint32_t m_FPSCount = 0;
float m_TotalTime = 0.0f;
float m_ElapsedTime = 0.0f;
float m_SecondsPerCount = 0.0f;
float m_ElapsedUpperBound = 0.03f;
float m_FPSTimer = 0.0f;
bool m_IsStopped = true;
bool m_ForceElapsedUpperBound = false;
};
}

9
project/src/Utils.cpp Normal file
View File

@@ -0,0 +1,9 @@
#include "Utils.h"
#include <fstream>
#include <vector>
#include <iostream>
#include <string>
#include "Math.h"
#include "Mesh.h"

145
project/src/Utils.h Normal file
View File

@@ -0,0 +1,145 @@
#pragma once
#include <fstream>
#include <vector>
#include "Math.h"
#include "Mesh.h"
namespace dae
{
namespace Utils
{
//Just parses vertices and indices
#pragma warning(push)
#pragma warning(disable : 4505) //Warning unreferenced local function
static bool ParseOBJ(const std::string& filename, std::vector<VertexIn>& vertices, std::vector<uint32_t>& indices, bool flipAxisAndWinding = true) {
std::ifstream file(filename);
if (!file)
return false;
std::vector<Vector3> positions{};
std::vector<Vector3> normals{};
std::vector<Vector2> UVs{};
vertices.clear();
indices.clear();
std::string sCommand;
// start a while iteration ending when the end of file is reached (ios::eof)
while (!file.eof()) {
//read the first word of the string, use the >> operator (istream::operator>>)
file >> sCommand;
//use conditional statements to process the different commands
if (sCommand == "#") {
// Ignore Comment
} else if (sCommand == "v") {
//Vertex
float x, y, z;
file >> x >> y >> z;
positions.emplace_back(x, y, z);
} else if (sCommand == "vt") {
// Vertex TexCoord
float u, v;
file >> u >> v;
UVs.emplace_back(u, 1 - v);
} else if (sCommand == "vn") {
// Vertex Normal
float x, y, z;
file >> x >> y >> z;
normals.emplace_back(x, y, z);
} else if (sCommand == "f") {
//if a face is read:
//construct the 3 vertices, add them to the vertex array
//add three indices to the index array
//add the material index as attibute to the attribute array
//
// Faces or triangles
VertexIn vertex{};
size_t iPosition, iTexCoord, iNormal;
uint32_t tempIndices[3];
for (size_t iFace = 0; iFace < 3; iFace++) {
// OBJ format uses 1-based arrays
file >> iPosition;
vertex.position = positions[iPosition - 1].ToVector4();
if ('/' == file.peek())//is next in buffer == '/' ?
{
file.ignore();//read and ignore one element ('/')
if ('/' != file.peek()) {
// Optional texture coordinate
file >> iTexCoord;
vertex.uv = UVs[iTexCoord - 1];
}
if ('/' == file.peek()) {
file.ignore();
// Optional vertex normal
file >> iNormal;
// vertex.normal = normals[iNormal - 1];
}
}
vertices.push_back(vertex);
tempIndices[iFace] = uint32_t(vertices.size()) - 1;
//indices.push_back(uint32_t(vertices.size()) - 1);
}
indices.push_back(tempIndices[0]);
if (flipAxisAndWinding) {
indices.push_back(tempIndices[2]);
indices.push_back(tempIndices[1]);
} else {
indices.push_back(tempIndices[1]);
indices.push_back(tempIndices[2]);
}
}
//read till end of line and ignore all remaining chars
file.ignore(1000, '\n');
}
// //Cheap Tangent Calculations
// for (uint32_t i = 0; i < indices.size(); i += 3) {
// uint32_t index0 = indices[i];
// uint32_t index1 = indices[size_t(i) + 1];
// uint32_t index2 = indices[size_t(i) + 2];
//
// const Vector3 &p0 = vertices[index0].position;
// const Vector3 &p1 = vertices[index1].position;
// const Vector3 &p2 = vertices[index2].position;
// const Vector2 &uv0 = vertices[index0].uv;
// const Vector2 &uv1 = vertices[index1].uv;
// const Vector2 &uv2 = vertices[index2].uv;
//
// const Vector3 edge0 = p1 - p0;
// const Vector3 edge1 = p2 - p0;
// const Vector2 diffX = Vector2(uv1.x - uv0.x, uv2.x - uv0.x);
// const Vector2 diffY = Vector2(uv1.y - uv0.y, uv2.y - uv0.y);
// float r = 1.f / Vector2::Cross(diffX, diffY);
//
// Vector3 tangent = (edge0 * diffY.y - edge1 * diffY.x) * r;
// vertices[index0].tangent += tangent;
// vertices[index1].tangent += tangent;
// vertices[index2].tangent += tangent;
// }
//
// //Fix the tangents per vertex now because we accumulated
// for (auto &v: vertices) {
// v.tangent = Vector3::Reject(v.tangent, v.normal).Normalized();
//
// if (flipAxisAndWinding) {
// v.position.z *= -1.f;
// v.normal.z *= -1.f;
// v.tangent.z *= -1.f;
// }
//
// }
return true;
}
#pragma warning(pop)
}
}

117
project/src/Vector2.cpp Normal file
View File

@@ -0,0 +1,117 @@
#include "pch.h"
#include "Vector2.h"
#include <cassert>
namespace dae {
const Vector2 Vector2::UnitX = Vector2{ 1, 0 };
const Vector2 Vector2::UnitY = Vector2{ 0, 1 };
const Vector2 Vector2::Zero = Vector2{ 0, 0 };
Vector2::Vector2(float _x, float _y) : x(_x), y(_y) {}
Vector2::Vector2(const Vector2& from, const Vector2& to) : x(to.x - from.x), y(to.y - from.y) {}
float Vector2::Magnitude() const
{
return sqrtf(x * x + y * y);
}
float Vector2::SqrMagnitude() const
{
return x * x + y * y;
}
float Vector2::Normalize()
{
const float m = Magnitude();
x /= m;
y /= m;
return m;
}
Vector2 Vector2::Normalized() const
{
const float m = Magnitude();
return { x / m, y / m};
}
float Vector2::Dot(const Vector2& v1, const Vector2& v2)
{
return v1.x * v2.x + v1.y * v2.y;
}
float Vector2::Cross(const Vector2& v1, const Vector2& v2)
{
return v1.x * v2.y - v1.y * v2.x;
}
#pragma region Operator Overloads
Vector2 Vector2::operator*(float scale) const
{
return { x * scale, y * scale };
}
Vector2 Vector2::operator/(float scale) const
{
return { x / scale, y / scale };
}
Vector2 Vector2::operator+(const Vector2& v) const
{
return { x + v.x, y + v.y };
}
Vector2 Vector2::operator-(const Vector2& v) const
{
return { x - v.x, y - v.y };
}
Vector2 Vector2::operator-() const
{
return { -x ,-y };
}
Vector2& Vector2::operator*=(float scale)
{
x *= scale;
y *= scale;
return *this;
}
Vector2& Vector2::operator/=(float scale)
{
x /= scale;
y /= scale;
return *this;
}
Vector2& Vector2::operator-=(const Vector2& v)
{
x -= v.x;
y -= v.y;
return *this;
}
Vector2& Vector2::operator+=(const Vector2& v)
{
x += v.x;
y += v.y;
return *this;
}
float& Vector2::operator[](int index)
{
assert(index <= 1 && index >= 0);
return index == 0 ? x : y;
}
float Vector2::operator[](int index) const
{
assert(index <= 1 && index >= 0);
return index == 0 ? x : y;
}
#pragma endregion
}

46
project/src/Vector2.h Normal file
View File

@@ -0,0 +1,46 @@
#pragma once
namespace dae
{
struct Vector2
{
float x{};
float y{};
Vector2() = default;
Vector2(float _x, float _y);
Vector2(const Vector2& from, const Vector2& to);
float Magnitude() const;
float SqrMagnitude() const;
float Normalize();
Vector2 Normalized() const;
static float Dot(const Vector2& v1, const Vector2& v2);
static float Cross(const Vector2& v1, const Vector2& v2);
//Member Operators
Vector2 operator*(float scale) const;
Vector2 operator/(float scale) const;
Vector2 operator+(const Vector2& v) const;
Vector2 operator-(const Vector2& v) const;
Vector2 operator-() const;
//Vector2& operator-();
Vector2& operator+=(const Vector2& v);
Vector2& operator-=(const Vector2& v);
Vector2& operator/=(float scale);
Vector2& operator*=(float scale);
float& operator[](int index);
float operator[](int index) const;
static const Vector2 UnitX;
static const Vector2 UnitY;
static const Vector2 Zero;
};
//Global Operators
inline Vector2 operator*(float scale, const Vector2& v)
{
return { v.x * scale, v.y * scale };
}
}

168
project/src/Vector3.cpp Normal file
View File

@@ -0,0 +1,168 @@
#include "pch.h"
#include "Vector3.h"
#include <cassert>
#include "Vector4.h"
#include "Vector2.h"
namespace dae {
const Vector3 Vector3::UnitX = Vector3{ 1, 0, 0 };
const Vector3 Vector3::UnitY = Vector3{ 0, 1, 0 };
const Vector3 Vector3::UnitZ = Vector3{ 0, 0, 1 };
const Vector3 Vector3::Zero = Vector3{ 0, 0, 0 };
Vector3::Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z){}
Vector3::Vector3(const Vector4& v) : x(v.x), y(v.y), z(v.z){}
Vector3::Vector3(const Vector3& from, const Vector3& to) : x(to.x - from.x), y(to.y - from.y), z(to.z - from.z){}
float Vector3::Magnitude() const
{
return sqrtf(x * x + y * y + z * z);
}
float Vector3::SqrMagnitude() const
{
return x * x + y * y + z * z;
}
float Vector3::Normalize()
{
const float m = Magnitude();
x /= m;
y /= m;
z /= m;
return m;
}
Vector3 Vector3::Normalized() const
{
const float m = Magnitude();
return { x / m, y / m, z / m };
}
float Vector3::Dot(const Vector3& v1, const Vector3& v2)
{
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
Vector3 Vector3::Cross(const Vector3& v1, const Vector3& v2)
{
return Vector3{
v1.y * v2.z - v1.z * v2.y,
v1.z * v2.x - v1.x * v2.z,
v1.x * v2.y - v1.y * v2.x
};
}
Vector3 Vector3::Project(const Vector3& v1, const Vector3& v2)
{
return (v2 * (Dot(v1, v2) / Dot(v2, v2)));
}
Vector3 Vector3::Reject(const Vector3& v1, const Vector3& v2)
{
return (v1 - v2 * (Dot(v1, v2) / Dot(v2, v2)));
}
Vector3 Vector3::Reflect(const Vector3& v1, const Vector3& v2)
{
return v1 - (2.f * Vector3::Dot(v1, v2) * v2);
}
Vector4 Vector3::ToPoint4() const
{
return { x, y, z, 1 };
}
Vector4 Vector3::ToVector4() const
{
return { x, y, z, 0 };
}
Vector2 Vector3::GetXY() const
{
return { x, y };
}
#pragma region Operator Overloads
Vector3 Vector3::operator*(float scale) const
{
return { x * scale, y * scale, z * scale };
}
Vector3 Vector3::operator/(float scale) const
{
return { x / scale, y / scale, z / scale };
}
Vector3 Vector3::operator+(const Vector3& v) const
{
return { x + v.x, y + v.y, z + v.z };
}
Vector3 Vector3::operator-(const Vector3& v) const
{
return { x - v.x, y - v.y, z - v.z };
}
Vector3 Vector3::operator-() const
{
return { -x ,-y,-z };
}
Vector3& Vector3::operator*=(float scale)
{
x *= scale;
y *= scale;
z *= scale;
return *this;
}
Vector3& Vector3::operator/=(float scale)
{
x /= scale;
y /= scale;
z /= scale;
return *this;
}
Vector3& Vector3::operator-=(const Vector3& v)
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
Vector3& Vector3::operator+=(const Vector3& v)
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
float& Vector3::operator[](int index)
{
assert(index <= 2 && index >= 0);
if (index == 0) return x;
if (index == 1) return y;
return z;
}
float Vector3::operator[](int index) const
{
assert(index <= 2 && index >= 0);
if (index == 0) return x;
if (index == 1) return y;
return z;
}
#pragma endregion
}

59
project/src/Vector3.h Normal file
View File

@@ -0,0 +1,59 @@
#pragma once
namespace dae
{
struct Vector2;
struct Vector4;
struct Vector3
{
float x{};
float y{};
float z{};
Vector3() = default;
Vector3(float _x, float _y, float _z);
Vector3(const Vector3& from, const Vector3& to);
Vector3(const Vector4& v);
float Magnitude() const;
float SqrMagnitude() const;
float Normalize();
Vector3 Normalized() const;
static float Dot(const Vector3& v1, const Vector3& v2);
static Vector3 Cross(const Vector3& v1, const Vector3& v2);
static Vector3 Project(const Vector3& v1, const Vector3& v2);
static Vector3 Reject(const Vector3& v1, const Vector3& v2);
static Vector3 Reflect(const Vector3& v1, const Vector3& v2);
Vector4 ToPoint4() const;
Vector4 ToVector4() const;
Vector2 GetXY() const;
//Member Operators
Vector3 operator*(float scale) const;
Vector3 operator/(float scale) const;
Vector3 operator+(const Vector3& v) const;
Vector3 operator-(const Vector3& v) const;
Vector3 operator-() const;
//Vector3& operator-();
Vector3& operator+=(const Vector3& v);
Vector3& operator-=(const Vector3& v);
Vector3& operator/=(float scale);
Vector3& operator*=(float scale);
float& operator[](int index);
float operator[](int index) const;
static const Vector3 UnitX;
static const Vector3 UnitY;
static const Vector3 UnitZ;
static const Vector3 Zero;
};
//Global Operators
inline Vector3 operator*(float scale, const Vector3& v)
{
return { v.x * scale, v.y * scale, v.z * scale };
}
}

102
project/src/Vector4.cpp Normal file
View File

@@ -0,0 +1,102 @@
#include "pch.h"
#include "Vector4.h"
#include <cassert>
#include "Vector2.h"
#include "Vector3.h"
namespace dae
{
Vector4::Vector4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {}
Vector4::Vector4(const Vector3& v, float _w) : x(v.x), y(v.y), z(v.z), w(_w) {}
float Vector4::Magnitude() const
{
return sqrtf(x * x + y * y + z * z + w * w);
}
float Vector4::SqrMagnitude() const
{
return x * x + y * y + z * z + w * w;
}
float Vector4::Normalize()
{
const float m = Magnitude();
x /= m;
y /= m;
z /= m;
w /= m;
return m;
}
Vector4 Vector4::Normalized() const
{
const float m = Magnitude();
return { x / m, y / m, z / m, w / m };
}
Vector2 Vector4::GetXY() const
{
return { x, y };
}
Vector3 Vector4::GetXYZ() const
{
return { x,y,z };
}
float Vector4::Dot(const Vector4& v1, const Vector4& v2)
{
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
}
#pragma region Operator Overloads
Vector4 Vector4::operator*(float scale) const
{
return { x * scale, y * scale, z * scale, w * scale };
}
Vector4 Vector4::operator+(const Vector4& v) const
{
return { x + v.x, y + v.y, z + v.z, w + v.w };
}
Vector4 Vector4::operator-(const Vector4& v) const
{
return { x - v.x, y - v.y, z - v.z, w - v.w };
}
Vector4& Vector4::operator+=(const Vector4& v)
{
x += v.x;
y += v.y;
z += v.z;
w += v.w;
return *this;
}
float& Vector4::operator[](int index)
{
assert(index <= 3 && index >= 0);
if (index == 0)return x;
if (index == 1)return y;
if (index == 2)return z;
return w;
}
float Vector4::operator[](int index) const
{
assert(index <= 3 && index >= 0);
if (index == 0)return x;
if (index == 1)return y;
if (index == 2)return z;
return w;
}
#pragma endregion
}

36
project/src/Vector4.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
namespace dae
{
struct Vector2;
struct Vector3;
struct Vector4
{
float x;
float y;
float z;
float w;
Vector4() = default;
Vector4(float _x, float _y, float _z, float _w);
Vector4(const Vector3& v, float _w);
float Magnitude() const;
float SqrMagnitude() const;
float Normalize();
Vector4 Normalized() const;
Vector2 GetXY() const;
Vector3 GetXYZ() const;
static float Dot(const Vector4& v1, const Vector4& v2);
// operator overloading
Vector4 operator*(float scale) const;
Vector4 operator+(const Vector4& v) const;
Vector4 operator-(const Vector4& v) const;
Vector4& operator+=(const Vector4& v);
float& operator[](int index);
float operator[](int index) const;
};
}

110
project/src/main.cpp Normal file
View File

@@ -0,0 +1,110 @@
#include "pch.h"
#if defined(_DEBUG)
#include "vld.h"
#endif
#undef main
#include "Renderer.h"
#include "GamePadController.h"
using namespace dae;
void ShutDown(SDL_Window *pWindow) {
SDL_DestroyWindow(pWindow);
SDL_Quit();
}
int main(int argc, char *args[]) {
//Unreferenced parameters
(void) argc;
(void) args;
//Create window + surfaces
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
const uint32_t width = 640;
const uint32_t height = 480;
SDL_Window *pWindow = SDL_CreateWindow(
"DirectX - Bram Verhulst - 2GD11E",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width, height, 0);
if (!pWindow)
return 1;
int joysticks = SDL_NumJoysticks();
std::cout << "Number of joysticks connected: " << joysticks << std::endl;
// If there are joysticks connected, open one up for reading
if (joysticks > 0) {
if (SDL_JoystickOpen(0) == NULL) {
std::cerr << "Failed to open joystick 0" << std::endl;
return -1;
}
} else {
std::cout << "No joysticks connected" << std::endl;
}
GamePadController::GetInstance().Init();
//Initialize "framework"
const auto pTimer = new Timer();
const auto pRenderer = new Renderer(pWindow);
//Start loop
pTimer->Start();
float printTimer = 0.f;
bool isLooping = true;
while (isLooping) {
//--------- Get input events ---------
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT:
isLooping = false;
break;
case SDL_KEYUP:
//Test for a key
//if (e.key.keysym.scancode == SDL_SCANCODE_X)
if (e.key.keysym.scancode == SDL_SCANCODE_F2) {
pRenderer->SwitchTechnique();
}
break;
default:
break;
}
}
GamePadController::GetInstance().Update();
//--------- Update ---------
pRenderer->Update(pTimer);
//--------- Render ---------
pRenderer->Render();
//--------- Timer ---------
pTimer->Update();
printTimer += pTimer->GetElapsed();
if (printTimer >= 1.f) {
printTimer = 0.f;
std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl;
}
}
pTimer->Stop();
//Shutdown "framework"
delete pRenderer;
delete pTimer;
ShutDown(pWindow);
return 0;
}

1
project/src/pch.cpp Normal file
View File

@@ -0,0 +1 @@
#include "pch.h"

24
project/src/pch.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>
#include <memory>
#define NOMINMAX //for directx
// SDL Headers
#include "SDL.h"
#include "SDL_syswm.h"
#include "SDL_surface.h"
#include "SDL_image.h"
// DirectX Headers
#include <dxgi.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <d3dx11effect.h>
// Framework Headers
#include "Timer.h"
#include "Math.h"